201 lines
11 KiB
Markdown
201 lines
11 KiB
Markdown
# 工程优化审查报告(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 体积
|
||
|
||
## 一句话结论
|
||
|
||
这个仓库已经从“功能堆叠期”进入“工程收尾期”了。当前最值得做的不是再加一层玩法,而是把门禁补齐、把超级模块拆开、把半迁移状态收尾;只要这一步做稳,后续继续扩展剧情、编辑器和自定义世界的成本都会明显下降。
|