WebAssembly で Rust コードを JavaScript から呼び出してみました。JavaScript のMarkdown文字列をRust の Markdown パーサに渡して HTML を得て、画面上に表示するというサンプルです。
準備
※ 下記の Cloudflare Worker のコードから派生して実装したので、Cloudflare Worker 用のコードが少し混じってます。
Cloudflare Workers を Rust で使う方法です。最小限のコードで、セットアップからデプロイまで行ってみました。
wrangler, wasm-pack をインストール
cargo install wrangler wasm-pack
wrangler generate
wrangler generate wasm-markdown-parser https://github.com/cloudflare/rustwasm-worker-template/
これは Cloudflare Workers 用のテンプレートですが、WebAssembly に必要なものが全て入ってます。(同時に、Cloudflare Worker でしか使わないコードも少し入ってしまいますが)
必要最小限のコードで進める場合は、公式の Rust から WebAssembly にコンパイルする(developer.mozilla.org) に沿って進めると良さそうです。
実装
Rust側
markdown ライブラリの追加
crates/markdown(GitHub) を使ってみます。
Cargo.toml に追加します。
[dependencies]
markdown = "0.3"
cargo build
lib.rs を編集
src/lib.rs
で JavaScript から呼ぶコードを実装します。
extern crate cfg_if;
extern crate markdown; // 追加
extern crate wasm_bindgen;
...
#[wasm_bindgen]
extern "C" {
// JavaScript の console.log が Rust から呼べるように(デバッグ用)
#[wasm_bindgen(js_namespace = console)]
fn log(s: &str);
}
#[wasm_bindgen]
pub fn to_html(md_string: &str) -> String {
let html: String = markdown::to_html(&md_string);
// debug
log(&format!(
"markdown is\n {}\n\nhtml is\n{}",
&md_string, &html
));
html
}
ビルド
wasm-pack build --scope ecpplus
--scope ecpplus
とすると、 npm パッケージ化されるときにパッケージ名が @ecpplus/~
となります。作成時に名称を wasm-markdown-parser
としてるので、フルのパッケージ名は @ecpplus/wasm-markdown-parser
となります。
npm パッケージは pkg
の下に生成されます。
フロントエンド側 (JavaScript)
Rust 実装コードの呼び出し方
const js = import("./node_modules/@ecpplus/rustwasm-markdown-parser/rustwasm_markdown_parser.js");
js.then(js => {
const htmlString = js.to_html('# This is H1')
console.log(htmlString)
})
というようにして、WebAssembly 側で実装した to_html
を呼び出すことが出来ます。
HTML 上で使ってみる
フォームの入力値を to_html
に渡して画面上に表示するというのを実装してみました → https://ecpplus.net/wasm-markdown-parser/
注意点として、WebAssembly の .wasm
ファイルは、 content-type を application/wasm
にしないとブラウザ上で実行する事ができません。 Nginx なら mime.types
に下記のように定義を追加すればOKです。
application/wasm wasm;
実装したコードを GitHub で公開しています。
ecpplus/wasm-markdown-parser(GitHub)