Files
Genarrative/docs/audits/engineering/ENGINEERING_OPTIMIZATION_REVIEW_2026-04-01.md
高物 ddcb5d5c8c
Some checks failed
CI / verify (push) Has been cancelled
Rework story engine flow and reorganize project docs
2026-04-06 23:19:00 +08:00

11 KiB
Raw Blame History

工程优化审查报告2026-04-01

审查范围

  • 扫描范围:src/scripts/docs/.github/package.jsontsconfig*.jsonvite.config.tsvitest.config.ts
  • 审查方式:阅读当前工作区代码结构,抽查核心运行时、编辑器、服务层与开发脚本,并执行工程命令验证现状
  • 当前快照说明:仓库存在大量未提交改动,本报告基于当前工作区状态,不假定这些改动都已经合入主分支
  • 说明:按仓库要求,不把中文乱码本身当成本次审查重点;只讨论工程结构、门禁、可维护性、可测试性和扩展成本

已执行检查

  • npm run lint:eslint 结果:失败。src/components/ItemCatalogEditor.tsx:167 存在未使用的 isSearchPendingstartTransition
  • npm run typecheck 结果:通过
  • npm run test 结果:通过,默认套件实际执行 10 个测试文件、28 个测试
  • npm run build 结果:通过,但 src/services/customWorldPresentation.ts:163-169 出现 duplicate key 警告
  • npm run check:content 结果:通过

当前结论

这轮代码库已经明显比前几版更有工程骨架了,至少有这些积极变化:

  • src/main.tsx + src/routing/appRoutes.tsx 已经承担了入口路由分发
  • src/App.tsx 已经比过去瘦很多,主流程开始交给 hook 和壳组件
  • src/components/PresetEditor.tsx 已经成为较薄的 lazy shell而不是继续堆成巨型入口
  • src/editor/shared/jsonClient.tssrc/persistence/src/hooks/combat/src/hooks/story/ 这些目录说明仓库已经开始做分层
  • CI、Vitest、ESLint、内容校验脚本都已经接上不再是完全裸奔状态

但从工程角度看,当前最值得优先优化的,不是继续加功能,而是把“半完成的工程化”补齐。核心问题集中在 6 个方面。

P0质量门禁和真实风险点仍然脱节

现状

仓库已经引入了 lint、typecheck、test、build 和 content checks但关键热区并没有真正纳入统一门禁。

证据

  • .eslintrc.cjs:47-63ignorePatterns 直接跳过了多个高复杂度核心文件: src/components/AdventurePanel.tsxsrc/components/NpcVisualEditor.tsxsrc/components/preset-editor/PresetEditorPanels.tsxsrc/hooks/useStoryGeneration.tssrc/services/customWorldPresentation.ts
  • tsconfig.typecheck-guardrails.json:6-15 只对非常有限的一小组文件开启严格类型检查,远没有覆盖主运行时链路
  • vitest.config.ts:8-10customWorldPresentation 映射到 stubvitest.config.ts:20 还排除了真实存在的 src/services/ai.test.ts
  • 当前 src/ 下共有 161 个文件,测试文件共有 11 个,但默认套件只执行其中 10 个
  • npm run build 已经能暴露 src/services/customWorldPresentation.ts:163-169 的 duplicate key 警告,但这块文件同时被 ESLint ignore、被 Vitest stub 掉,说明真实风险没有被完整看见

影响

  • 工程信号不一致:test 绿、build 过,不代表关键模块真的健康
  • 复杂模块越是难测,越容易被长期豁免,最后演变成“最关键的地方最不受控”
  • 后续重构会缺乏可靠的回归保护review 只能更多依赖人工记忆

