DOCUMENTATION · 构建指南
构建指南
本文档说明如何搭建环境、安装依赖、启动开发服务器、产出生产构建,以及如何编译 Rust WASM 插件。
本项目不使用 Python,仓库中不存在任何
.py文件,也不存在任何 Python 构建步骤。 所有脚本都是 Node.js(.mjs)或 Rust(cargo)。 WASM 插件只用 Rust,本构建指南不包含 AssemblyScript 构建步骤。
1. 环境要求
| 组件 | 版本要求 | 用途 | 是否必需 |
|---|---|---|---|
| Node.js | ≥ 18(开发时以 Node 22 验证) | 跑 Vite / Vitest / 构建脚本 | 必需 |
| npm | ≥ 9 | 安装依赖、执行脚本 | 必需 |
| Rust(stable) | 1.70+ | 编译 WASM 插件 | 仅构建 WASM 插件时必需 |
wasm32-unknown-unknown target | — | Rust 交叉编译目标 | 仅构建 WASM 插件时必需 |
仓库内已经内置 WASM 插件构建产物(如 public/plugins/hello-wasm/plugin.wasm),
因此只想运行示例的话,可以不安装 Rust,直接 npm install && npm run dev 即可。
检查环境
node -v # 期望 v18.x / v20.x / v22.x
npm -v # 期望 9.x 及以上
cargo --version # 仅在需要构建 WASM 插件时检查2. 安装依赖
在仓库根目录执行:
npm install- 本项目没有运行时依赖,
dependencies为空。 - 开发依赖:
vite、typescript、vitest、@types/node。 - 安装完成后会生成
node_modules/与package-lock.json。
3. 开发模式启动
npm run dev- Vite 默认监听 http://localhost:5173/;端口被占用时会自动顺延(如 5174),以终端输出为准。
- 页面启动后自动读取
public/stories/index.json,加载其中第一个剧情并播放。 public/下的文件(剧情、插件清单、plugin.wasm)都是静态资源, 修改后直接刷新页面即可生效,无需重启 dev server。
4. 类型检查与测试
npm run typecheck # tsc --noEmit,严格模式类型检查
npm test # vitest run,一次性跑完所有用例
npm run test:watch # vitest,监听模式测试覆盖:表达式 DSL(tests/expression.test.ts)、剧情执行(tests/story.test.ts)、
插件管理器(tests/plugin-manager.test.ts)、WASM ABI 集成(tests/wasm-abi.test.ts)、
世界模拟器(tests/world-loop.test.ts)。
当前共 31 个用例,npm test 全绿。
5. 生产构建
npm run build # 等价于:tsc --noEmit && vite build
npm run preview # 本地预览产物,默认 http://localhost:4173/- 构建产物输出到
dist/,可直接部署到任意静态托管(Nginx / GitHub Pages / CDN)。 构建有四个页面入口(vite.config.ts的rollupOptions.input):index.html(引擎演示页)、editor.html(给编剧的剧本编辑器)、embed.html(嵌入子页)、embed-demo.html(嵌入演示父页)、showcase.html(展示页:故事库 + 内嵌演示 + 发布三步); 它们共享同一个引擎 chunk。 另外npm run build:lib产出库形态(dist-lib/rne.js+ 类型声明),与上面这套应用构建互不影响。 - ⚠️ 响应头不会随
dist/走:vite.config.ts里的COOP/COEP只作用于 dev 与 preview。 生产部署时要么由托管方回传(见 CROSS_ORIGIN.md §4),要么不开—— 但开与不开都有代价:开了会拦掉所有不带 CORP 的跨域资源、切断window.opener, 不开则 SAB 相关能力不可用(本引擎默认不使用 SAB,所以默认不开)。 详细取舍见 CROSS_ORIGIN.md。 - 注意:
public/目录下的内容会被 Vite 原样拷贝到dist/根目录, 因此部署后剧情与插件路径与开发环境一致(/stories/...、/plugins/...)。 - 若部署在子路径(如
https://example.com/story/),需在vite.config.ts中设置base, 并相应调整剧情文件里的插件路径。
6. 构建 Rust WASM 插件
以下命令均不需要 Python。
6.1 安装 Rust 与 target(仅首次)
# 安装 rustup / Rust(若尚未安装)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
# 或访问 https://rustup.rs 按平台指引安装
# 添加 wasm32 目标(关键,缺了会报 can't find crate for `std`)
rustup target add wasm32-unknown-unknown6.2 手动构建
仓库内的 WASM 插件 crate 都位于 wasm-src/<crate>/(如 hello-wasm),构建命令完全相同:
cd wasm-src/hello-wasm
cargo build --target wasm32-unknown-unknown --release产物路径:
wasm-src/hello-wasm/target/wasm32-unknown-unknown/release/hello_wasm.wasmcrate 名
hello-wasm会被转成hello_wasm.wasm(连字符转下划线)。 若你的 crate 名是my-plugin,产物就是my_plugin.wasm。
复制产物到插件目录(文件名必须是 manifest 里 entry 指定的名字,示例为 plugin.wasm):
cp wasm-src/hello-wasm/target/wasm32-unknown-unknown/release/hello_wasm.wasm \
public/plugins/hello-wasm/plugin.wasm6.3 用内置脚本一键构建(推荐)
仓库提供的 scripts/build-wasm.mjs 会把上面「构建 + 复制」两步自动化(纯 Node.js):
npm run build:wasm脚本行为:
- 遍历
wasm-src/下登记的 crate 清单(每个 crate 对应一个插件,可随时增减); - 执行
cargo --version检查 Rust 是否可用(可用CARGO环境变量指定 cargo 路径); - 逐个执行
cargo build --target wasm32-unknown-unknown --release; - 把各产物复制到对应插件目录(
public/plugins/<id>/plugin.wasm),并打印体积。
新增 WASM 插件时,在
scripts/build-wasm.mjs顶部的PLUGINS数组追加一条即可。
6.4 构建全部(WASM + 前端)
npm run build:all # = npm run build:wasm && npm run build7. 目录复制与静态资源说明
| 源 | 角色 | 部署后位置 |
|---|---|---|
public/stories/*.json | 剧情文件与清单 | dist/stories/*.json |
public/plugins/<id>/manifest.json | 插件清单 | dist/plugins/<id>/manifest.json |
public/plugins/<id>/index.js | JS 插件入口 | dist/plugins/<id>/index.js |
public/plugins/<id>/plugin.wasm | Rust WASM 插件产物 | dist/plugins/<id>/plugin.wasm |
要点:
- WASM 产物必须放在
public/下(或在构建时复制进去),否则 Vite 不会把它当作静态资源发布。 - 剧情内声明插件时使用的是运行时可访问的 URL,例如
"plugins": ["/plugins/hello-js/manifest.json"]。部署到子路径时要同步修改。 - 更新 WASM 插件后记得刷新页面;引擎对清单与剧情请求默认带
cacheBust,但浏览器对.wasm仍可能缓存,遇到「代码改了没生效」可强制刷新(Ctrl/Cmd + Shift + R)。
8. 常见构建问题
8.1 can't find crate for \std``
未安装 wasm32 目标。执行:
rustup target add wasm32-unknown-unknown8.2 error: linking with \rust-lld` failed` / 找不到内存导出
Cargo.toml 缺少 crate-type = ["cdylib"]。确认:
[lib]
crate-type = ["cdylib"]8.3 npm run build:wasm 提示「未找到 cargo」
Rust 未安装或不在 PATH。可安装 Rust,或显式指定:
CARGO=/path/to/cargo npm run build:wasm8.4 构建成功但页面报「WASM 插件缺少 xxx 导出」
产物不是 cdylib,或导出函数名被 #[no_mangle] 之外的因素改名。
检查 src/lib.rs 中每个 ABI 函数都带 #[no_mangle] pub extern "C",
导出清单见 docs/ABI.md。
8.5 npm run build 报 TypeScript 错误
先本地跑 npm run typecheck 定位。项目开启了 strict、noUnusedLocals、
noUnusedParameters,未使用的变量/参数也会报错。
8.6 部署后剧情 / 插件 404
- 确认
dist/stories/、dist/plugins/存在(public/内容是否被拷贝); - 若部署在子路径,检查
vite.config.ts的base与剧情内的插件 URL 前缀。
9. 明确不包含的内容
- ❌ 不包含 AssemblyScript 构建步骤,也不提供
.ts→ wasm 的 AssemblyScript 示例。 - ❌ 不使用 Python / Pyodide,不生成
.py文件,不使用任何 Python 工具链。 - ❌ 不使用 wasm-bindgen(插件直接导出 C ABI,减少胶水层,便于运行时动态加载)。
Rust WASM 插件的完整源码与 ABI 说明见 docs/PLUGIN_WASM.md 与 docs/ABI.md。