跳转到正文

WebAssembly(使用 WASI) ​

WebAssembly 是安全、沙盒化、可移植的运行时,可在浏览器内部和外部运行。

具体来说:

  • JavaScript 等语言编译为 WebAssembly(.wasm 文件)。
  • WebAssembly 运行时(例如 wasmtime 或 jco)允许运行 WebAssembly 二进制文件。

核心 WebAssembly 无法访问本地文件系统、套接字等功能,而 WebAssembly 系统接口 可以为 WebAssembly 工作负载定义底层平台。

这意味着,借助 WASI,WebAssembly 就能操作文件、套接字等更多资源。

说明

想亲自查看 WASI 接口吗?请参阅 wasi:http。

JavaScript 对使用 WASI 的 WebAssembly 的支持由 StarlingMonkey 提供。由于 StarlingMonkey 和 Hono 都注重 Web 标准,Hono 无需额外配置即可在支持 WASI 的 WebAssembly 生态系统中运行*。

1. 初始化 ​

WebAssembly JavaScript 生态系统提供工具,方便你开始构建支持 WASI 的 WebAssembly 组件:

  • StarlingMonkey 是 SpiderMonkey 的分支,可编译到 WebAssembly 并支持组件。
  • componentize-js 将 JavaScript ES 模块转换为 WebAssembly 组件。
  • jco 是一个多功能工具,可构建组件、生成类型,并在 Node.js 或浏览器等环境中运行组件。

说明

WebAssembly 拥有开放的生态系统并且开源,核心项目主要由 Bytecode Alliance 及其成员维护。

始终欢迎新功能、问题反馈、拉取请求及其他形式的贡献。

虽然目前还没有用于 WebAssembly 的 Hono 项目模板,但可以像其他项目一样创建 WebAssembly Hono 项目:

sh
mkdir my-app
cd my-app
npm init
npm i hono
npm i -D @bytecodealliance/jco @bytecodealliance/componentize-js @bytecodealliance/jco-std
npm i -D rolldown
sh
mkdir my-app
cd my-app
npm init
yarn add hono
yarn add -D @bytecodealliance/jco @bytecodealliance/componentize-js @bytecodealliance/jco-std
yarn add -D rolldown
sh
mkdir my-app
cd my-app
pnpm init --init-type module
pnpm add hono
pnpm add -D @bytecodealliance/jco @bytecodealliance/componentize-js @bytecodealliance/jco-std
pnpm add -D rolldown
sh
mkdir my-app
cd my-app
npm init
bun add hono
bun add -D @bytecodealliance/jco @bytecodealliance/componentize-js @bytecodealliance/jco-std

说明

要确保项目使用 ES 模块,请在 package.json 中将 type 设为 "module"。

进入 my-app 文件夹后,安装依赖并初始化 TypeScript:

sh
npm i
npx tsc --init
sh
yarn
yarn tsc --init
sh
pnpm i
pnpm exec tsc --init
sh
bun i

创建基本的 TypeScript 配置文件(tsconfig.json)后,请确保包含以下配置:

  • 将 compilerOptions.module 设为 "nodenext"。

由于 componentize-js(以及复用它的 jco)仅支持单个 JavaScript 文件, 需要进行打包,可以使用 rolldown 创建单文件包。

可以使用以下 Rolldown 配置(rolldown.config.mjs):

js
import { defineConfig } from 'rolldown'

export default defineConfig({
  input: 'src/component.ts',
  external: /wasi:.*/,
  output: {
    file: 'dist/component.js',
    format: 'esm',
  },
})

说明

也可以使用你更熟悉的其他打包工具(rolldown、esbuild、rollup 等)。

2. 配置 WIT 接口和依赖 ​

WebAssembly 接口类型(WIT) 是一种接口定义语言(IDL),用于规定 WebAssembly 组件使用的功能(导入)和提供的功能(导出)。

在标准化 WIT 接口中,wasi:http 用于处理 HTTP 请求(接收或发送)。由于要构建 Web 服务器,我们的组件必须在其 WIT world 中声明使用 wasi:http/incoming-handler:

首先,在名为 wit/component.wit 的文件中配置组件的 WIT world:

txt
package example:hono;

world component {
    export wasi:http/incoming-handler@0.2.6;
}

