Skip to content

fix(docs): /docs 根路由 404 — 加 landing page 列出所有分区#290

Closed
longsizhuo wants to merge 1 commit intomainfrom
fix/docs-root-404
Closed

fix(docs): /docs 根路由 404 — 加 landing page 列出所有分区#290
longsizhuo wants to merge 1 commit intomainfrom
fix/docs-root-404

Conversation

@longsizhuo
Copy link
Copy Markdown
Member

现象

Header 导航栏 "文档 / Docs" 直接指向 `/docs`,点进去生产 404:

```
$ curl -I https://involutionhell.com/docs
HTTP/2 404
x-matched-path: /_not-found
x-next-error-status: 404
```

根因

`app/docs/` 下当前只有两样东西:

  • `layout.tsx` — DocsLayout 包装器
  • `[...slug]/page.tsx` — catch-all,但 Next.js `[...slug]` 不匹配空 slug(只有 `[[...slug]]` 才会)

`/docs` 本身没有任何 route 匹配 → 走 `not-found`。

修法

新增 `app/docs/page.tsx`(server component),复用 `app/docs/layout.tsx` 已经挂好的 DocsLayout(侧边栏 / copy tracking / view tracking 都自动继承),自己只负责渲染中间内容区:

  • 读 `source.pageTree.children` 顶层分区 → 渲染成 fumadocs `` 列表,不硬编码分区名
  • 卡片标题 / 描述来自各分区 `index.mdx` 的 frontmatter.title / description
  • 没 index 的分区(目前 jobs / all-projects)降级用目录名 + 兜底到子树第一个 page 的 url,保证不点空
  • locale 从 cookie 读,只切 H1 / intro 两句话;卡片内容本身由 `[...slug]` 的 locale fallback 负责

本地验证

```
$ curl -s -o /tmp/docs.html -w "HTTP %{http_code}\n" http://localhost:3010/docs
HTTP 200
```

5 张卡片渲染:AI 知识库 / Computer Science / 群友分享 / Jobs / All projects。

