Node.js、浏览器和 Cloudflare Workers 的wasm引入问题
Posted | stdout
最近在鼓捣 WebAssembly,这玩意没啥神秘的,可以看出一坨二进制的 .js 库文件
它本身的export和调用方式是统一的,但如今天我才知道,在不同 JavaScript 运行环境加载 .wasm 方式并不完全一样。
例如 Cloudflare Workers 可以直接:
import wasm from "./simple.wasm";
const { instance } = await WebAssembly.instantiate(wasm, imports);
Cloudflare 会把 .wasm 模块作为 WebAssembly.Module 提供给代码。
浏览器通常则是通过 fetch() 获取 Wasm,再使用 WebAssembly.instantiateStreaming():
const { instance } = await WebAssembly.instantiateStreaming(
fetch("./simple.wasm"),
imports,
);
Node.js 则通过文件系统读取 .wasm 二进制,然后初始化。
.instantiate() 第一参数必须是 typed array 或者 ArrayBuffer
我自己写了个 Wasm 库,AI 为 Node、浏览器、Cloudflare Workers 分别写一套初始化代码,8个 .mjs 文件。给我搞懵了。
提了个简化思路:让初始化函数只接受两种东西:string 表示路径,或者cf那种 WebAssembly.Module 对象
然后搞的时候发现,为了兼容 nodejs,必须 import "node:fs" ,才能读 .wasm 文件嘛
然后逆天的 js 引入必须在 top-level ,在 cf 和浏览器侧就必挂。你 typeof process 提前判断一下环境都不行。
不过AI这时候想到一个聪明办法
if (process?.getBuiltinModule) {
const fs = process.getBuiltinModule("fs");
const bytes = await fs.promises.readFile(source);
return WebAssembly.compile(bytes);
}
卧槽,有这么好的办法,你为啥不早点告诉我。
于是使用方式统一成:
Cloudflare Workers
import wasm from "./simple.wasm";
import { init } from "./foo.mjs";
const foo = await init(wasm);
Browser / Node.js
import { init } from "./foo.mjs";
const foo = await init("./simple.wasm");
Comments