第03章 - 环境准备与快速开始

本章的目标只有一个:在十分钟内把 CHAGS 跑起来,并知道日常开发最常用的几条命令和调试入口。如果只想体验游戏,做完 3.1–3.4 即可;如果要参与开发,把 3.5 之后的命令过一遍。

3.1 环境要求

依赖 版本 说明
Node.js 24.x Vite 8 需要现代 Node;仓库 CI 统一用 Node 24
pnpm 11.x 根 package.json 声明 "packageManager": "pnpm@11.22.0"
Git 任意近期版本 克隆仓库
浏览器 Chromium 系 / 微信内浏览器 开发预览与端到端测试

桌面壳与安卓壳的额外依赖(Rust、JDK、Android SDK)只在打包时需要,见第 14 章,普通开发不装也能跑。

安装 Node 与 pnpm

推荐用 nvm / fnm 管理 Node:

# 以 fnm 为例
fnm install 24
fnm use 24

# 启用 Corepack 后,pnpm 的版本由 package.json 自动接管
corepack enable

Windows 下如果没装过 pnpm,也可以用 npm i -g pnpm 作为兜底(核心约束只有一个:全仓统一使用 pnpm,不要混用 npm/yarn,否则 workspace:* 协议无法解析)。

克隆并安装依赖

git clone https://github.com/znlgis/CHAGS.git
cd CHAGS
pnpm install

