🍱

vite-plugin-singlefileでwasmを単一HTMLに埋め込む

に公開

備忘録メモ

どうしてもネットから隔離されたローカル環境の某RADソフトウェアでwasmを動作させたかったため、単一HTMLにRustで作ったwasmを埋め込めるか試してみました。

単一HTMLを某RADソフトウェア内に埋め込んでwasmがWebビューで動作することを確認しました。

Viteで新規プロジェクト

今回はViteで新規プロジェクトを立ち上げてみます。

$ npm create vite@latest my-wasm-app -- --template vanilla-ts

$ cd my-wasm-app
$ npm install

publicディレクトリは使わないので削除(状況に応じて残すかを決めてください)
srcディレクトリもサンプルコードが入っているので一旦削除し、空のmain.tsファイルを作ります。

$ rm -r public

$ rm -r src
$ mkdir src
$ touch src/main.ts

wasmのためにRustのコードを追加

プロジェクトディレクトリ内でRustでwasmのコードを書くためにcargo newします。

$ cargo new --lib wasm

Cargo.tomlを編集してcrate-type = ["cdylib"]を追加したり、dependenciesにwasm-bindgen = "0.2"を追加しています。
このあたりはcargo add wasm-bindgenしてもいいかもしれません。

wasm/Cargo.toml
[package]
name = "wasm"
version = "0.1.0"
edition = "2024"

[lib]
crate-type = ["cdylib"]

[dependencies]
wasm-bindgen = "0.2"

足し算ができる関数add()をTypeScript側に公開しておきます。

wasm/src/lib.rs
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn add(left: u64, right: u64) -> u64 {
    left + right
}

wasm-packをインストールし、一旦ビルドします。

$ npm i -D wasm-pack
$ npx wasm-pack build ./wasm --target web

これでwasm/pkgディレクトリができました。

TypeScriptのコードを追加

src/main.ts
import init, { add } from '../wasm/pkg';

init().then(() => {
  alert(add(1n, 2n));
});
index.html
<!doctype html>
<html lang="ja">
  <head>
    <meta charset="utf-8" />
    <title>my-wasm-app</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>

動作確認のためviteを立ち上げ

$ npm run dev

ブラウザでhttp://localhost:5173/を開いてアラートダイアログで3と表示されていればOK

確認が終わったらControl+Cで終了します。

vite-plugin-singlefileを導入

$ npm i -D vite-plugin-singlefile
vite.config.ts
import { defineConfig } from 'vite';
import { viteSingleFile } from 'vite-plugin-singlefile';

export default defineConfig({
  plugins: [viteSingleFile()],
});
$ npm run build

buildするとdist/index.htmlに単一のHTMLファイルとして出力されます。index.htmlをブラウザにドラッグ&ドラップすると動作を確認できます。

package.jsonを編集してnpm run buildwasm-pack build ./wasm/ --target webを仕込んでもいいかもしれません。

package.json
 {
   "name": "my-wasm-app",
   "private": true,
   "version": "0.0.0",
   "type": "module",
   "scripts": {
     "dev": "vite",
-    "build": "tsc && vite build",
+    "build": "wasm-pack build ./wasm/ --target web && tsc && vite build",
     "preview": "vite preview"
   },
   "devDependencies": {
     "typescript": "~5.8.3",
     "vite": "^6.3.5",
     "vite-plugin-singlefile": "^2.2.0",
     "wasm-pack": "^0.13.1"
   }
 }

以上です。

Discussion