Notist
On this page
  1. 2026-10-31 XIV DB 数据驱动 SSG 实践评估 (OpenCode, GPT-6.1 Sol)
  2. 目标与输入
  3. 三个性能问题及处理
  4. 1. 每页复制整站上下文
  5. 2. 每插入一个发布文件都扫描所有旧路径
  6. 3. Handlebars 隐式 partial 复制当前上下文
  7. 全量结果与限制
  8. 验证与复现

2026-10-31 XIV DB 数据驱动 SSG 实践评估 (OpenCode, GPT-6.1 Sol)

目标与输入

用真实国服 Item.csv 构建完整物品目录,不把 Notist 的性能问题改成客户端加载详情来回避。

  • 消费者:/home/azurice/Files/_ffxiv/xiv-db。

  • 上游:thewakingsands/ffxiv-datamining-cn,commit 2c6741cffe3cfe70f093c54c463791364e515d8d。

  • 输入 SHA-256:abb68a057f68e4d9d37eae76d31354555d30f76a88554d0d1c04315598c7268f。

  • 客户端版本:2026.10.06.0000.0000;非零 ID 且名称非空的物品 51,225 件。

  • prepare 命令扩展在内存生成 .not 文档和模板数据,每件物品一个稳定 HTML 路径,每 100 件生成一页目录。

  • 搜索索引是额外的静态资源;关闭 JavaScript 不影响目录翻页和详情正文。

三个性能问题及处理

1. 每页复制整站上下文

notist-ssg/src/build.rs 原来在每页循环中使用 json! 构造含完整 site 的上下文,再调用 Handlebars render 重新序列化。site 包含整站 pages、directories 和 data,因此生成页面越多,重复工作越多。

改为一次建立 handlebars::Context,通过 render_with_context 渲染;逐页替换 page、assets,仅在目录变化时替换 directory。整站查询语义保持不变,新增回归测试检查兄弟页、不同目录、lookup、@root 和资源路径。

单轮本地 release 对照(简单合成页面、无 partial,不代表完整业务负载):

页面数

原实现

上下文复用后

100

0.063 s

0.011 s

300

0.507 s

0.032 s

600

1.936 s

0.069 s

600 页产物的全部文件 SHA-256 与原实现一致。临时测量记录位于 /tmp/opencode/notist-catalog-bench-o596atvh/,不是持久化基准设施。

2. 每插入一个发布文件都扫描所有旧路径

publication::Assets::generated 原先用全表遍历检查相同、祖先和后代路径冲突。这会使数万资源的发布规划出现平方级开销。

保留冲突检查,改用已有 BTreeMap:检查路径祖先是否已存在,再查询有序范围中的首个潜在后代。新增双向祖先冲突、相同路径及相似字符串但不同路径组件的测试。

3. Handlebars 隐式 partial 复制当前上下文

即使前两处修复,真实模板中的 {{> head}}、header 和 footer 仍会让 Handlebars 深拷贝整站上下文。检查本机依赖 6.4.4 的 partial.rs 可见其通过 merge_json 构造 partial 的 base value;6.4.1 也有该行为。

这次没有 vendoring、修改依赖缓存或实现特殊的文本内联。站点模板采用 Handlebars 正式支持的显式上下文:{{> head page}},在 partial 中通过 @root.site.title 读取整站信息。这个依赖库边界已写入 SSG 文档;隐式 partial 的通用性能问题并未因此从 Handlebars 本身消失。

全量结果与限制

本机 release 单轮完整构建(含 Python prepare 扩展及输出文件写入,不含首次编译和 CSV 下载):

  • 51,739 张 HTML:51,225 详情 + 513 目录 + 1 首页。

  • 用时 6.974 s。

  • Linux 子进程 ru_maxrss 为 2,622,936 KiB,约 2.50 GiB;不是进程树内存总和。

  • HTML 合计 112,544,774 bytes,搜索索引 1,745,218 bytes。

  • 全量检查详情与分页数量,并解析所有 HTML 验证本地 href/src 存在。

未完成的性能工作:

  • 内存仍偏高,尚未做详细分配剖析;构建保留文档、环境、模板上下文和全部输出,不能据此宣称流式或增量构建。

  • template 自身的全站遍历仍可能产生平方级开销。

  • 显式传入大型对象的 partial 仍会复制该对象。

  • 命令扩展协议整体传递文档和数据;此轮未修改其协议或增加生成静态资源 API。搜索索引由显式数据准备阶段产生。

  • 当前数据只有物品基本字段,没有图标图片、分类中文名和获取来源;不能声称是完整物品获取途径库。

验证与复现

# Notist 根目录
cargo test -p notist publication:: --release
cargo test -p notist-ssg --release
cargo test -p notist -p notist-book --release
TERM=dumb NO_COLOR=1 cargo test -p notist-cli --release
cargo build -p notist-cli --release

# xiv-db 根目录
python3 scripts/items.py fetch
python3 scripts/items.py prepare
python3 -m unittest discover -s tests -v
/home/azurice/Files/notist/target/release/notist build
python3 scripts/check_site.py

CLI 测试在当前 TERM=xterm-256color 环境中有两项既有的重定向输出不含 ANSI 转义断言失败;设置 TERM=dumb NO_COLOR=1 后 CLI 测试全部通过,本次未改颜色处理逻辑。

XIV DB 的 Nix 沙箱构建通过显式本地输入 override 验证,不将本地路径写入依赖锁:

nix build --no-write-lock-file --override-input notist /home/azurice/Files/notist

修复尚未提交或发布,消费者默认锁定仍是远端旧版;发布 Notist 修复后应更新消费者 flake.lock,再验证不带 override 的构建。