WebAssembly(WASI を使用)
WebAssembly は、安全でサンドボックス化されたポータブルなランタイムで、Web ブラウザーの内外で動作します。
具体的には、次のように使います。
- JavaScript などの言語を WebAssembly(
.wasmファイル)にコンパイルします。 wasmtimeやjcoなどの WebAssembly ランタイムで、WebAssembly バイナリを実行できます。
WebAssembly のコア自体は、ローカルファイルシステムやソケットなどにアクセスできませんが、WebAssembly System Interface が 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 を使うスターターテンプレートはまだありませんが、他のプロジェクトと同様に開始できます。
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 Interface Types(WIT) は、WebAssembly コンポーネントが使う機能(インポート)と提供する機能(エクスポート)を定めるインターフェース定義言語(IDL)です。
標準化された 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 フォルダー内の component.wit と同じ階層に、新しい deps フォルダーが作成されます。
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 というファイルで、基本的な Hono アプリケーションを WebAssembly コンポーネントとして作成し、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 やブラウザーなど(V8 などの JavaScript エンジンを使う)の環境を WebAssembly コンポーネントのランタイムとして利用できます。
jco transpile の仕組みはこのガイドの範囲外です。詳しくは Jco ブックを参照してください。
詳細情報
WASI や WebAssembly コンポーネントなどについて詳しく知るには、次の資料を参照してください。
- Bytecode Alliance コンポーネントモデルのブック
jcoのコードベースjcoコンポーネントの例(特に Hono の例)
- Jco ブック
componentize-jsのコードベース- StarlingMonkey のコードベース
WebAssembly コミュニティへの質問、コメント、貢献、問題報告には、次を利用できます。