建议

  • 先缩小 .eslintrc.cjs 的 ignore 范围,优先把 useStoryGeneration.tscustomWorldPresentation.tsPresetEditorPanels.tsx 拉回 lint
  • src/services/ai.test.ts 重新纳入默认测试套件,除非有明确且短期的阻塞原因
  • 不要长期依赖 tsconfig.typecheck-guardrails.json 的 allowlist至少把 src/hooks/src/services/src/components/game-shell/ 逐步纳入 strict 范围
  • 对 build warning 建立明确策略:要么在 CI 中失败,要么把 warning 收敛到零

P0当前工作区不在真正的绿色基线

现状

当前代码不是“纯优化空间”问题,而是已经存在直接可见的门禁破口。

证据

  • package.json:11-15lint:eslinttypecheck 定义成正式脚本,说明它们本来就属于项目基线
  • 实际执行 npm run lint:eslint 时,src/components/ItemCatalogEditor.tsx:167 报出未使用变量错误
  • src/components/ItemCatalogEditor.tsx:167 引入了 useTransition() 返回值,但当前组件没有消费它
  • npm run build 虽然成功,但 src/services/customWorldPresentation.ts:163-169 仍然有重复 object key 警告

影响

  • 团队会越来越难区分“可接受的技术债”和“已经破坏基线的问题”
  • 继续叠加功能会把问题扩散到更多文件,后面补起来成本更高

建议

  • 先恢复工作区绿色基线,再继续推进大功能
  • 把“lint 零错误、build 零 warning”作为下一轮工程整理的硬目标

P1运行时主链路仍然被少数超级模块吸住

现状

入口已经变薄,但主复杂度仍集中在少数大文件里,尤其是故事推进、战斗同步和界面编排三层。

证据

  • src/hooks/useStoryGeneration.ts 当前约 2210 行
  • src/hooks/useStoryGeneration.ts:694 导出主 hooksrc/hooks/useStoryGeneration.ts:1416 接入 useTreasureFlow,后面还继续承接 NPC 互动、库存、打字机、AI、历史推进和故事回写
  • src/hooks/useCombatFlow.ts:134 是主战斗 hooksrc/hooks/useCombatFlow.ts:796-832 仍然负责逃跑流程与 story sync 的耦合
  • src/components/GameShell.tsx 当前约 791 行,src/components/GameShell.tsx:260-269 管理一组本地 UI 状态,src/components/GameShell.tsx:482 继续处理场景切换时的选择编排
  • 构建产物里 dist/assets/App-*.js 约 389 kBdist/assets/index-*.js 约 198 kB说明主运行时 chunk 仍然偏重

影响

  • 任何一个功能变化都容易跨 story、combat、transition、panel 几条链一起改
  • hook 单测越来越难写,因为副作用、异步和 UI 编排仍然混在一起
  • App 主 chunk 偏重,会继续拖累首屏和回归速度

建议

  • 继续把 useStoryGeneration 收敛成 orchestration 层,把 treasure、NPC、inventory、chat、typewriter、AI 回写拆成更纯的领域 action
  • useCombatFlow 更明确地区分“战斗结算”和“播放同步”
  • GameShell 进一步下沉为 scene transition、selection flow、overlay panel 三类 view-model

P1编辑器共享层只迁移了一半重复基础设施还在

现状

编辑器入口已经做了 shell 化,但真正的复杂度仍然堆在大型面板组件里,而且共享层没有吃干净。

证据

  • src/components/PresetEditor.tsx:41 的入口已经很薄,说明方向是对的
  • src/components/preset-editor/PresetEditorPanels.tsx 仍然约 2163 行
  • src/components/preset-editor/PresetEditorPanels.tsx:55 仍然自带 cloneValue
  • src/components/preset-editor/PresetEditorPanels.tsx:117 仍然自带 saveJsonObject
  • src/components/preset-editor/PresetEditorPanels.tsx:189 仍然自带 SectionCard
  • 与之对应,src/editor/shared/jsonClient.ts:29-40 已经提供了共享版 fetchJson / saveJsonObject
  • src/components/preset-editor/PresetEditorPanels.tsx:364:1128:1500:1806 仍然把四个大型 panel 放在同一个文件里

