Rust + WebAssemblyで広がるWebの未来

0fa1c2ed2eb4a18ddec3dd70cb1f72db?s=47 Yosuke Onoue
November 24, 2018

Rust + WebAssemblyで広がるWebの未来

FRONTEND CONFERENCE 2018(https://2018.kfug.jp/)の登壇資料です

0fa1c2ed2eb4a18ddec3dd70cb1f72db?s=128

Yosuke Onoue

November 24, 2018
Tweet

Transcript

  1. 2.

    ࣗݾ঺հ w ඌ্༸հ :PTVLF0OPVF  w ೔ຊେֶจཧֶ෦৘ใՊֶՊॿڭ w OHLZPUPΦʔΨφΠβʔ w

    ৘ใՄࢹԽɺ਺ཧ࠷దԽɺҙࢥܾఆࢧԉͷݚڀ w ՄࢹԽγεςϜͷ։ൃʹ8FCϑϩϯτΤϯυٕज़Λ࢖༻
  2. 13.

    &NTDSJQUFO w IUUQFNTDSJQUFOPSH w $$ UPBTNKT8FC"TTFNCMZίϯύΠϥ w .P[JMMB͕த৺Ͱ։ൃ w --7.ϕʔε

    w MJCDɺMJCD ʢ Ћʣͷޓ׵ϨΠϠʔ w ϑΝΠϧγεςϜɺ$(ɺήʔϜΤϯδϯɺFUD
  3. 14.

    (FUUJOH4UBSUFEXJUI&NTDSJQUFO $ emcc -s EXTRA_EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]' \
 -s EXPORTED_FUNCTIONS='["_twice"]' \

    -s MODULARIZE=1 -s -o example.js example.c $ node main.js 4.4 1 double twice(double value) { 2 return value * 2; 3 } FYBNQMFD 1 const wasm = require('./example') 2 3 wasm().then((Module) => { 4 const twice = Module.cwrap('twice', 'number', ['number']) 5 console.log(twice(2.2)) 6 }) NBJOKT
  4. 15.

    $$ ʁ w ϝϦοτ w ߴ଎ w ௿ϨΠϠʔͷૢ࡞ w աڈͷࢿ࢈ͷ׆༻

    w σϝϦοτ w ҆શੑ w पลπʔϧͷෆࡏ #FUUFS$ ͱͯ͠ͷ3VTU
  5. 17.

    4FUVQ $ curl https://sh.rustup.rs -sSf | sh $ source ~/.cargo/env

    $ rustup default nightly $ rustup target add wasm32-unknown-unknown
  6. 18.

    Ϗϧυ $ cargo new --lib example $ cd example $

    cargo build --target wasm32-unknown-unknown 1 [package] 2 name = "example" 3 version = "0.1.0" 4 authors = ["Yosuke Onoue <onoue@likr-lab.com>"] 5 6 [dependencies] 7 8 [lib] 9 crate-type = ["cdylib"] $BSHPUPNM 1 #[no_mangle] 2 pub fn twice(value: f64) -> f64 { 3 value * 2.0 4 } TSDMJCST
  7. 19.

    ࣮ߦ 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta

    charset="utf-8"/> 5 <title>Rust + WebAssembly Example</title> 6 </head> 7 <body> 8 <script> 9 fetch('./target/wasm32-unknown-unknown/debug/example.wasm') 10 .then((response) => response.arrayBuffer()) 11 .then((buffer) => WebAssembly.instantiate(buffer)) 12 .then(({ instance }) => { 13 const { twice } = instance.exports 14 console.log(twice(2.2)) 15 }) 16 </script> 17 </body> 18 </html> JOEFYIUNM
  8. 20.

    8FC"TTFNCMZ+4"1* w XBTNϑΝΠϧΛಡΈࠐΜͰ8FC"TTFNCMZJOTUBOUJBUF ʹ౉͢ w "SSBZ#V⒎FSΛ௨ͨ͡௿ϨΠϠʔͳૢ࡞ w /VNCFSʢ਺஋ɺϙΠϯλʣɺ5ZQFE"SSBZΛ
 ѻ͏ؔ਺ͷݺͼग़͠ͷΈ 9

    fetch('./target/wasm32-unknown-unknown/debug/example.wasm') 10 .then((response) => response.arrayBuffer()) 11 .then((buffer) => WebAssembly.instantiate(buffer)) 12 .then(({ instance }) => { 13 const { twice } = instance.exports 14 console.log(twice(2.2)) 15 })
  9. 22.

    Ϗϧυ 1 extern crate wasm_bindgen; 2 3 use wasm_bindgen::prelude::*; 4

    5 #[wasm_bindgen] 6 pub fn twice(value: f64) -> f64 { 7 value * 2.0 8 } TSDMJCST 1 [package] 2 name = "bindgen-example" 3 version = "0.1.0" 4 authors = ["Yosuke Onoue <onoue@likr-lab.com>"] 5 edition = "2018" 6 7 [dependencies] 8 wasm-bindgen = "0.2" 9 10 [lib] 11 crate-type = ["cdylib"] $BSHPUPNM $ wasm-bindgen --out-dir . target/wasm32-unknown-unknown/debug/bindgen_example.wasm
  10. 23.

    ࣮ߦ 1 import('./bindgen_example').then(({ twice }) => { 2 console.log(twice(2.2)) 3

    }) JOEFYKT 1 const path = require('path') 2 3 module.exports = { 4 entry: './index.js', 5 output: { 6 path: path.resolve(__dirname), 7 filename: 'bundle.js' 8 } 9 } XFCQBDLDPOpHKT 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"/> 5 <title>wasm-bindgen Example</title> 6 </head> 7 <body> 8 <script src="bundle.js"></script> 9 </body> 10 </html> JOEFYIUNM
  11. 24.

    ଞʹͰ͖Δ͜ͱ 15 #[wasm_bindgen] 16 pub struct Screen { 17 bytes:

    Vec<u8>, 18 #[wasm_bindgen(readonly)] 19 pub width: usize, 20 #[wasm_bindgen(readonly)] 21 pub height: usize, 22 } 23 24 #[wasm_bindgen] 25 impl Screen { 26 #[wasm_bindgen(constructor)] 27 pub fn new(width: usize, height: usize) -> Screen { 28 Screen { 29 bytes: create_buffer(width, height), 30 width, 31 height, 32 } 33 } 34 42 43 pub fn resize(&mut self, width: usize, height: usize) { 44 self.bytes = create_buffer(width, height); 45 self.width = width; 46 self.height = height; 47 } 48 }
  12. 25.

    +BWB4DSJQUΫϥεͷੜ੒ w 3VTUͷߏ଄ମɺUSBJU͔Β+BWB4DSJQUΫϥεΛੜ੒ 1 const mod = import('mandelbrot') 2 const

    bg = import('mandelbrot/mandelbrot_bg') 3 Promise.all([mod, bg]).then(([{ mandelbrot, Screen }, { memory }]) => { 4 const canvas = this.display.nativeElement; 5 const screen = new Screen(canvas.width, canvas.height); 6 7 const bytes = new Uint8ClampedArray(memory.buffer, screen.pointer(), screen.size()); 8 const image = new ImageData(bytes, screen.width, screen.height); 9 mandelbrot(screen, -3, -2, 0.01, 100); 10 11 const ctx = canvas.getContext('2d'); 12 ctx.putImageData(image, 0, 0); 13 })