wasm-packを使って作成したwasmのパッケージを利用していた時にsvelte-kitのビルドにはまったのでメモします.
svelte-kitでwasmのパッケージを読み込む
svelte-kitは内部でviteを利用しているのですが,viteでwasm-packで作成したパッケージを利用するためには
wasm-pack build --target web
のようにターゲットを指定します.--target
はwasm-packのオプション なので,featuresの指定をするときはwasm-pack build --target web -- --features console_error_panic_hook
のように前に--
を入れます.他のビルドターゲットにしたい場合もあると思いますが,viteで読み込む方法は分かりませんでした.
javascript側では普通に以下のようにimportできます.以下はwasm-bindgenでinterface(IAppOption
)とクラス(CanvasApp
)を定義した例です.
import init, {CanvasApp} from '$lib/wasm/pkg/wasm';
import type {IAppOption} from '$lib/wasm/pkg/wasm';
上ではビルドで生成したjsファイルを読み込んでいますが,$lib/wasm/pkg
のようにpkg
ディレクトリを指定することもできます.デフォルトで読み込まれるinit
は非同期関数であり,init
が完了した後にCanvasApp
が利用可能になります.具体的には
import init, {CanvasApp} from '$lib/wasm/pkg/wasm';
import type {IAppOption} from '$lib/wasm/pkg/wasm';
import {onMount} from "svelte";
onMount(async () => {
await init();
const app_opt: IAppOption = {...何かオプション};
const canvas_app = new CanvasApp(app_opt);
...何か処理
});
のように利用します.こちらはsvelte-kit dev
(npm run dev
)では問題なく動きますが,svelte-kit build
(npm run build
)では
Error: 'new URL(url, import.meta.url)' is not supported in SSR.
というエラーがでます.これはインポートしたjsファイル内のURLコンストラクタがnodeで動かないためです.
svelte-kit build が通るようにする
こちらにissueが上がっているので,紹介されているテンプレートを参考にします.以下はrustプロジェクトのディレクトリがルートから./src/lib/wasm
である場合の例です.
{
"crates_path": "./src/lib/",
"crates": [
"wasm"
]
}
と
// Temporary fix for https://github.com/vitejs/vite/issues/5169
import { readFileSync, writeFileSync } from 'fs';
const re = /[^\n]*new URL[^\n]*/g;
for(let crateName of JSON.parse(readFileSync("./.rsw.json", "utf8")).crates) {
try {
const crates_path = JSON.parse(readFileSync("./.rsw.json", "utf8")).crates_path
const fileName = crates_path + crateName + "/pkg/" + crateName + ".js";
writeFileSync(fileName, readFileSync(fileName, "utf8").replace(re, ""));
} catch {}
}
をプロジェクトのルートに用意しnode fix-new-urls
をsvelte-kit build
の前に実行します(jsファイルを変更してしまうのでtsconfigがvscode上でエラーを出します).ビルド時のエラーの該当部分を削除しています.
するとsvelte-kit build
が通るようになります.以上でビルドは成功しますが
ブラウザで
WebAssembly.instantiate(): Argument 0 must be a buffer source or a WebAssembly.Module object
というエラーが出てwasmを読み込めなくなってしまいます.そこで javascript側を以下のように変更します.
import init, {CanvasApp} from '$lib/wasm/pkg/wasm';
import type {IAppOption} from '$lib/wasm/pkg/wasm';
import wasm_path from "$lib/wasm/pkg/wasm_bg.wasm?url";
import {onMount} from "svelte";
onMount(async () => {
await init(wasm_path);
const app_opt: IAppOption = {...何かオプション};
const canvas_app = new CanvasApp(app_opt);
...何か処理
});
init
関数にwasmファイルのパスを与えるだけです.これでnpm run dev
でもnpm run build
でも動くようになります.