docs(website): serve index routes at their clean-URL .md addresses

Each index route also emits a parent-level alias twin, projected over
the alias route so its relative links stay correct; llms.txt and the
docs now state the drop-trailing-slash convention exactly. Frontmatter
failures name their page, the twin pass refuses to overwrite existing
build files, the dev middleware documents the deliberate in-page
fetch() divergence, and the per-locale collection order moves to one
shared export. Refs #2846.
This commit is contained in:
Yichen Jiang
2026-08-20 22:10:35 +08:00
parent f3ce8218cc
commit 17c85209a0
10 changed files with 174 additions and 50 deletions
+11 -8
View File
@@ -5,7 +5,7 @@ import { resolve } from 'node:path'
import type { DefaultTheme, PageData, SiteConfig } from 'vitepress'
import type { ViteDevServer } from 'vite'
import { withMermaid } from 'vitepress-plugin-mermaid'
import { landingLink, orderedPages, routeLink, sectionSpec, type DocsLocale, type DocsPage, type DocsSidebar } from '../docs.ts'
import { landingLink, localeCollections, orderedPages, routeLink, sectionSpec, type DocsLocale, type DocsPage, type DocsSidebar } from '../docs.ts'
import { docsSourceFiles, emitRawMarkdownPages, llmsTxt, projectDocs, rawMarkdownRoute } from '../../scripts/project-doc-site.ts'
projectDocs()
@@ -58,14 +58,14 @@ interface GuideModules {
*/
const guideModules = {
root: {
guide: 'zh-guide',
develop: { label: '开发', collection: 'zh-develop' },
reference: { label: '参考', collection: 'zh-reference' },
guide: localeCollections.root[0],
develop: { label: '开发', collection: localeCollections.root[1] },
reference: { label: '参考', collection: localeCollections.root[2] },
},
en: {
guide: 'en-guide',
develop: { label: 'Development', collection: 'en-develop' },
reference: { label: 'Reference', collection: 'en-reference' },
guide: localeCollections.en[0],
develop: { label: 'Development', collection: localeCollections.en[1] },
reference: { label: 'Reference', collection: localeCollections.en[2] },
},
} satisfies Record<DocsLocale, GuideModules>
@@ -125,7 +125,10 @@ function serveRawMarkdown(server: ViteDevServer): void {
// The dev client imports page modules at these same `.md` URLs, and a
// module script must reach Vite's transform. Browsers declare the purpose:
// `script` for module imports, `document` for address-bar navigation.
// Header-less clients (curl, agents) read the raw twin.
// Header-less clients (curl, agents) read the raw twin. In-page fetch()
// (`empty`) also passes to Vite — a deliberate dev-only divergence that
// keeps Vite's own requests unbroken, while production static hosting
// answers such a fetch with the raw file.
const fetchDest = req.headers['sec-fetch-dest']
if (fetchDest !== undefined && fetchDest !== 'document') {
next()
+1 -1
View File
@@ -10,6 +10,6 @@ Keep canonical prose and generated catalogs in their owning `docs/` tier, then e
The projector writes disposable Markdown to the ignored `website/.generated/` directory. Never edit or commit `.generated/`, `.cache/`, or `.dist/`.
The build also emits each route's raw-Markdown twin and a root `llms.txt` index into `.dist/`, so `<page URL>.md` serves the page as plain Markdown. Both derive from the publication manifest at build time; neither is ever a file in this tree.
The build also emits each route's raw-Markdown twin (with a parent-level alias per index route) and a root `llms.txt` index into `.dist/`, so a page's URL, minus any trailing slash, plus `.md` serves it as plain Markdown. Both derive from the publication manifest at build time; neither is ever a file in this tree.
Run `pnpm docs:check` after changing this subtree; the gate rejects additional non-ignored Markdown under `website/`.
+10
View File
@@ -412,6 +412,16 @@ const reference = [
}]),
]
/**
* Sidebar collections of each locale, in the order the site's navigation
* presents them. The navigation bar and the llms.txt index both read this
* sequence, so a new collection lands in both surfaces together.
*/
export const localeCollections = {
root: ['zh-guide', 'zh-develop', 'zh-reference'],
en: ['en-guide', 'en-develop', 'en-reference'],
} as const satisfies Record<DocsLocale, readonly DocsSidebar[]>
/** A sidebar group, matched to pages by `label`. */
export interface DocsSection {
/** Group heading, equal to the `section` field of every page it holds. */