概要
WebAssemblyを使用して、HTMLのDOMを操作することを目的とします。
メモベースで書いていきます。
まずはプロジェクト作成
cargo new
でライブラリのテンプレートを作成します。
$ cargo new --lib dom
Cargo.tomlに追記
多言語からもビルド後のライブラリを触れるようにするために、 carte-type
にcdylib
を設定します。
[lib]
crate-type = ["cdylib"]
WebAssemblyとJavaScript間でデータの受け渡しができるように、wasm-bindgen
をインストールします。
[dependencies]
wasm-bindgen = "0.2.83"
ビルドを高速にするためにweb-sysのAPIを制限しているっぽいです。なので、dependencies.web-sys
にfeatures
としてリストする必要があります。
To keep build times super speedy, web-sys gates each Web interface behind a cargo feature. Find the type or method you want to use in the API documentation; it will list the features that must be enabled to access that API.
以下のような感じ
[dependencies.web-sys]
version = "0.3.4"
features = [
'Document',
'Element',
'HtmlElement',
'Node',
'Window',
]
他のAPIを追加したい場合は以下を参照して探すと良さそうです。
Rustのコード
use wasm_bindgen::prelude::*;
#[wasm_bindgen(start)]
pub fn run() -> Result<(), JsValue> {
// Use `web_sys`'s global `window` function to get a handle on the global
// window object.
let window = web_sys::window().expect("no global `window` exists");
let document = window.document().expect("should have a document on window");
let body = document.body().expect("document should have a body");
// Manufacture the element we're gonna append
let val = document.create_element("p")?;
val.set_text_content(Some("Hello from Rust!"));
body.append_child(&val)?;
Ok(())
}
expectは実行の失敗時に表示される文字列を引数とするメソッドです。
document.create_element
で p
タグを作成し、Hello from Rust!
をセットしています。
val.set_text_contentの引数で使用しているSome(T)
は何かしらの型を1つ持った、匿名タプル構造体型です。
コード的には意外とJavaScriptでの書き方に似ているのでわかりやすいですね。
JavaScriptのプロジェクトを作成
webpack-dev-serverで起動するための準備をします。
{
"scripts": {
"build": "webpack",
"serve" : "webpack serve"
},
"devDependencies": {
"@wasm-tool/wasm-pack-plugin": "1.5.0",
"text-encoding": "^0.7.0",
"html-webpack-plugin": "^5.3.2",
"webpack": "^5.49.0",
"webpack-cli": "^4.7.2",
"webpack-dev-server": "^3.11.2"
}
}
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const WasmPackPlugin = require("@wasm-tool/wasm-pack-plugin");
module.exports = {
entry: './index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.js',
},
plugins: [
new HtmlWebpackPlugin({
template: 'index.html'
}),
new WasmPackPlugin({
crateDirectory: path.resolve(__dirname, ".")
}),
// Have this example work in Edge which doesn't ship `TextEncoder` or
// `TextDecoder` at this time.
new webpack.ProvidePlugin({
TextDecoder: ['text-encoding', 'TextDecoder'],
TextEncoder: ['text-encoding', 'TextEncoder']
})
],
mode: 'development',
experiments: {
asyncWebAssembly: true
}
};
HtmlWebpackPlugin
HtmlWebpackPluginは、バンドルしたjsファイルをsourceにしたscriptタグを挿入してくれます。
WasmPackPlugin
WasmPackPluginは、Rustで書かれたlibテンプレートをpkgディレクトリにビルドしてくれる設定してくれます。
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
</head>
<body>
</body>
</html>
import('./pkg')
.catch(console.error);
これで準備が整いました。
起動
npm run serve
でwebpack-dev-serverを起動します。
localhost:8080にアクセスするとtemplateのindex.htmlに対してrustで書いたwasm用のコードのp
タグのappendがされて Hello from Rust!
という表示がでました。