影响

  • 编辑器的保存、错误处理、基础 UI 容器会继续多处复制,后续很难统一行为
  • 迁移看起来开始了,但没有真正收尾,维护者仍然需要在“大文件 + 共享层”之间来回切换

建议

  • 继续把 PresetEditorPanels.tsx 拆成按 tab 或按领域分文件
  • 统一复用 src/editor/shared/ 下的保存客户端、基础容器、表单片段
  • 对编辑器做一次“小型迁移收尾”,目标是消灭重复的基础 helper

P1本地开发 API 层与构建工具耦合过深

现状

本地 API 插件已经把很多临时逻辑吸收进项目内部,这是好事;但它现在承担的职责太多,且全部挂在 Vite 插件层。

证据

  • vite.config.ts:7-18 直接把 createLocalApiPlugins(__dirname, env) 注入到 Vite config
  • scripts/dev-server/localApiPlugins.ts 当前约 394 行
  • scripts/dev-server/localApiPlugins.ts:150 定义 LLM proxy 插件
  • scripts/dev-server/localApiPlugins.ts:216 定义通用 JSON 文件编辑插件
  • scripts/dev-server/localApiPlugins.ts:265 直接把编辑器保存结果写回 src/data/*.json
  • scripts/dev-server/localApiPlugins.ts:429 再统一把所有插件拼到一起

影响

  • dev server、preview server、编辑器持久化和 LLM 代理被绑在一个文件里,测试与替换成本都偏高
  • 随着编辑器继续扩张,这个文件会继续演化成“隐形后端”
  • 生产与开发环境的边界容易模糊,问题排查也更依赖熟悉 Vite 插件机制的人

建议

  • 至少先按职责把 localApiPlugins.ts 拆成 llm-proxyjson-editor-apiasset-catalog 三块
  • 下一阶段可以考虑把编辑器 API 抽成独立本地服务层,而不是继续塞在 Vite 插件里
  • 给 JSON 写入接口补 schema 校验,而不只是“是 object 就写入”

P2构建体积仍有继续优化空间

现状

路由 lazy load 和部分 modal lazy load 已经做了,但主游戏运行时包仍然偏大。

证据

  • dist/assets/App-*.js 约 389 kB
  • dist/assets/index-*.js 约 198 kB
  • dist/assets/index-*.css 约 117 kB
  • src/components/GameShell.tsxsrc/hooks/useStoryGeneration.tssrc/services/prompt.ts 仍然是较大的主链路文件

影响

  • 新人本地启动、构建和回归阅读成本仍然偏高
  • 主运行时模块越重,越不利于后续继续做场景扩展和编辑器共存

建议

  • 优先沿着“运行时 orchestration 拆分”去减主 chunk而不是单纯追求更多 lazy import
  • prompt、自定义世界、编辑器预览等非首屏关键代码继续做边界拆分
  • 每轮重构后用真实构建产物复测,而不是只凭代码体感判断

建议的落地顺序

  1. 先恢复绿色基线:修掉 ItemCatalogEditor lint 错误,处理 customWorldPresentation 的 duplicate key warning
  2. 再补齐门禁:缩小 ESLint ignore、把 ai.test.ts 拉回默认测试、扩大 strict typecheck 覆盖
  3. 然后拆主链:优先处理 useStoryGenerationuseCombatFlowGameShell
  4. 再做编辑器迁移收尾:拆 PresetEditorPanels.tsx,统一共享层
  5. 最后处理 dev API 分层和 bundle 体积

一句话结论

这个仓库已经从“功能堆叠期”进入“工程收尾期”了。当前最值得做的不是再加一层玩法,而是把门禁补齐、把超级模块拆开、把半迁移状态收尾;只要这一步做稳,后续继续扩展剧情、编辑器和自定义世界的成本都会明显下降。