pnpm-workspace.yaml 里已经声明了 apps/*、packages/*、games/* 三个工作区目录,以及需要执行安装脚本的依赖(esbuild、@tailwindcss/oxide)。安装完成后不会产生任何构建中间产物 —— 所有包都是「exports 直连源码」,直接跑就行。

3.2 启动开发服务器

pnpm dev

开发服务器在 http://127.0.0.1:5183 启动(apps/site/vite.config.ts 里配置了 strictPort: true,端口被占用会直接报错而不是静默换端口)。

打开后看到的是典故馆:十二张典故卡片按年代排序,每张卡片上有定性徽章(神话 / 传说 / 信史)、拼音、适用年龄、一句话寓意和关键词,右上角是已获得的星星。顶部导航只有三个按钮:

  • 典故馆 —— 全部典故列表,点「开始玩」进入游戏;
  • 我的图鉴 —— 通关后收集到的典故卡(未通关时是空状态提示);
  • English / 中文 —— 一键切换语言,界面、典故内容、语音全部跟随。

3.3 完整玩一遍:曹冲称象

以样板典故「曹冲称象」为例,说明一局的完整闭环(这也是理解整个教程的最小样本):

  1. 看故事:两幕绘本,每屏一句话,点屏幕任意位置继续(这一步有 350 毫秒的输入锁,防止孩子连点跳幕);
  2. 试着直接称:把大象拖到大秤上 —— 秤被压垮。问题是被玩家自己撞见的,而不是被告知的;
  3. 大象上船:拖大象上船,船身下沉,水面处留下一道待刻的水痕;
  4. 刻水痕:点船身刻一刀,水痕被「记」下来;
  5. 换石头:大象下船,从岸边石堆里一块块拖石头上船,直到水痕重新回到水面 —— 这一步就是等量代换本身。水位提示用箭头表示「还轻 / 太沉」,全程没有数字;
  6. 石头过秤:石头一块块搬上秤,读数累加出 3000,与大象图案并列成等式;
  7. 典故卡:星星、寓意、关键词、出处与原文,点「收下」回大厅,图鉴里多一张卡。

每一幕、每一次选择、每一次完成都会通过事件系统上报(scene:enter、beat:enter、choice:made、level:complete、card:unlocked……),这是自动化测试的观测基础,第 4 章会详细讲。

3.4 自动通关与调试直达

开发和测试时不需要手动玩,URL 上有三个调试开关(apps/site/src/shell/createGameContext.ts 解析):

参数 作用 例子
?autoplay=1 自动走完整个流程(含典故卡),并自动返回大厅 /?autoplay=1#/play/caochong-elephant
?lang=en 强制英文(优先级高于上次选择) /?lang=en#/play/pangu
?seed=fixed 注入确定性种子(当前游戏本身已是确定性的,此参数为将来的随机内容预留) /?seed=fixed#/play/pangu

组合使用:

http://127.0.0.1:5183/?autoplay=1&lang=en#/play/dayu

autoplay 模式下每个模板都实现了自己的「同路径自动操作」:例如 substitution 模板会自动把大象拖上船并连搬 60 块石头;tap 模板会自动循环点按;place 模板逐个归位。它们走的是与真实操作完全相同的代码路径,所以 autoplay 过 ≠ 真实操作过,端到端里两者都会跑(第 13 章)。

另外有两个观测窗口:

  • window.__chags.events —— 事件序列(如 ['session:start', 'scene:enter:story', 'beat:enter:s1', ...]);
  • window.__chags.lastError —— 最近一次载入失败的技术详情。玩家在界面上看到的是一句人话(「这个典故暂时打不开」),技术细节留给控制台与这个属性。

在浏览器控制台里随时可以查看:

window.__chags.events   // 事件轨迹
window.__chags.last     // 最近一条事件

3.5 日常命令

命令 场景 备注
pnpm dev 日常开发 热更新;改 packages/* 与 games/* 即时生效
pnpm typecheck 改完类型先跑 vue-tsc 全仓检查,含 .vue
pnpm lint 提交前 eslint flat config,逻辑层有额外禁令
pnpm test 改逻辑时随写随跑 Vitest;写作时实测 23 个文件、156 项全绿
pnpm content:check 改内容 JSON / 译文后 12 个典故的 schema 与双语完整性校验
pnpm verify 提交前的完整门禁 typecheck → lint → test → content:check → build → size
pnpm build + pnpm size 关心体积时 size 读 apps/site/dist,需先 build
pnpm e2e 改玩法交互后 首次需 npx playwright install chromium
pnpm e2e:dist 打包前 针对生产产物验证懒加载与代码分割
pnpm audit:i18n 改文案 / 版面 / 加语言后 双语 34 张画面截图到 .scratch/i18n-audit/(不入库)

pnpm verify 是「完成」的定义。它全绿之前不要提 PR —— 这不是纪律口号,而是因为其中每一环都对应一类真实故障:类型错、风格坏味道、逻辑回归、内容写错、构建失败、体积超预算。

3.6 构建产物与本地预览

pnpm build     # 产物在 apps/site/dist/
pnpm preview   # 本地服务器预览生产产物

构建之后可以看两个东西:

  1. 产物结构:dist/index.html 只引用外壳的 JS/CSS;Phaser 与各游戏的 chunk 全在 dist/assets/ 里按需加载;
  2. 体积报告:
pnpm size

输出会列出「首屏必须下载的」与「按需加载的 chunk」两组数字,并与预算对比:

首屏必须下载的:
  · assets/index-xxxx.js  xx.x KB (gzip)
check 首屏 JS+CSS 合计:xx.x KB / 预算 150 KB
按需加载的 chunk:
  · assets/phaser-xxxx.js  3xx KB (gzip)   ← 引擎共享 chunk
  · assets/pangu-xxxx.js    x KB (gzip)    ← 单游戏业务代码
体积在预算内 ✅

预算写在 scripts/check-size.mjs 的 BUDGETS 里(首屏 150 KB、单个懒加载 chunk 450 KB、assets 原始总量 3500 KB)。超预算会让 pnpm verify 失败,处置方式是优化或显式调预算并说明原因 —— 不允许悄悄绕过。

3.7 跑端到端测试

首次需要下载浏览器(一次性):

npx playwright install chromium

然后:

pnpm e2e        # 开发服务器上的 41 项用例(真实操作通关、autoplay、双语、慢设备、截图)
pnpm e2e:dist   # 先 build 再起 preview,验证生产产物
pnpm audit:i18n # 双语版面巡检(约 6 分钟),截图在 .scratch/i18n-audit/

失败时的产物会自动留在 test-results/(截图 + trace),CI 上会作为 artifact 上传。

3.8 常见问题

1)pnpm install 报找不到 workspace 依赖 / workspace:* 无法解析

用错包管理器了。删除 node_modules 后用 pnpm 重装;不要用 npm 或 yarn 安装这个仓库。

2)端口 5183 被占用

strictPort: true 会直接报错。要么停掉占用进程,要么临时改 apps/site/vite.config.ts 里的端口(改了之后 e2e 的 baseURL 也要同步,所以更推荐前者):

# Windows
netstat -ano | findstr 5183
# macOS / Linux
lsof -i :5183

3)vue-tsc 报 ERR_PACKAGE_PATH_NOT_EXPORTED: './lib/tsc'

TypeScript 被升级到大版本 7 了。仓库刻意锁在 ~5.9.3(原因见第 2 章),恢复 pnpm install 的锁定版本即可;不要单独 pnpm add typescript@latest。

4)pnpm e2e 报没找到浏览器

先执行 npx playwright install chromium。CI 上用的是 pnpm exec playwright install --with-deps chromium(含系统依赖)。

5)pnpm size 报 ENOENT ... apps/site/dist/index.html

size 读的是构建产物,先 pnpm build。pnpm verify 里顺序已经排好,不用手跑。

6)Windows 上 pnpm dist:apk 报 Gradle 与 JDK 不兼容

那是 JDK 25 的问题。把 JDK 17–24 装到常见目录(如 C:\Program Files\Eclipse Adoptium),或者用 CHAGS_JDK 环境变量指定,scripts/build-apk.mjs 会自动挑。

3.9 小结

到这里你已经可以:安装依赖、启动开发服务器、玩通并自动通关任意典故、跑完整质量门禁、构建并检查体积、跑端到端。下一章进入开发部分的第一站 —— 整个架构的心脏:核心契约与游戏生命周期。