WebAssembly(使用 WASI)
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 的 Hono 项目模板,但可以像其他项目一样创建 WebAssembly Hono 项目:
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 rolldownmkdir my-app
cd my-app
npm init
yarn add hono
yarn add -D @bytecodealliance/jco @bytecodealliance/componentize-js @bytecodealliance/jco-std
yarn add -D rolldownmkdir 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 rolldownmkdir 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:
npm i
npx tsc --inityarn
yarn tsc --initpnpm i
pnpm exec tsc --initbun i创建基本的 TypeScript 配置文件(tsconfig.json)后,请确保包含以下配置:
- 将
compilerOptions.module设为"nodenext"。
由于 componentize-js(以及复用它的 jco)仅支持单个 JavaScript 文件, 需要进行打包,可以使用 rolldown 创建单文件包。
可以使用以下 Rolldown 配置(rolldown.config.mjs):
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:
package example:hono;
world component {
export wasi:http/incoming-handler@0.2.6;
}简单来说,上面的 WIT 文件表示组件「提供」接收和处理传入 HTTP 请求的功能。
wasi:http/incoming-handler 接口依赖上游标准化 WIT 接口,例如请求结构的规范。
要获取这些由 Bytecode Alliance 维护的第三方 WIT 接口,可以使用 wkg:
wkg wit fetchwkg 运行结束后,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.wit3. Hello Wasm
要在 WebAssembly 中构建 HTTP 服务器,可以使用 [jco-std][jco-std] 项目。它包含辅助函数,能让开发体验与常规 Hono 开发非常接近。
在名为 src/component.ts 的文件中,使用一个作为 WebAssembly 组件的基础 Hono 应用,实现 component world:
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 编译,因此可以用它进行构建和打包:
npx rolldown -cyarn rolldown -cpnpm exec rolldown -cbun build --target=bun --outfile=dist/component.js ./src/component.ts说明
打包是必需的,因为 WebAssembly JavaScript 生态系统的工具目前只支持单个 JavaScript 文件,而我们需要包含 Hono 及相关库。
对于需求更简单的组件,无需使用打包工具。
使用 jco(间接使用 componentize-js)构建 WebAssembly 组件:
npx jco componentize -w wit -o dist/component.wasm dist/component.jsyarn jco componentize -w wit -o dist/component.wasm dist/component.jspnpm exec jco componentize -w wit -o dist/component.wasm dist/component.jsbun run jco componentize -w wit -o dist/component.wasm dist/component.js5. 运行
要运行 Hono WebAssembly HTTP 服务器,可以使用任何支持 WASI 的 WebAssembly 运行时:
wasmtimejco(在 Node.js 中运行)
本指南使用 jco serve,因为它已经安装好。
注意
jco serve 面向开发用途,不建议用于生产环境。
npx jco serve dist/component.wasmyarn jco serve dist/component.wasmpnpm exec jco serve dist/component.wasmbun run jco serve dist/component.wasm你应该会看到如下输出:
$ npx jco serve dist/component.wasm
Server listening @ localhost:8000...向 localhost:8000/hello 发送请求,会得到 Hono 应用中指定的 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 社区提出问题、发表意见、贡献代码或提交问题报告,可使用以下渠道: