Logo of unwasm

unwasm

适用于 JavaScript 的 WebAssembly 工具

适用于 JavaScript 的通用 WebAssembly 工具。

目标

本项目旨在为 WebAssembly 模块支持提供一个通用且面向未来的解决方案,适用于各种 JavaScript 运行时、框架和构建工具,尽可能遵循 WebAssembly 社区组的 WebAssembly/ES 模块集成 提案,同时努力保持与现有生态系统库的兼容性。

绑定 API

当导入 .wasm 模块时,unwasm 在构建过程中解析、读取并解析模块,以获取有关导入和导出的信息,甚至尝试自动解析导入并为打包工具生成适当的代码绑定。

如果目标环境支持顶层 await 且 wasm 模块不需要导入对象(或者它们可以自动解析),unwasm 会生成绑定,允许像导入任何其他 ESM 模块一样导入 wasm 模块。

如果目标环境不支持顶层 await,或者 wasm 模块需要导入对象,或者 lazy 插件选项设置为 true,unwasm 将导出一个包装的 Proxy 对象,该对象可以作为函数调用,以惰性地使用自定义导入对象评估模块。这样我们仍然可以拥有尽可能接近 ESM 模块的简单语法,并且可以惰性初始化模块。

示例:使用静态导入

import { sum } from "unwasm/examples/sum.wasm";

示例:使用动态导入

const { sum } = await import("unwasm/examples/sum.wasm");

如果您的 WebAssembly 模块需要导入对象(unwasm 可以自动推断它们),则用法语法会略有不同,因为我们首先需要使用导入对象初始化模块。

示例:使用带导入对象的动态导入

const { rand } = await import("unwasm/examples/rand.wasm").then((r) =>
  r.default({
    env: {
      seed: () => () => Math.random() * Date.now(),
    },
  }),
);

示例:使用带导入对象的静态导入

import initRand, { rand } from "unwasm/examples/rand.wasm";

await initRand({
  env: {
    seed: () => () => Math.random() * Date.now(),
  },
});
当使用静态导入语法时,在初始化模块之前,命名导出将被包装到一个代理函数中,该函数会等待模块初始化。如果在初始化之前调用,它将立即尝试不带导入地调用初始化,并返回一个在初始化之后调用函数的 Promise。

模块兼容性

有些情况下,库需要 WebAssembly.Module 实例来初始化其自身的 WebAssembly.Instance。为了最大化兼容性,unwasm 允许使用特定的导入后缀 ?module 直接将 .wasm 文件作为模块导入。

import _sumMod from "unwasm/examples/sum.wasm?module";
const { sum } = await WebAssembly.instantiate(_sumMod).then((i) => i.exports);
请向我们提交问题!我们很乐意帮助这些库进行迁移!

集成

Unwasm 需要将 .wasm 导入转换为兼容的绑定。目前,唯一的方法是使用 Rollup 插件。未来将引入更多使用方法。

安装

首先,安装 unwasm npm 包。

# ✨ Auto-detect
npx nypm install unwasm

# npm
npm install unwasm

# yarn
yarn add unwasm

# pnpm
pnpm install unwasm

# bun
bun install unwasm

构建器插件

Rollup
// rollup.config.js
import { rollup as unwasm } from "unwasm/plugin";

export default {
  plugins: [
    unwasm({
      /* options */
    }),
  ],
};

插件选项

  • esmImport:直接导入 wasm 文件而不是打包,Cloudflare Workers 需要此项,并适用于允许原生导入 .wasm 模块的环境(默认为 false
  • lazy:使用惰性求值代理导入 .wasm 文件,以兼容不支持顶层 await 的运行时(默认为 false

工具

unwasm 提供有用的构建工具,可直接操作 .wasm 模块。

注意: unwasm/tools 子路径导出适用于或优化用于生产运行时。仅在开发和构建时依赖它。

parseWasm

使用 webassemblyjs/wasm-parser 解析 wasm 二进制格式并获取有用的信息。

import { readFile } from "node:fs/promises";
import { parseWasm } from "unwasm/tools";

const source = await readFile(new URL("./examples/sum.wasm", import.meta.url));
const parsed = parseWasm(source);
console.log(JSON.stringify(parsed, undefined, 2));

解析结果示例

{
  "modules": [
    {
      "exports": [
        {
          "id": 5,
          "name": "rand",
          "type": "Func"
        },
        {
          "id": 0,
          "name": "memory",
          "type": "Memory"
        }
      ],
      "imports": [
        {
          "module": "env",
          "name": "seed",
          "params": [],
          "returnType": "f64"
        }
      ]
    }
  ]
}

自动导入

unwasm 可以自动推断导入对象,并使用导入映射将其打包(了解更多:MDNNode.jsWICG)。

为了提示打包工具如何解析 .wasm 文件所需的导入,您需要在父级 package.json 文件中定义它们。

示例

{
  "exports": {
    "./rand.wasm": "./rand.wasm"
  },
  "imports": {
    "env": "./env.mjs"
  }
}

注意:如果您希望遵循 Node.js 约定,导入也可以以 # 为前缀,例如 #env

贡献

本地开发
  • 克隆此仓库
  • 安装最新 LTS 版本的 Node.js
  • 使用 corepack enable 启用 Corepack
  • 使用 pnpm install 安装依赖项
  • 使用 pnpm devpnpm test 运行测试

许可

根据 MIT 许可证发布。由 @pi0社区 💛 制作