Rust を WebAssembly にコンパイルして Vite で使ってみる
はじめに
2023 年 11 月から弊社で TRPL の輪読会を週一で開催しています。そろそろ何かを動かしたい衝動に駆られたので、自分のホームページで Rust からコンパイルした WebAssembly を使ってみることにしました。
まだ「Rust 何も分からん」な筆者ですが、まるで実用性のない塊を作ってみます。
また、この記事は既に Vite のプロジェクトと Rust を利用できる前提で書いています。
Rust から WebAssembly にコンパイル
実は MDN にすごく分かりやすいチュートリアルがあります。
なので MDN を見てください。一応、長い文章を見たくない人のために簡単にやったことを書きます。
WebAssembly にコンパイルしたり、npm ライブラリとして公開する機能を提供してくれる wasm-pack をインストールします。
cargo install wasm-pack
次に Rust のコードを置くディレクトリを作成します。
mkdir packages
移動して cargo new をします。
cargo new --lib wasm-kazuhe-github-io
Cargo.toml
と src/lib.rs
が作成されるので、チュートリアルに従って JavaScript から window.alert
を受け取り、greet 関数の中で実行するだけの極めて単純なファイルを作ります。
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
pub fn alert(s: &str);
}
#[wasm_bindgen]
pub fn greet(name: &str) {
alert(&format!("Hello, {}!", name));
}
wasm-bindgen の依存の追加とその他設定を Cargo.toml
に追記します。
[package]
name = "wasm-kazuhe-github-io"
version = "0.1.0"
authors = ["Ohara Kazuhiro"]
description = "WebAssembly package for my website."
repository = "https://github.com/kazuhe/kazuhe.github.io"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2.84"
npm ライブラリとして公開するために wasm-pack でコンパイルを実行します。
wasm-pack build packages --target bundler
これで packages/pkg
に package.json
や .wasm
ファイル、型定義ファイル (.d.ts
) が生成され、WebAssembly の npm ライブラリができました。
WebAssembly の npm ライブラリを公開
npm のアカウントが必要なので、なければ作成しログインします。その後 publish コマンドを実行するだけで簡単に公開ができます。
(私以外使わないのに、わざわざ npm ライブラリとして公開するのも大袈裟ですが練習として公開してみました)
wasm-pack login
wasm-pack publish
これで npm ライブラリを使う準備ができました。
Vite プロジェクトからの利用
普通の npm ライブラリをインストールするのと同じようにインストールします。
pnpm i -E wasm-kazuhe-github-io
Rust で定義した greet 関数をインポートして実行します。
import { greet } from "wasm-kazuhe-github-io";
greet("wasm");
生成された npm ライブラリには型定義ファイルも含まれているので、もちろん型の補完も効きます。
index.html
に TypeScript ファイルを読み込みます。
<body>
<!-- ~~ -->
<script type="module" src="/src/index.ts"></script>
</body>
現時点では、このままの状態だと WebAssembly が ESM と統合されていないため動作しません。ただ、ESM 統合の提案があり、将来的には動作することが期待されているようです。
なので、vite-plugin-wasm を追加します。
まだ top-level await がサポートされていないブラウザもあるようなので、ついでに vite-plugin-top-level-await も追加します。
vite.config.ts
を以下のように書きます。
import { defineConfig } from "vite";
import wasm from "vite-plugin-wasm";
import topLevelAwait from "vite-plugin-top-level-await";
export default defineConfig({
plugins: [wasm(), topLevelAwait()],
});
これを GitHub Pages にデプロイしてみると..
.wasm
ファイルが読み込まれて window.alert
が実行されていることを確認できました。
さいごに
今の状態では、まるで実用性のない機能ですが 簡単に WebAssembly を試すことができました。
Discussion