はじめに
Vue CLI + Vue Router + Vuetifyで構築したSPAでWebAssembly(以下Wasm)を使おうとして,少し詰まったのでメモしておきます.
Hello Wasm
Wasm事始めということで,こちらの記事にある,Wasmのサンプルを動かそうとしました.
qiita.com
下記のリポジトリでHTMLコードとWasmバイナリが公開されています.
github.com
このリポジトリからindex.htmlとsample.wasmをダウンロードして,プロジェクト内の public/ 配下にこれらのファイルを置きます(下図).
(簡単のため,下記レポジトリ内の index.hrml は count.html,sample.wasmはcount.wasmとリネームしました.)
public/
├ count.html
└ count.wasmその後 yarn serve して,ブラウザからlocalhost:8080/count.html にアクセスすると,期待通りの画面が表示され,正常に動作します.
謎のコンパイルエラー
さて,HTML + Wasmの動作を確認できたので,次はVueに移植していきます.
ディレクトリ構想は下図のようにしました.
src/
└ views/
└ count/
├ count.vue
└ count.wasmcount.vueは先ほどのcount.htmlをVueに移植したもので,次のようにしました.
- count.vue
<template>
<v-app id>
<v-content>
<v-content>
<v-row justify="space-around" no-gutters>
<h1>wasm-count</h1>
</v-row>
<v-row justify="space-around" no-gutters>
<v-btn id="countup">count</v-btn>
<h1>{{ data.val }}</h1>
</v-row>
</v-content>
</v-content>
</v-app>
</template>
<script>
const wasm_file_path = "count.wasm";
export default {
data: () => ({
data: {
val: "-"
}
}),
methods: {
main(data) {
console.log("file: " + wasm_file_path);
fetch(wasm_file_path)
.then(function(response) {
return response.arrayBuffer();
})
.then(function(buffer) {
return WebAssembly.compile(buffer);
})
.then(function(module) {
return WebAssembly.instantiate(module);
})
.then(function(instance) {
document.getElementById("countup").addEventListener(
"click",
function() {
data.val = instance.exports.count();
},
false
);
});
}
},
mounted() {
this.main(this.data);
}
};
</script>細かい処理は置いておいて,wasm_file_path で指定したWasmバイナリを fetch で取ってきて処理する,というのが大まかな流れです.
Vue Routerで /wasm/count でアクセスできるように設定したうえで,yarn serveをして,ブラウザで localhost:8080/#/wasm/count にアクセスします.
すると,次のようなエラーが表示されました.
Uncaught (in promise) CompileError: WebAssembly.compile(): expected magic word 00 61 73 6d, found 3c 21 44 4f @+0
「Wasmバイナリの先頭には 00 61 73 6d というマジックナンバーがあるはずなのに,指定されたファイルの先頭は 3c 21 44 4f ですよ」というエラーが表示されている.
さっきはちゃんと動いたバイナリなのに何故??と思い,バイナリエディタで確認してみると当該ファイルの先頭はしっかり「00 61 73 6d」となっていました.
ぐぬぬと思いつつ,localhost固有の原因かもしれないと思い,Github Pagesにデプロイしてみました.
ページにアクセスすると,今度は以下のようなエラーが表示されました.
また,次のissueも発見しました.
github.com
先ほどの
Uncaught (in promise) CompileError: WebAssembly.compile(): expected magic word 00 61 73 6d, found 3c 21 44 4f @+0
というエラーが話題に上がっています.
Q. なんかこんなエラー出たんだけど.
A. 「3c 21 44 4f」ってASCIIで読んだら「<!DO」じゃん.多分404ページかなんかを読んでるよ,それ.
なるほど!!!
fetch(wasm_file_path)をした際に,404ページが返ってきて,HTMLの1行目「<!DOCTYPE html>」を読み込み,上記のエラーが出現したようです.
解決
要はHTTPでcount.wasmにアクセスできるようにしてやればいいわけですね.
解決法は他にもあるかもしれませんが,今回は public/ 配下にWasmバイナリを配置することで解決しました.
public/
└ wasm/
└ count.wasmこれに伴って,Vueファイルでは
const wasm_file_path = "wasm/count.wasm";
とファイル名を定めることにしました.
ということで,無事にVue製SPA内でWasmを動かすことができました!
これは https://w-haibara.github.io/wasm/count で確認することができます.
おわりに
意外なところで詰まってしまいましたが,なんとかWasmを動かせました.
これでVue.js + Wasmで遊べます.