# 工程优化审查报告(2026-04-01) ## 审查范围 - 扫描范围:`src/`、`scripts/`、`docs/`、`.github/`、`package.json`、`tsconfig*.json`、`vite.config.ts`、`vitest.config.ts` - 审查方式:阅读当前工作区代码结构,抽查核心运行时、编辑器、服务层与开发脚本,并执行工程命令验证现状 - 当前快照说明:仓库存在大量未提交改动,本报告基于当前工作区状态,不假定这些改动都已经合入主分支 - 说明:按仓库要求,不把中文乱码本身当成本次审查重点;只讨论工程结构、门禁、可维护性、可测试性和扩展成本 ## 已执行检查 - `npm run lint:eslint` 结果:失败。`src/components/ItemCatalogEditor.tsx:167` 存在未使用的 `isSearchPending` 和 `startTransition` - `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.ts`、`src/persistence/`、`src/hooks/combat/`、`src/hooks/story/` 这些目录说明仓库已经开始做分层 - CI、Vitest、ESLint、内容校验脚本都已经接上,不再是完全裸奔状态 但从工程角度看,当前最值得优先优化的,不是继续加功能,而是把“半完成的工程化”补齐。核心问题集中在 6 个方面。 ## P0:质量门禁和真实风险点仍然脱节 ### 现状 仓库已经引入了 lint、typecheck、test、build 和 content checks,但关键热区并没有真正纳入统一门禁。 ### 证据 - `.eslintrc.cjs:47-63` 的 `ignorePatterns` 直接跳过了多个高复杂度核心文件: `src/components/AdventurePanel.tsx`、`src/components/NpcVisualEditor.tsx`、`src/components/preset-editor/PresetEditorPanels.tsx`、`src/hooks/useStoryGeneration.ts`、`src/services/customWorldPresentation.ts` - `tsconfig.typecheck-guardrails.json:6-15` 只对非常有限的一小组文件开启严格类型检查,远没有覆盖主运行时链路 - `vitest.config.ts:8-10` 把 `customWorldPresentation` 映射到 stub,`vitest.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.ts`、`customWorldPresentation.ts`、`PresetEditorPanels.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-15` 把 `lint:eslint` 和 `typecheck` 定义成正式脚本,说明它们本来就属于项目基线 - 实际执行 `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` 导出主 hook,`src/hooks/useStoryGeneration.ts:1416` 接入 `useTreasureFlow`,后面还继续承接 NPC 互动、库存、打字机、AI、历史推进和故事回写 - `src/hooks/useCombatFlow.ts:134` 是主战斗 hook,`src/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 kB,`dist/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-proxy`、`json-editor-api`、`asset-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.tsx`、`src/hooks/useStoryGeneration.ts`、`src/services/prompt.ts` 仍然是较大的主链路文件 ### 影响 - 新人本地启动、构建和回归阅读成本仍然偏高 - 主运行时模块越重,越不利于后续继续做场景扩展和编辑器共存 ### 建议 - 优先沿着“运行时 orchestration 拆分”去减主 chunk,而不是单纯追求更多 lazy import - 对 `prompt`、自定义世界、编辑器预览等非首屏关键代码继续做边界拆分 - 每轮重构后用真实构建产物复测,而不是只凭代码体感判断 ## 建议的落地顺序 1. 先恢复绿色基线:修掉 `ItemCatalogEditor` lint 错误,处理 `customWorldPresentation` 的 duplicate key warning 2. 再补齐门禁:缩小 ESLint ignore、把 `ai.test.ts` 拉回默认测试、扩大 strict typecheck 覆盖 3. 然后拆主链:优先处理 `useStoryGeneration`、`useCombatFlow`、`GameShell` 4. 再做编辑器迁移收尾:拆 `PresetEditorPanels.tsx`,统一共享层 5. 最后处理 dev API 分层和 bundle 体积 ## 一句话结论 这个仓库已经从“功能堆叠期”进入“工程收尾期”了。当前最值得做的不是再加一层玩法,而是把门禁补齐、把超级模块拆开、把半迁移状态收尾;只要这一步做稳,后续继续扩展剧情、编辑器和自定义世界的成本都会明显下降。