feat(polaris): 实现静态分类页

新增七个预生成分类路由、工具卡片网格与空状态。启用侧栏分类导航和当前分类选中态,修复 Windows 静态导出 RSC 路径并补充产物验证,保持静态导出与安全外链约束。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-15 19:24:57 +08:00
co-authored by Claude Opus 5
parent e9f3bf6934
commit 4a032ea742
24 changed files with 2332 additions and 46 deletions
@@ -0,0 +1,46 @@
import assert from "node:assert/strict"
import { readFile, readdir } from "node:fs/promises"
import path from "node:path"
import { fileURLToPath } from "node:url"
const projectDir = fileURLToPath(new URL("../", import.meta.url))
const appDir = path.join(projectDir, ".next/server/app")
const outDir = path.join(projectDir, "out")
const categories = JSON.parse(
await readFile(path.join(projectDir, "src/data/categories.json"), "utf8"),
)
const routes = ["/", ...categories.map(({ id }) => `/categories/${id}`)]
let checkedSegments = 0
// 只读构建产物:验证浏览器需要的扁平 URL,绝不修补或复制 out/ 文件。
for (const route of routes) {
const routeDir = path.join(outDir, route)
assert((await readFile(path.join(routeDir, "index.html"))).length > 0)
assert((await readFile(path.join(routeDir, "index.txt"))).length > 0)
const segmentsDir = path.join(
appDir,
`${route === "/" ? "index" : route}.segments`,
)
const files = (await readdir(segmentsDir, { recursive: true })).filter(
(file) => file.endsWith(".segment.rsc"),
)
assert(files.length > 0, `${route} 缺少 RSC segment 构建产物`)
for (const file of files) {
const segment = file
.replaceAll("\\", "/")
.slice(0, -".segment.rsc".length)
.replaceAll("/", ".")
const filename = `__next.${segment}.txt`
const source = await readFile(path.join(segmentsDir, file))
const exported = await readFile(path.join(routeDir, filename))
assert.deepEqual(exported, source, `${route}/${filename} 内容不一致`)
checkedSegments += 1
}
}
assert((await readFile(path.join(outDir, "404.html"))).length > 0)
console.log(
`静态导出检查通过:${routes.length} 个页面、${checkedSegments} 个 RSC 文件及 404.html。`,
)