Node.js、浏览器和 Cloudflare Workers 的wasm引入问题

💡 原文中文,约1300字,阅读约需4分钟。
📝

内容提要

文章比较了不同 JavaScript 环境加载 Wasm 的方式:Cloudflare Workers 可直接 import .wasm,浏览器使用 fetch 配合 instantiateStreaming,Node.js 需读取文件。为实现统一初始化接口,作者通过 process.getBuiltinModule("fs") 动态获取 fs,避免顶层 import 在浏览器和 Workers 中报错,从而统一调用方式。

🔎

延伸解读

环境差异带来的加载方式分歧

文章指出,Cloudflare Workers 可直接 import .wasm 文件,浏览器需通过 fetch 配合 instantiateStreaming,而 Node.js 则需从文件系统读取二进制。这种差异导致同一 Wasm 库在不同平台需要不同的初始化代码,增加了维护成本。作者最初为三个环境分别编写了 8 个 .mjs 文件,正是这种分歧的直接体现。

统一初始化接口的设计思路

作者提出让初始化函数只接受两种参数:字符串路径或 Cloudflare Workers 中的 WebAssembly.Module 对象。这样,调用方无需关心底层加载细节,只需传入对应参数即可。这种抽象简化了跨环境使用,但实现时需要解决 Node.js 特有的文件读取问题。

Node.js 文件读取的兼容性挑战

在 Node.js 中读取 .wasm 文件必须引入 node:fs 模块,但顶层 import 在浏览器和 Cloudflare Workers 中会报错,即使使用 typeof process 提前判断环境也无法避免。这导致代码无法在多个环境中通用,成为统一接口的主要障碍。

利用 getBuiltinModule 动态获取 fs

作者发现可以通过 process.getBuiltinModule("fs") 动态获取 fs 模块,从而避免顶层 import。这样,在 Node.js 环境下可以安全地读取文件并编译 Wasm,而在其他环境中则不会执行该分支。最终,初始化函数统一为接受路径或 Module 对象,调用方式在各平台保持一致。

❓

Q&A

Cloudflare Workers 中如何加载 Wasm 模块?

在 Cloudflare Workers 中,可以直接使用 import 语句导入 .wasm 文件,例如:import wasm from "./simple.wasm"; 然后通过 WebAssembly.instantiate(wasm, imports) 来实例化。Cloudflare 会将 .wasm 模块作为 WebAssembly.Module 提供给代码。

浏览器中加载 Wasm 的常见方法是什么?

浏览器通常通过 fetch() 获取 Wasm 文件,再使用 WebAssembly.instantiateStreaming() 进行实例化,例如:const { instance } = await WebAssembly.instantiateStreaming(fetch("./simple.wasm"), imports);

Node.js 中如何加载 Wasm 文件?

Node.js 需要通过文件系统读取 .wasm 二进制文件,然后使用 WebAssembly.instantiate() 进行初始化。.instantiate() 的第一个参数必须是 typed array 或 ArrayBuffer。

为什么在 Node.js 中引入 fs 模块会导致浏览器和 Workers 报错?

因为 JavaScript 的 import 语句必须在顶层使用,而 Node.js 需要 import "node:fs" 来读取 .wasm 文件。如果在顶层引入,在浏览器和 Cloudflare Workers 环境中会因不支持 Node.js 内置模块而报错。即使使用 typeof process 提前判断环境也无法避免,因为 import 是静态的。

如何统一不同 JavaScript 环境下的 Wasm 初始化接口?

可以设计一个初始化函数,只接受两种参数:字符串路径或 WebAssembly.Module 对象。在 Node.js 中,通过 process.getBuiltinModule("fs") 动态获取 fs 模块来读取文件,避免顶层 import。这样,Cloudflare Workers 可以传入 WebAssembly.Module,而浏览器和 Node.js 可以传入路径字符串,实现统一调用。

process.getBuiltinModule 方法有什么作用?

process.getBuiltinModule 是 Node.js 的一个方法,可以动态获取内置模块(如 fs),而无需在顶层使用 import 语句。这样可以在需要时获取模块,避免在浏览器和 Cloudflare Workers 等环境中因顶层 import 而报错,从而实现跨环境兼容。

🏷️

标签

➡️

继续阅读