Rust Webassembly + node/express DOM操作する例 #Rust #Webassembly #javascript #node
■ 概要:
前のRust Webassembly (下記 wasm) 関係で
機能の実践編で、
express でCRUD実装の、一部表示機能をwasm で実装する例となります。
■ 前の関連ページ
https://note.com/knaka0209/n/n0da6740b3c7c
■ 環境
Rust
rustc 1.46.0
cargo 1.46.0
wasm-pack
node 12.18.3
express
■ プロジェクト作成、ビルド
cargo generate --git https://github.com/rustwasm/wasm-pack-template
wasm-pack build --target=web
■ 実装など
・Cargo.toml
[package]
name = "wasm-crud-1"
version = "0.1.0"
authors = ["naka"]
edition = "2018"
[lib]
crate-type = ["cdylib", "rlib"]
[features]
default = ["console_error_panic_hook"]
[dependencies]
wasm-bindgen = "0.2.63"
js-sys = "0.3.44"
# The `console_error_panic_hook` crate provides better debugging of panics by
# logging them with `console.error`. This is great for development, but requires
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
# code size when deploying.
console_error_panic_hook = { version = "0.1.6", optional = true }
# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size
# compared to the default allocator's ~10K. It is slower than the default
# allocator, however.
#
# Unfortunately, `wee_alloc` requires nightly Rust when targeting wasm for now.
wee_alloc = { version = "0.4.5", optional = true }
[dependencies.web-sys]
version = "0.3.4"
features = [
'console',
'Document',
'Element',
'HtmlElement',
'Node',
'Window',
]
[dev-dependencies]
wasm-bindgen-test = "0.3.13"
[profile.release]
# Tell `rustc` to optimize for small code size.
opt-level = "s"
・Rust , lib.rs
id指定し、DOM追加します。
#[wasm_bindgen]
pub fn wasm_put_item(id_name: &str, title: &str, id_val: &str) -> Result<(), JsValue>{
let document = web_sys::window().unwrap().document().unwrap();
let entry_point = document.get_element_by_id(id_name).unwrap();
let val = document.create_element("li")?;
let s_elm = format!("<div class='div_post_wrap'>
<a href='/tasks/show/{}'>
<h3 class='h3_title'>{}</h3>
</a>
<span>ID :{}</span>
<a href='/tasks/edit/{}'> [ edit ] </a>
<hr />
</div>", id_val , title, id_val, id_val );
val.set_inner_html(&s_elm );
// console::log_1(&JsValue::from_str( &s_elm ));
val.set_inner_html(&s_elm );
entry_point.append_child(&val)?;
Ok(())
}
■ express
CRUDリストの画面
views/tasks/index.ejs
JS配列から、wasm_put_itemでDOM追加します。
<script type="module">
import init, * as wasm from '/pkg/wasm_crud_1.js';
var task_items = [];
var TaskIndex = {
get_items: async function(){
await axios.get("/api/tasks_index").then(res => {
task_items = res.data.docs
})
this.dispRow();
},
dispRow: async function(){
await init();
if(task_items instanceof Array){
// console.log(task_items );
task_items.map(function(object, index){
wasm.wasm_put_item("ul_post_wrap", String(object.title), String(object.id));
})
}
},
}
//
$(function(){
TaskIndex.get_items();
});
</script>
■ 補足、json形式で、DOM操作する方法を追加しました。2020/09/05
・Cargo.toml , serde, serde_json を追加
[dependencies]
wasm-bindgen = "0.2.63"
js-sys = "0.3.44"
serde = { version = "1.0.100", default-features = false }
serde_json = "1.0"
・lib.rs
#[wasm_bindgen]
pub fn wasm_put_json(id_name: &str, json: &str) -> Result<(), JsValue>{
let v: Value = serde_json::from_str( json ).unwrap();
let tmp_title = v["title"].to_string();
let title = tmp_title.replace('"', "");
let id_val = format!("{}", &v["id"] );
// console::log_1(&JsValue::from_str( &title ));
let document = web_sys::window().unwrap().document().unwrap();
let entry_point = document.get_element_by_id(id_name).unwrap();
let val = document.create_element("li")?;
let s_elm = format!("<div class='div_post_wrap'>
<a href='/tasks/show/{}'>
<h3 class='h3_title'>{}</h3>
</a>
<span>ID :{}</span>
<a href='/tasks/edit/{}'> [ edit ] </a>
<hr />
</div>", id_val , title, id_val, id_val );
val.set_inner_html(&s_elm );
entry_point.append_child(&val)?;
Ok(())
}
・express, wasm_put_json呼びます
dispRow:async function(){
await init();
if(task_items instanceof Array){
task_items.map(function(object, index){
var json = JSON.stringify( object );
//console.log(json );
wasm.wasm_put_json("ul_post_wrap", String(json) );
})
}
},
■ 参考のコード
・Rust コード
・express
■ 画面
一覧画面です