inkjs多文件故事解决方案:JsonFileHandler与PosixFileHandler处理INCLUDE完全指南
【免费下载链接】inkjsA javascript port of inkle's ink scripting language.项目地址: https://gitcode.com/gh_mirrors/in/inkjs
inkjs 是 inkle 叙事语言 ink 的 JavaScript 移植版。编写多文件故事时,INCLUDE语句能否正确找到被包含的 .ink 文件,取决于你提供的文件处理器:inkjs 提供 PosixFileHandler 与 JsonFileHandler 两种方案。本文带你快速掌握这两个处理器的用法与选型。
为什么多文件故事需要文件处理器
一个较大的 ink 故事通常会拆成主文件 + 章节文件,通过 INCLUDE 语句合并,例如 include.ink 就演示了嵌套引入子文件的方式:
INCLUDE includes/included_file.ink INCLUDE includes/included_file_2.ink This is the main file.编译时的内部流程由解析器驱动(见 InkParser.ts):
- 解析器读到
INCLUDE xxx.ink; - 调用文件处理器的
ResolveInkFilename把文件名解析为完整路径; - 调用
LoadInkFileContents读取文件内容并递归解析; - 同时检测递归 INCLUDE,发现重复引入会报错
Recursive INCLUDE detected。
这两个方法的契约定义在 IFileHandler.ts 中。inkjs 默认给的是 DefaultFileHandler——它不做任何解析,一旦遇到 INCLUDE 就直接抛错,提示你"必须提供合适的 FileHandler"。
⚠️ 官方模板的 Node.js 示例正是这样处理多文件的:inkjs-compiler.ts 用
new PosixFileHandler(path.dirname(inputFile))把主文件所在目录设为根目录,因此相对路径的 INCLUDE 都能命中。
方案一:PosixFileHandler 磁盘多文件方案(Node.js 首选)
PosixFileHandler.ts 面向 Node.js 环境,直接读写磁盘:
- 构造时传入
rootPath(根目录),省略时默认为当前工作目录; ResolveInkFilename用path.resolve(process.cwd(), rootPath, filename)拼出绝对路径;LoadInkFileContents用fs.readFileSync(filename, "utf-8")读取。
最简用法:
const { Compiler } = require("inkjs/full"); const { PosixFileHandler } = require("inkjs/full"); const fileHandler = new PosixFileHandler("/path/to/stories"); const source = fs.readFileSync("/path/to/stories/main.ink", "utf-8"); const options = new CompilerOptions("main.ink", [], false, null, fileHandler); const story = new Compiler(source, options).Compile();📌 小提示:把rootPath指向主文件所在目录最稳妥,这样主文件里INCLUDE chapters/ch1.ink这类相对写法即可直接命中。
方案二:JsonFileHandler 内存映射方案(浏览器/前端首选)
浏览器没有文件系统,JsonFileHandler.ts 用一个Record<string, string>字典模拟文件树——键是文件名,值是 .ink 源码文本:
const hierarchy = { "main.ink": "INCLUDE chars.ink\n-> scene_start", "chars.ink": "+ scene_start\n 你好,世界" }; const fileHandler = new JsonFileHandler(hierarchy); const options = new CompilerOptions("main.ink", [], false, null, fileHandler);⚠️关键限制:JsonFileHandler 的ResolveInkFilename只接受字典中已存在的键,相对导入尚未实现,遇到不存在的文件名会抛出Cannot locate ... Are you trying a relative import ?。所以:
- 所有 INCLUDE 里写的文件名都必须原样作为字典的键;
- 文件名含子目录(如
chapters/ch1.ink)时,键也要写成完整字符串,与 INCLUDE 内容完全一致。
一张表看懂:两种处理器怎么选
| 对比项 | PosixFileHandler | JsonFileHandler |
|---|---|---|
| 运行环境 | Node.js(服务端/CLI) | 浏览器、内存环境 |
| 数据来源 | 磁盘真实文件 | 你传入的 文件内容字典 |
| 路径解析 | 自动拼绝对路径,支持相对路径 | 仅支持字典中完整键名 |
| 典型场景 | 命令行编译、CI 构建 | 前端打包、Serverless 模板 |
| 源码位置 | PosixFileHandler.ts | JsonFileHandler.ts |
官方browser_serverless模板(templates/browser_serverless/)走的就是前端直接持有故事内容的路线,与 JsonFileHandler 思路一致。
常见问题速查清单
- 报错 "Can't resolve filename because no FileHandler was provided"→ 忘了把 fileHandler 传给 CompilerOptions 的第五个参数;
- 报错 "Cannot locate xxx.ink. Are you trying a relative import?"→ JsonFileHandler 字典里缺少该键名;
- 报错 "Recursive INCLUDE detected"→ A 引入 B、B 又引入 A,检查引入链;
- 找不到文件但路径看起来对→ PosixFileHandler 的 rootPath 不是主文件所在目录;
- 浏览器方案→ 换用 JsonFileHandler 或按 webpack 指南 把 .ink 作为 asset 内联后编译单文件。
总结
inkjs 的多文件故事支持把"找文件"的职责交给 IFileHandler 接口:Node.js 环境交给PosixFileHandler读磁盘,浏览器环境交给JsonFileHandler查字典。只要选对处理器、配好根目录或文件字典,INCLUDE就能像 ink 原生一样顺畅工作,把大故事拆成可维护的多文件结构。
【免费下载链接】inkjsA javascript port of inkle's ink scripting language.项目地址: https://gitcode.com/gh_mirrors/in/inkjs
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考