2019
Nicolas Decoster
@ogadaki
Vue.js
éditeur de texte
collaboratif
offline first
mon use case
possibilité d'éditer même en déconnecté
resynchronisation à la reconnexion
sans centralisation
cohérence du résultat
entre tous les éditeurs connectés
mon use case
algorithme
de cohérence
interface
utilisateur
(on laisse de côté la partie communication entre éditeurs)
"WebAssembly or wasm is a new portable, size- and load-time-efficient format suitable for compilation to the web."
portable
efficient
compilation to the web
webassembly.org :
fast!
safe!
crédit: @linclark code-cartoons.com
un format binaire
moteur WebAssembly dédié dans le navigateur
interaction avec le moteur JavaScript
format WebAssembly
(module
(table 0 anyfunc)
(memory $0 1)
(export "memory" (memory $0))
(export "_Z4facti" (func $_Z4facti))
(func $_Z4facti (param $0 i32) (result f64)
(local $1 i64)
(local $2 i64)
(block $label$0
(br_if $label$0
(i32.lt_s
(get_local $0)
(i32.const 1)
)
)
(set_local $1
(i64.add
(i64.extend_s/i32
(get_local $0)
)
(i64.const 1)
)
)
(set_local $2
(i64.const 1)
)
(loop $label$1
(set_local $2
(i64.mul
(get_local $2)
(tee_local $1
(i64.add
(get_local $1)
(i64.const -1)
)
)
)
)
(br_if $label$1
(i64.gt_s
(get_local $1)
(i64.const 1)
)
)
)
(return
(f64.convert_s/i64
(get_local $2)
)
)
)
(f64.const 1)
)
)
0000000: 6100 6d73 0001 0000 0601 6001 7f01 7c01
0000010: 0203 0001 0404 7001 0000 0305 0001 0701
0000020: 0215 6d06 6d65 726f 0279 0800 5a5f 6634
0000030: 6361 6974 0000 3f0a 3d01 0201 027e 2040
0000040: 4100 4801 000d 0020 42ac 7c01 0121 0142
0000050: 0221 4003 0220 0120 7f42 227c 7e01 0221
0000060: 0120 0142 0d55 0b00 0220 0fb9 440b 0000
0000070: 0000 0000 3ff0 000b
0000000: 0061 736d # WASM_BINARY_MAGIC
0000004: 0100 0000 # WASM_BINARY_VERSION
# section "Type" (1)
0000008: 01 # section code
0000009: 00 # section size (guess)
000000a: 01 # num types
# type 0
000000b: 60 # func
000000c: 01 # num params
000000d: 7f # i32
000000e: 01 # num results
000000f: 7c # f64
0000009: 06 # FIXUP section size
# section "Function" (3)
0000010: 03 # section code
0000011: 00 # section size (guess)
0000012: 01 # num functions
0000013: 00 # function 0 signature index
0000011: 02 # FIXUP section size
# section "Table" (4)
0000014: 04 # section code
0000015: 00 # section size (guess)
0000016: 01 # num tables
# table 0
0000017: 70 # anyfunc
0000018: 00 # limits: flags
0000019: 00 # limits: initial
0000015: 04 # FIXUP section size
# section "Memory" (5)
000001a: 05 # section code
000001b: 00 # section size (guess)
000001c: 01 # num memories
# memory 0
000001d: 00 # limits: flags
000001e: 01 # limits: initial
000001b: 03 # FIXUP section size
# section "Export" (7)
000001f: 07 # section code
0000020: 00 # section size (guess)
0000021: 02 # num exports
0000022: 06 # string length
0000023: 6d65 6d6f 7279 # export name
0000029: 02 # export kind
000002a: 00 # export memory index
000002b: 08 # string length
000002c: 5f5a 3466 6163 7469 # export name
0000034: 00 # export kind
0000035: 00 # export func index
0000020: 15 # FIXUP section size
# section "Code" (10)
0000036: 0a # section code
0000037: 00 # section size (guess)
0000038: 01 # num functions
# function body 0
0000039: 00 # func body size (guess)
000003a: 01 # local decl count
000003b: 02 # local type count
000003c: 7e # i64
000003d: 02 # block
000003e: 40 # void
000003f: 20 # get_local
0000040: 00 # local index
0000041: 41 # i32.const
0000042: 01 # i32 literal
0000043: 48 # i32.lt_s
0000044: 0d # br_if
0000045: 00 # break depth
0000046: 20 # get_local
0000047: 00 # local index
0000048: ac # i64.extend_s/i32
0000049: 42 # i64.const
000004a: 01 # i64 literal
000004b: 7c # i64.add
000004c: 21 # set_local
000004d: 01 # local index
000004e: 42 # i64.const
000004f: 01 # i64 literal
0000050: 21 # set_local
0000051: 02 # local index
0000052: 03 # loop
0000053: 40 # void
0000054: 20 # get_local
0000055: 02 # local index
0000056: 20 # get_local
0000057: 01 # local index
0000058: 42 # i64.const
0000059: 7f # i64 literal
000005a: 7c # i64.add
000005b: 22 # tee_local
000005c: 01 # local index
000005d: 7e # i64.mul
000005e: 21 # set_local
000005f: 02 # local index
0000060: 20 # get_local
0000061: 01 # local index
0000062: 42 # i64.const
0000063: 01 # i64 literal
0000064: 55 # i64.gt_s
0000065: 0d # br_if
0000066: 00 # break depth
0000067: 0b # end
0000068: 20 # get_local
0000069: 02 # local index
000006a: b9 # f64.convert_s/i64
000006b: 0f # return
000006c: 0b # end
000006d: 44 # f64.const
000006e: 0000 0000 0000 f03f # f64 literal
0000076: 0b # end
0000039: 3d # FIXUP func body size
0000037: 3f # FIXUP section size
format binaire
format texte
(s-expression)
format binaire avec commentaires
WebAssembly, le langage.
(module)
(module
(func $getValue)
)
(module
(func $getValue (result i32)
i32.const 38)
)
exemple minimal
(module
(func $getValue (result i32)
i32.const 38)
)
0000000: 0061 736d # WASM_BINARY_MAGIC
0000004: 0100 0000 # WASM_BINARY_VERSION
# section "Type" (1)
0000008: 01 # section code
0000009: 05 # section size
000000a: 01 # num types
# type 0
000000b: 60 # func
000000c: 00 # num params
000000d: 01 # num results
000000e: 7f # i32
# section "Function" (3)
000000f: 03 # section code
0000010: 02 # section size
0000011: 01 # num functions
0000012: 00 # function 0 signature index
# section "Code" (10)
0000013: 0a # section code
0000014: 06 # section size
0000015: 01 # num functions
# function body 0
0000016: 04 # func body size
0000017: 00 # local decl count
0000018: 41 # i32.const
0000019: 26 # i32 literal
000001a: 0b # end
version texte func.wat
version binaire
func.wasm
exemple minimal
(module
(func $getValue (result i32)
i32.const 38)
)
(module
(func $getValue (result i32)
i32.const 38)
(export "getValue" (func $getValue))
)
exemple minimal
(module
(func $getValue (result i32)
i32.const 38)
(export "getValue" (func $getValue))
)
const binary = await fetch('./func.wasm')
38
func.wat
func.js
console
const binary = await fetch('./func.wasm')
const module = await WebAssembly.compile(binary)
const binary = await fetch('./func.wasm')
const module = await WebAssembly.compile(binary)
const instance = await WebAssembly.instantiate(module)
const binary = await fetch('./func.wasm')
const module = await WebAssembly.compile(binary)
const instance = await WebAssembly.instantiate(module)
console.log(instance.exports.getValue())
exemple minimal
func.wasm
(module
(func $add (param $a i32) (param $b i32) (result i32)
get_local $a
get_local $b
i32.add)
(export "add" (func $add))
)
const binary = await fetch('./add.wasm')
const module = await WebAssembly.compile(binary)
const instance = await WebAssembly.instantiate(module)
console.log(instance.exports.add(38, 4))
42
add.wat
add.js
console
avec paramètres
(module
(import "global" "log" (func $log (param i32)))
(func $apply (param $value i32)
(call $log (get_local $value))
)
(export "apply" (func $apply))
)
const imports = {
global: {
log: console.log
}
}
const instance = await WebAssembly.instantiate(
module, imports
)
instance.exports.apply(33)
33
console
appel d'une fonction JavaScript depuis WebAssembly
l'instance lit et écrit dans sa mémoire
instance d'un module WebAssembly
zone mémoire de l'instance
instance d'un module WebAssembly
zone mémoire de l'instance
JavaScript
mais il est également possible que JavaScript accède à cette mémoire
la mémoire de l'instance
est vue
comme un BufferArray
par JavaScript
le partage se fait par import ou par export
comme pour les fonctions
(module
(func $set (param $index i32) (param $value i32)
(i32.store8
(get_local $index)
(get_local $value)
)
)
(export "set" (func $set))
(memory (export "memory") 1)
)
// ...
const buffer = instance.exports.memory.buffer
Int8Array [ 1, 4, 7 ]
Int8Array [ 1, 8, 7 ]
console
(module
(func $set (param $index i32) (param $value i32)
(i32.store8
(get_local $index)
(get_local $value)
)
)
(export "set" (func $set))
)
// ...
const buffer = instance.exports.memory.buffer
const array = new Int8Array(buffer, 0, 3)
array.set([1, 4, 7])
console.log(array)
instance.exports.set(1, 8)
console.log(array)
// ...
const buffer = instance.exports.memory.buffer
const array = new Int8Array(buffer, 0, 3)
array.set([1, 4, 7])
// ...
const buffer = instance.exports.memory.buffer
const array = new Int8Array(buffer, 0, 3)
array.set([1, 4, 7])
instance.exports.set(1, 8)
échanges mémoire entre JavaScript et WebAssembly
(module
(import "global" "memory" (memory 1))
(func $increment (param $index i32)
(i32.store8
(get_local $index)
(i32.add
(i32.load8_s (get_local $index))
(i32.const 1)
)
)
)
(export "increment" (func $increment))
)
const imports = {
global: {
memory: new WebAssembly.Memory({ initial: 1 })
}
}
Int8Array [ 6, 3, 4 ]
Int8Array [ 6, 3, 5 ]
console
const imports = {
global: {
memory: new WebAssembly.Memory({ initial: 1 })
}
}
const buffer = imports.global.memory.buffer
const array = new Int8Array(buffer, 0, 3)
array.set([6, 3, 4])
const imports = {
global: {
memory: new WebAssembly.Memory({ initial: 1 })
}
}
const buffer = imports.global.memory.buffer
const array = new Int8Array(buffer, 0, 3)
array.set([6, 3, 4])
console.log(array)
const instance = await WebAssembly.instantiate(
module, imports
)
instance.exports.increment(2)
console.log(array)
const imports = {
global: {
memory: new WebAssembly.Memory({ initial: 1 })
}
}
const buffer = imports.global.memory.buffer
const array = new Int8Array(buffer, 0, 3)
array.set([6, 3, 4])
const instance = await WebAssembly.instantiate(
module, imports
)
const imports = {
global: {
memory: new WebAssembly.Memory({ initial: 1 })
}
}
const buffer = imports.global.memory.buffer
const array = new Int8Array(buffer, 0, 3)
array.set([6, 3, 4])
const instance = await WebAssembly.instantiate(
module, imports
)
instance.exports.increment(2)
échanges mémoire entre JavaScript et WebAssembly - alternative
moteur WebAssembly
module
instance
imports et exports
mémoire linéaire
format binaire
https://github.com/appcypher/awesome-wasm-langs
mai 2019
éditeur de texte
collaboratif
offline first
mon use case
possibilité d'éditer même en déconnecté
resynchronisation à la reconnexion
sans centralisation
cohérence du résultat
entre tous les éditeurs connectés
mon use case
Operational transformation (OT) ?
Conflict-free replicated data type (CRDT) !
arbre causal !!
"Data Laced with History:
Causal Trees & Operational CRDTs"
Alexei Baboulevitch
causal tree
interface
utilisateur
algorithme
de cohérence
Outils
Binding entre JavaScript et Rust
via WebAssembly
wasm-bindgen
Outils
Binding entre JavaScript et Rust
via WebAssembly
wasm-bindgen
présentation par Nick Fitzgerald @fitzgen :
Outils
"building, testing, and publishing Rust-generated WebAssembly"
wasm-pack
Outils
pour une intégration
dans le workflow de build
plugin wasm pour webpack
un Rust book de parcours pas à pas
de dev en Rust et WebAssembly
Tutoriel Game of Life
je veux mixer
rust + wasm + webpack + Vue.js
pour mon use case
npm init rust-webpack my_project
pour mon use case
installation de vue et des outils de build associés
npm run start
configuration de webpack et de babel
Nicolas Decoster @ogadaki