WebAssembly 準備
用意するもの
The Rust Toolchain
- rustup
- rustc
- cargo
wasm-pack
ビルド、テスト、WebAssemblyの生成のためのワンストップショップ
https://rustwasm.github.io/wasm-pack/installer/
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
cargo-generate
gitリポジトリにあるテンプレートから Rustプロジェクトを生成する
インストール
cargo install cargo-generate
使い方
WebAssembly サンプルプロジェクトの生成
cargo generate --git https://github.com/rustwasm/wasm-pack-template
npm
サーバーサイド。
生成した .wasm
を npmレジストリーに公開する。
npm install npm@latest -g
wasmのロード
Node.js ビルド版
index.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Hello wasm-pack!</title> </head> <body> <noscript>This page contains webassembly and javascript content, please enable javascript in your browser.</noscript> <script src="./bootstrap.js"></script> </body> </html>
bootstrap.js
// A dependency graph that contains any wasm must all be imported // asynchronously. This `bootstrap.js` file does the single async import, so // that no one else needs to worry about it again. import("./index.js") .catch(e => console.error("Error importing `index.js`:", e));
wasm-pack build
--target
を付けなければ、 webpack対応版が作られる。
index.js
// hello-wasm-pack側でwasmがロードされている import * as wasm from "hello-wasm-pack"; wasm.greet();
hello-wasm-pack.js
import * as wasm from "./hello-wasm-pack_bg.wasm"; export * from "./hello-wasm-pack_bg.js";
web版
wasm-pack build --target web
index.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Hello wasm-pack!</title> </head> <body> <noscript>This page contains webassembly and javascript content, please enable javascript in your browser.</noscript> <script type="module" src="./index.js"></script> </body> </html>
<html> <head> <meta content="text/html;charset=utf-8" http-equiv="Content-Type"/> </head> <body> <!-- Note the usage of `type=module` here as this is an ES6 module --> <script type="module"> // Use ES module import syntax to import functionality from the module // that we have compiled. // // Note that the `default` import is an initialization function which // will "boot" the module and make it ready to use. Currently browsers // don't support natively imported WebAssembly as an ES module, but // eventually the manual initialization won't be required! import init, { add } from './pkg/without_a_bundler.js'; async function run() { // First up we need to actually load the wasm file, so we use the // default export to inform it where the wasm file is located on the // server, and then we wait on the returned promise to wait for the // wasm to be loaded. // // It may look like this: `await init('./pkg/without_a_bundler_bg.wasm');`, // but there is also a handy default inside `init` function, which uses // `import.meta` to locate the wasm file relatively to js file. // // Note that instead of a string you can also pass in any of the // following things: // // * `WebAssembly.Module` // // * `ArrayBuffer` // // * `Response` // // * `Promise` which returns any of the above, e.g. `fetch("./path/to/wasm")` // // This gives you complete control over how the module is loaded // and compiled. // // Also note that the promise, when resolved, yields the wasm module's // exports which is the same as importing the `*_bg` module in other // modes await init(); // And afterwards we can use all the functionality defined in wasm. const result = add(1, 2); console.log(`1 + 2 = ${result}`); if (result !== 3) throw new Error("wasm addition doesn't work!"); } run(); </script> </body> </html>
type=moduleでない方式
<html> <head> <meta content="text/html;charset=utf-8" http-equiv="Content-Type"/> </head> <body> <!-- Include the JS generated by `wasm-pack build` --> <script src='pkg/without_a_bundler_no_modules.js'></script> <script> // Like with the `--target web` output the exports are immediately // available but they won't work until we initialize the module. Unlike // `--target web`, however, the globals are all stored on a // `wasm_bindgen` global. The global itself is the initialization // function and then the properties of the global are all the exported // functions. // // Note that the name `wasm_bindgen` can be configured with the // `--no-modules-global` CLI flag const { add } = wasm_bindgen; async function run() { await wasm_bindgen('./pkg/without_a_bundler_no_modules_bg.wasm'); const result = add(1, 2); console.log(`1 + 2 = ${result}`); } run(); </script> </body> </html>
index.js
import * as wasm from "./pkg/bindgen_sample.js"; wasm.default().then((module) => { module.greet("Tanaka") })
hello-wasm-pack.js
// 省略 async function init(input) { if (typeof input === 'undefined') { input = import.meta.url.replace(/\.js$/, '_bg.wasm'); } const imports = {}; imports.wbg = {}; imports.wbg.__wbg_alert_83023aa40c1985f5 = function(arg0, arg1) { alert(getStringFromWasm0(arg0, arg1)); }; if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) { input = fetch(input); } const { instance, module } = await load(await input, imports); wasm = instance.exports; init.__wbindgen_wasm_module = module; return wasm; } // wasmが取得できる export default init;