简单来说,上面的 WIT 文件表示组件「提供」接收和处理传入 HTTP 请求的功能。

wasi:http/incoming-handler 接口依赖上游标准化 WIT 接口,例如请求结构的规范。

要获取这些由 Bytecode Alliance 维护的第三方 WIT 接口,可以使用 wkg:

sh
wkg wit fetch

wkg 运行结束后,wit 文件夹中应包含一个新的 deps 文件夹,与 component.wit 并列:

wit
├── component.wit
└── deps
    ├── wasi-cli-0.2.6
    │   └── package.wit
    ├── wasi-clocks-0.2.6
    │   └── package.wit
    ├── wasi-http-0.2.6
    │   └── package.wit
    ├── wasi-io-0.2.6
    │   └── package.wit
    └── wasi-random-0.2.6
        └── package.wit

3. Hello Wasm ​

要在 WebAssembly 中构建 HTTP 服务器,可以使用 [jco-std][jco-std] 项目。它包含辅助函数,能让开发体验与常规 Hono 开发非常接近。

在名为 src/component.ts 的文件中,使用一个作为 WebAssembly 组件的基础 Hono 应用,实现 component world:

ts
import { Hono } from 'hono'
import { fire } from '@bytecodealliance/jco-std/wasi/0.2.6/http/adapters/hono/server'

const app = new Hono()

app.get('/hello', (c) => {
  return c.json({ message: 'Hello from WebAssembly!' })
})

fire(app)

// Although we've called `fire()` with wasi HTTP configured for use above,
// we still need to actually export the `wasi:http/incoming-handler` interface object,
// as jco and componentize-js will be looking for the ES module export that matches the WASI interface.
export { incomingHandler } from '@bytecodealliance/jco-std/wasi/0.2.6/http/adapters/hono/server'

4. 构建 ​

我们使用 Rolldown,并已配置 TypeScript 编译,因此可以用它进行构建和打包:

sh
npx rolldown -c
sh
yarn rolldown -c
sh
pnpm exec rolldown -c
sh
bun build --target=bun --outfile=dist/component.js ./src/component.ts

说明

打包是必需的,因为 WebAssembly JavaScript 生态系统的工具目前只支持单个 JavaScript 文件,而我们需要包含 Hono 及相关库。

对于需求更简单的组件,无需使用打包工具。

使用 jco(间接使用 componentize-js)构建 WebAssembly 组件:

sh
npx jco componentize -w wit -o dist/component.wasm dist/component.js
sh
yarn jco componentize -w wit -o dist/component.wasm dist/component.js
sh
pnpm exec jco componentize -w wit -o dist/component.wasm dist/component.js
sh
bun run jco componentize -w wit -o dist/component.wasm dist/component.js

5. 运行 ​

要运行 Hono WebAssembly HTTP 服务器,可以使用任何支持 WASI 的 WebAssembly 运行时:

本指南使用 jco serve,因为它已经安装好。

注意

jco serve 面向开发用途,不建议用于生产环境。

sh
npx jco serve dist/component.wasm
sh
yarn jco serve dist/component.wasm
sh
pnpm exec jco serve dist/component.wasm
sh
bun run jco serve dist/component.wasm

你应该会看到如下输出:

$ npx jco serve dist/component.wasm
Server listening @ localhost:8000...

向 localhost:8000/hello 发送请求,会得到 Hono 应用中指定的 JSON 输出。

你应该会看到如下输出:

json
{ "message": "Hello from WebAssembly!" }

说明

jco serve 将 WebAssembly 组件转换为基础的 WebAssembly 核心模块,使其能够在 Node.js 和浏览器等运行时中运行。

此过程通常通过 jco transpile 执行,让我们能够将 Node.js 和浏览器等 JavaScript 引擎环境(可能使用 V8 或其他 JavaScript 引擎)作为 WebAssembly 组件运行时使用。

jco transpile 的工作方式不在本指南范围内,可在 Jco 手册中了解更多。

更多信息 ​

要进一步了解 WASI、WebAssembly 组件等内容,请参阅以下资源:

如需向 WebAssembly 社区提出问题、发表意见、贡献代码或提交问题报告,可使用以下渠道:

基于 MIT 许可证发布。