From 740ec470fafae05be4c197e27421dedde5e922c5 Mon Sep 17 00:00:00 2001 From: wait4xx Date: Mon, 2 Nov 2026 17:50:19 +0800 Subject: [PATCH] =?UTF-8?q?chore(spec):=20=E7=AB=8B=E9=A1=B9=20blog-5g?= =?UTF-8?q?=E2=80=94=E2=80=94=E9=A1=B5=E9=9D=A2=E5=90=8E=E5=8F=B0=E5=8C=96?= =?UTF-8?q?=EF=BC=88blocks=EF=BC=89=E4=B8=8E=E5=AD=97=E4=BD=93=E5=AD=90?= =?UTF-8?q?=E9=9B=86=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 按 docs/research/10 方案 E 拆七任务:块式页面构建器(T1/T2)、样式即数据 +对比度闸门(T3)、首页抽 HomePage 去双份(T4)、开源页收尾(T5)、文档 与 hint(T6)、字体子集化工具(T7)。三车道分配:op-gitea(T1/T2)、 op-artalk(T3/T4)、worker-one(T5/T6)、orchestrator(T7+统筹验收)。 Spec: 2026-11-02_blog-5g-pages Co-authored-by: GLM-5.3 --- .spec/specs/2026-11-02_blog-5g-pages/spec.md | 84 +++++++++++++++++++ .spec/specs/2026-11-02_blog-5g-pages/tasks.md | 42 ++++++++++ 2 files changed, 126 insertions(+) create mode 100644 .spec/specs/2026-11-02_blog-5g-pages/spec.md create mode 100644 .spec/specs/2026-11-02_blog-5g-pages/tasks.md diff --git a/.spec/specs/2026-11-02_blog-5g-pages/spec.md b/.spec/specs/2026-11-02_blog-5g-pages/spec.md new file mode 100644 index 0000000..174548b --- /dev/null +++ b/.spec/specs/2026-11-02_blog-5g-pages/spec.md @@ -0,0 +1,84 @@ +# Phase 5g:页面后台化(blocks 模型)与字体子集化 - 项目范围 + + + +## 1. 问题定义 +- **项目目标**:①按 docs/research/10 方案 E 把关于页改造成「块式页面构建器」(结构可增删排序)②样式即数据(theme.yaml → 构建期 CSS 变量,含对比度闸门)③首页字段细化并抽 HomePage 消 zh/en 双份 ④开源页收尾(README 缓存/回落/告警)⑤后台文档与 hint 补齐 ⑥字体子集化工具(把艺术字体单页增量从数百 KB 降到数十 KB) +- **目标用户**:站长(希望整页可编辑、能上更多艺术字体)与读者(版式与可读性不退化) +- **核心价值**:内容与结构的编辑权交回后台,同时守住灰阶体系/双语/SEO/构建期零运行时四条红线 + +## 2. 假设与待确认 + +### 2.1 已确认事实 +- Sveltia 0.252 支持 list 的 types + typeKey(方案 10 §3.4 从本仓 bundle 取证),块模型可行 +- 页面文案 markdown 净化(D1/D2)已在 2cab243 落地(P0 完成) +- 字体实测:@fontsource CJK 切片粒度导致单页 +163KB~+8605KB;现有 6 自托管族为基线 + +### 2.2 关键假设 +- 块渲染器受控,破版风险低于整页 HTML 直编(方案 10 §2 对比表) +- 字体子集化(pyftsubset 按页实际用字)能把艺术字体单页增量压到 ≤150KB 阈值内 + +### 2.3 待确认问题 +- [x] 关于页整页可编辑路线 → 用户 2026-11-02 批准方案 E(blocks + theme.yaml + 局部自由区) +- [x] 字体扩充路线 → 先落 6 族,其余按子集化工具就绪后再评估(本包 T7 交付工具) + +### 2.4 可选解释与取舍 +- 关于页保留 intro markdown 通道作为 compat(blocks 为空时三级回落:blocks → intro → 默认文案) +- 样式即数据只开放白名单旋钮(约 12 项),不开放整份 tokens.css +- 图片只走 Astro image() 管线,禁止块内填外链/绝对路径(schema 层拦) + +### 2.5 已证伪路径 +- 整页富文本直编(C 方案):XSS 面大、无设计兜底,弃 +- 新增 webfont 直接上(不子集化):单页 +535KB~+8605KB,超阈值,弃(改走 T7 工具) + +## 3. 功能范围 + +### 3.1 核心功能(MVP) +- [ ] T1 blocks 骨架:schema(discriminatedUnion)+ page-blocks.ts + BlockRenderer + prose/tracks/divider 三块 + 后台 types 声明 +- [ ] T2 块型扩充:cards/timeline/quote/figure/linklist/cta + 图标键白名单 + 图片 image() 管线 +- [ ] T3 样式即数据:theme.yaml + theme.ts + BaseLayout 内联变量 + 对比度闸门脚本 +- [ ] T4 首页细化与去重:抽 HomePage.astro 消 zh/en 双份 + 字段细化(projectsLimit/announcement 等) +- [ ] T5 开源页收尾:README 缓存策略/超时/回落矩阵 + fallback JSON 回填 + include 未命中 WARN +- [ ] T6 文档与 hint:docs/管理台.md(块编辑用法)+ 写作指南扩充 + admin 全字段中文 hint +- [ ] T7 字体子集化工具:按页用字裁剪艺术字体为小切片 + build.sh 守卫挂载 + 实测对比 + +### 3.2 扩展功能 +- 无 + +### 3.3 不在范围内 +- 换 CMS、页面布局的任意拖拽网格、运行时编辑器 + +## 4. 最小实现路径 +- 最简单可行方案:块类型先用 3 类跑通闭环(prose/tracks/divider),再扩到 9 类;theme 只做 12 个白名单旋钮 +- 暂不引入:可视化块预览、块级动画配置 +- 不做的抽象:通用页面 DSL(只服务现有页面) + +## 5. 技术决策 +- 技术栈:Astro 7.4.4 + zod discriminatedUnion + Sveltia list/types + pyftsubset(fonttools) +- 证据协议:evidence: runs +- 本轮允许改动:src/content.config.ts、src/lib/{page-blocks,theme,site-content}.ts、src/components/blocks/*、src/components/pages/{AboutPage,HomePage}.astro、src/pages/{index,en/index,opensource,en/opensource}.astro、src/layouts/BaseLayout.astro、public/admin/*、content/site/*.yaml、scripts/build-perf/*、infra/deploy/build.sh、docs/*、tests/e2e.mjs +- 本轮不应触碰:nginx/ESA、图库灯箱(GalleryPage/PhotoZoom)、Header/Footer 结构 +- Git integration branch:`spec/2026-11-02_blog-5g-pages` + +### 5.1 验证策略 +- 范围级别:package +- 变更对象:页面数据模型与渲染器、后台配置、样式变量生成、字体产物、文档 +- 快速检查:`pnpm astro build`(node26) +- 集成检查:`node tests/e2e.mjs`(37 项,本包预期新增块/主题断言)+ content-lint 0/0/0 +- 全项目检查:字体体积账(三页增量)+ 视觉复核(glm-5.3-flash:max,块版式与主题变量双态);仅在构建链或 BaseLayout 结构再变更时升级范围 +- 升级触发:若 theme 变量波及全局排版(字体字号全站变化)或 blocks 改动触及首页/文章页结构,升级为全站视觉复核与 E2E 全量并记录理由 + +## 6. 成功标准与验证方式 +- [ ] 关于页整页由 yaml blocks 驱动,增删排序生效 -> verify: task_0001 +- [ ] 九类块全部可渲染且旧内容零回归(三级回落) -> verify: task_0002 +- [ ] theme.yaml 改值 → 产物 CSS 变量变化,对比度闸门拦截不达标 -> verify: task_0003 +- [ ] 首页 zh/en 由同一组件渲染且字段可配 -> verify: task_0004 +- [ ] 开源页 README 失败矩阵与 fallback 告警可用 -> verify: task_0005 +- [ ] 后台文档与 hint 完整 -> verify: task_0006 +- [ ] 字体子集化工具把指定字体单页增量压到 ≤150KB -> verify: task_0007 + +## 7. 风险与约束 +- 灰阶体系与双语红线不变;彩色仅正文强调 +- 块渲染器未知类型跳过 + WARN,绝不炸构建 +- 字体子集化需保证字形覆盖(裁错字会出现豆腐块)→ 断言:子集后页面文本逐字命中 +- 多车道并行:共享文件(content.config.ts/admin config/docs)按 boundary 划界,tokens/global 由 orchestrator 或指定单车道 diff --git a/.spec/specs/2026-11-02_blog-5g-pages/tasks.md b/.spec/specs/2026-11-02_blog-5g-pages/tasks.md new file mode 100644 index 0000000..89b56d6 --- /dev/null +++ b/.spec/specs/2026-11-02_blog-5g-pages/tasks.md @@ -0,0 +1,42 @@ +# Phase 5g:页面后台化(blocks 模型)与字体子集化 - 任务拆解 + +## 使用规则 +- boundary/verify 齐备;verify 只读断言;车道工作树开发禁 git,收编由 orchestrator 统一提交 +- 构建一律 `export PATH="$HOME/.local/node/bin:$PATH"`(Node 26) + +## 阶段一:实现 + +- [ ] T1 blocks 骨架(关于页块式页面构建器) + - claim: op-gitea + - boundary: src/content.config.ts(siteAbout 加 blocks: z.array(discriminatedUnion))、新增 src/lib/page-blocks.ts(getAboutBlocks:过滤 enabled、未知 type 跳过+WARN、文本 pickBi 回落、块数≤24/单块≤4000 字)、新增 src/components/blocks/{BlockRenderer,Prose,Tracks,Divider}.astro、AboutPage.astro 改由 blocks 驱动(blocks 空→intro markdown→默认文案三级回落)、public/admin/config.yml 加 list+types(typeKey: type) + - verify: `E2E_BASE=http://127.0.0.1:18924 node tests/e2e.mjs 2>&1 | grep -q "37/37 PASS" && grep -q "discriminatedUnion" src/content.config.ts && grep -q "BlockRenderer" src/components/pages/AboutPage.astro && grep -q "typeKey" public/admin/config.yml` + +- [ ] T2 块型扩充与图片管线 + - claim: op-gitea + - boundary: 新增 src/components/blocks/{Cards,Timeline,Quote,Figure,LinkList,Cta}.astro + 图标键白名单(复用 SocialLinks 注册表或新建 icons 注册表)、schema 块型补全(图片字段用 image(),禁止外链字符串)、content/site/assets/ 目录、near docs 图表说明 + - verify: `E2E_BASE=http://127.0.0.1:18924 node tests/e2e.mjs 2>&1 | grep -q "37/37 PASS" && ls src/components/blocks/ | grep -qC1 "Cards\|Timeline" && grep -q "image()" src/content.config.ts` + +- [ ] T3 样式即数据(theme.yaml + 对比度闸门) + - claim: op-artalk + - boundary: 新增 content/site/theme.yaml(12 个白名单旋钮:prose-size/measure/radius/accent/leading 等)、新增 src/lib/theme.ts(getTheme + themeVarsCss 生成 :root:root{…})、BaseLayout.astro head 内联 theme 变量(构建期静态)、新增 scripts/build-perf/contrast-check.mjs(断言 theme 结果下正文对比度 ≥4.5)、public/admin/config.yml 加 theme 单例、build.sh 守卫挂载 + - verify: `E2E_BASE=http://127.0.0.1:18924 node tests/e2e.mjs 2>&1 | grep -q "37/37 PASS" && test -f content/site/theme.yaml && node scripts/build-perf/contrast-check.mjs dist` + +- [ ] T4 首页细化与去重 + - claim: op-artalk + - boundary: 新增 src/components/pages/HomePage.astro(承接现 index.astro 区块逻辑,locale prop)、src/pages/{index,en/index}.astro 改为薄壳、home.yaml 增 projectsLimit / announcement(markdown)/ postsTracks(轨开关细分),site-content 访问器同步 + - verify: `E2E_BASE=http://127.0.0.1:18924 node tests/e2e.mjs 2>&1 | grep -q "37/37 PASS" && test -f src/components/pages/HomePage.astro && grep -q "HomePage" src/pages/en/index.astro` + +- [ ] T5 开源页收尾(缓存/回落/告警) + - claim: worker-one + - boundary: src/lib/site-content.ts(README 缓存策略与超时、回落矩阵)、content/.github-readme.md 与 README HTML 剥离策略(复用 rehype-content-sanitize 已挡危险标签;补: 外链徽章不阻断)、src/data/projects-fallback.json 回填 5-8 条真实仓、projects.ts include 未命中 console.warn + - verify: `E2E_BASE=http://127.0.0.1:18924 node tests/e2e.mjs 2>&1 | grep -q "37/37 PASS" && python3 -c "import json;d=json.load(open('src/data/projects-fallback.json'));assert len(d)>=5"` + +- [ ] T6 文档与后台 hint 补齐 + - claim: worker-one + - boundary: docs/管理台.md(块编辑怎么用、增删排序、预览限制)、docs/写作指南.md(块字段表/受限类/主题项)、public/admin/config.yml 全字段中文 hint(含 T1-T4 新增字段) + - verify: `test -f docs/管理台.md && grep -q "blocks\|区块" docs/管理台.md && grep -c "hint" public/admin/config.yml | awk '$1>=20'` + +- [ ] T7 字体子集化工具 + - claim: orchestrator + - boundary: 新增 scripts/build-perf/subset-fonts.py(pyftsubset 按指定字体 + 页面实际用字生成子集 woff2 + 重写 fonts.css 指向子集文件)、infra/deploy/build.sh 守卫挂载、docs/写作指南加字流程补"子集化"一节 + - verify: `test -f scripts/build-perf/subset-fonts.py && python3 -c "import fontTools; print('fonttools ok')" && E2E_BASE=http://127.0.0.1:18924 node tests/e2e.mjs 2>&1 | grep -q "37/37 PASS"`