Test plan

  • 本地 dev server `/docs` 返回 200,5 张卡片全部可点
  • `pnpm tsc --noEmit` 对新文件无报错
  • 合并部署后再 `curl https://involutionhell.com/docs\` 验证生产 200
  • 点每张卡片进入对应分区,确认跳转 URL 正确(尤其 jobs / all-projects 这俩没 index 的走 fallback url)

Header 导航栏 "文档 / Docs" 点进去是 /docs,但路由目录下只有
app/docs/[...slug]/page.tsx(catch-all 不匹配空 slug)和 layout.tsx,
没有东西匹配 /docs 本身,所以生产直接 404(x-matched-path: /_not-found)。

修法:新增 app/docs/page.tsx(server component),复用已有的 docs layout,
读 fumadocs source.pageTree.children 顶层分区渲染成 Cards 列表:
- 不硬编码分区名,新增顶层目录自动出现在 landing
- 卡片标题/描述读各分区 index.mdx frontmatter,没 index 的分区(jobs /
  all-projects)降级用目录名 + 兜底到子树第一个 page 的 url,保证不点空
- locale 从 cookie 读(zh/en),只切 H1/intro 两句话;卡片内容本身
  已由 [...slug] 的 locale fallback 负责,这里不重复处理
Copilot AI review requested due to automatic review settings April 16, 2026 19:07
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 16, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
involutionhell-github-io Ready Ready Preview, Comment Apr 16, 2026 8:28pm
website-preview Ready Ready Preview, Comment Apr 16, 2026 8:28pm

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

/docs 根路由新增一个 landing page,解决导航栏直达 /docs 在生产环境返回 404 的问题,并在该页面动态列出 docs 顶层分区入口卡片。

Changes:

  • 新增 app/docs/page.tsx 作为 /docs 的 server component 路由,渲染分区卡片列表
  • source.pageTree.children 生成卡片数据,并为无 index 的分区提供 fallback 跳转 URL
  • 基于 locale cookie 切换 landing 页的标题与简介文案,并补充页面 metadata

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread app/docs/page.tsx
indexUrl ?? findFirstPageUrl(folder.children) ?? undefined;
if (!fallbackUrl) return null;
return {
title: asPlainText(folder.name),
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Folder 类型分区卡片目前用的是 folder.name 作为标题(通常是目录名如 ai),而不是分区 index.mdx 的 frontmatter/title。现有 docs 里如 app/docs/ai/index.mdx 的 title 是“AI 知识库”,按现在实现 landing 会展示成“ai”,与 PR 目标(用 index frontmatter.title/description)不一致。建议优先使用 folder.index?.name(或等价的 index page 标题字段)作为 title,并在缺失 index 时再回退到 folder.name

Suggested change
title: asPlainText(folder.name),
title: asPlainText(folder.index?.name ?? folder.name),

Copilot uses AI. Check for mistakes.
Comment thread app/docs/page.tsx
Comment on lines +96 to +100
const tree = source.pageTree;

const cards = tree.children
.map(toSectionCard)
.filter((c): c is SectionCard => c !== null);
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里读取的是未处理过的 source.pageTree,但 docs 的 layout.tsx 会对 tree 做 pruneEmptyFolders(source.pageTree) 后再交给 DocsLayout。landing 用原始 tree 可能会把 layout 已经 prune 掉/提升成 page 的节点也展示出来,导致 landing 卡片与侧边栏结构不一致。建议复用同一份 prune 逻辑(例如将 pruneEmptyFolders 提到共享 util 并在这里也使用)。

Copilot uses AI. Check for mistakes.
Comment thread app/docs/page.tsx
Comment on lines +42 to +46
/** 把 pageTree 顶层 node 映射成 landing 卡片;遇到 separator / 孤立 page 就跳过 */
function toSectionCard(node: PageTree.Node): SectionCard | null {
if (node.type === "separator") return null;
if (node.type === "page") {
// 顶层直接挂的文件(比如目录只有一个文件被 pruneEmptyFolders 提出来了)
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

注释“遇到 separator / 孤立 page 就跳过”与实际逻辑不一致:当前 node.type === "page" 会被映射成卡片而不是跳过。建议更新注释以匹配真实行为,避免后续维护者误解。

Copilot uses AI. Check for mistakes.
longsizhuo added a commit that referenced this pull request Apr 16, 2026
合并 #288 + #290 + app/docs/CommunityShare/Leetcode/index.mdx 里原先三份
各自实现的"列目录子节点"逻辑,改成一个 server component。

## 为什么要合并

原本三处各自实现:
- /docs 根路由(PR #290 draft)—— 读 pageTree.children
- CommunityShare/index.mdx(PR #288 draft)—— 读 getPages() 过滤 path
- CommunityShare/Leetcode/index.mdx —— 内联 MDX 里 source.getPages().filter().map()

drift 问题:排序、英文过滤、fallback URL 三份逻辑各走各的;更严重的是
PR #288 里对"没 index.mdx 的子目录"硬拼 /docs/CommunityShare/<dir> 会 404
(Copilot CR 指出),和 PR #290 修 /docs 404 是同一个根因:Next [...slug]
不匹配空 slug,folder 没 index 就意味着 /docs/X 没 route。

## <SectionIndex root?>

- 走 source.pageTree(不是 getPages),fumadocs 已经把 folder+index
  关系建好了,不用自己从扁平 page 列表反推
- root 接 "CommunityShare" / "CommunityShare/Leetcode" 这种相对路径,
  不传就是从 pageTree 根开始(给 /docs landing 用)
- URL 永不硬拼:folder 有 index 走 index.url;没 index 递归找子树第一个
  page 的 url 作为 fallback(直接修掉 CR 那个 404 bug)
- 英文翻译版(URL 末段 .en)过滤不进列表;语言切换仍由 [...slug] 的 cookie
  fallback 负责
- 统一 fumadocs <Cards>/<Card> 视觉

## 本地验证

- /docs → 5 张卡片,全部 200
- /docs/CommunityShare → 8 张卡片,全部 200(包括原先会 404 的 Language/
  Life/Personal-Study-Notes/RAG 四个没 index 的分类,现在点进去是子目录里
  第一篇 page,不再死链)
- /docs/CommunityShare/Leetcode → 49 张卡片,0 个 .en 泄漏

## 取代关系

- 关闭 PR #288(CommunityShareIndex 专用实现,有 404 bug)
- 关闭 PR #290(/docs landing 单独实现)
- 本 PR 一并覆盖,继续承担解决 #110 的责任

Co-authored-by: LynPtl <194795025+LynPtl@users.noreply.github.com>
@longsizhuo
Copy link
Copy Markdown
Member Author

并入 #292/docs landing 与 CommunityShare / Leetcode 用同一个 <SectionIndex> 渲染,避免 drift 维护。

@longsizhuo longsizhuo closed this Apr 16, 2026
longsizhuo added a commit that referenced this pull request Apr 16, 2026
…(取代 #288 #290) (#292)

* refactor(docs): 统一 /docs、CommunityShare、Leetcode 三处索引为 <SectionIndex>

合并 #288 + #290 + app/docs/CommunityShare/Leetcode/index.mdx 里原先三份
各自实现的"列目录子节点"逻辑,改成一个 server component。

## 为什么要合并

原本三处各自实现:
- /docs 根路由(PR #290 draft)—— 读 pageTree.children
- CommunityShare/index.mdx(PR #288 draft)—— 读 getPages() 过滤 path
- CommunityShare/Leetcode/index.mdx —— 内联 MDX 里 source.getPages().filter().map()

drift 问题:排序、英文过滤、fallback URL 三份逻辑各走各的;更严重的是
PR #288 里对"没 index.mdx 的子目录"硬拼 /docs/CommunityShare/<dir> 会 404
(Copilot CR 指出),和 PR #290 修 /docs 404 是同一个根因:Next [...slug]
不匹配空 slug,folder 没 index 就意味着 /docs/X 没 route。

## <SectionIndex root?>

- 走 source.pageTree(不是 getPages),fumadocs 已经把 folder+index
  关系建好了,不用自己从扁平 page 列表反推
- root 接 "CommunityShare" / "CommunityShare/Leetcode" 这种相对路径,
  不传就是从 pageTree 根开始(给 /docs landing 用)
- URL 永不硬拼:folder 有 index 走 index.url;没 index 递归找子树第一个
  page 的 url 作为 fallback(直接修掉 CR 那个 404 bug)
- 英文翻译版(URL 末段 .en)过滤不进列表;语言切换仍由 [...slug] 的 cookie
  fallback 负责
- 统一 fumadocs <Cards>/<Card> 视觉

## 本地验证

- /docs → 5 张卡片,全部 200
- /docs/CommunityShare → 8 张卡片,全部 200(包括原先会 404 的 Language/
  Life/Personal-Study-Notes/RAG 四个没 index 的分类,现在点进去是子目录里
  第一篇 page,不再死链)
- /docs/CommunityShare/Leetcode → 49 张卡片,0 个 .en 泄漏

## 取代关系

- 关闭 PR #288(CommunityShareIndex 专用实现,有 404 bug)
- 关闭 PR #290(/docs landing 单独实现)
- 本 PR 一并覆盖,继续承担解决 #110 的责任

Co-authored-by: LynPtl <194795025+LynPtl@users.noreply.github.com>

* docs(SectionIndex): 加大量中文注释说明 pageTree 心智模型 + 每步做什么

* fix(SectionIndex): 按 CR 补齐 locale 变体过滤 + 去掉注释里的 markdown

Copilot 在 #292 提了 3 条要修的:

1) isEnglishVariant 只过滤 .en,没管 .zh —— 站点实际有 .zh.md(原文是 en 时的中文翻译),
   重复链接会在索引里暴露。改成 isHideableLocaleVariant(url, canonicals):只有对应
   canonical 存在时才隐藏,孤儿(只有 .en 或 .zh 单一形态的文档,共 35 + 7 篇)保留。

2) folder.index 如果本身是翻译版(理论上会有 index.en.mdx / index.zh.mdx),不能直接
   当卡片 href,会暴露非 canonical URL。nodeToCard 里给 idxUrl 加同样的过滤,不合规时
   退回 findFirstPageUrl。

3) folderSegmentName 注释写的"倒数第二段"但代码取的是最后一段,改掉注释。

另外按用户反馈清掉注释里的 markdown(**bold**、反引号等),代码注释又不会被渲染。

---------

Co-authored-by: LynPtl <194795025+LynPtl@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants