mbasso / asm-dom
- понедельник, 22 мая 2017 г. в 03:12:10
JavaScript
A minimal WebAssembly virtual DOM focused on performance
A minimal WebAssembly virtual DOM focused on performance
You can install asm-dom using npm:
npm install --save asm-dom
If you are using this library with webpack you also need to install arraybuffer-loader
:
npm install --save-dev arraybuffer-loader
and add this object to your loaders:
{
test: /\.wasm$/,
loaders: ['arraybuffer-loader'],
}
also, if you have some problems with fs, you can add this to your webpack config:
node: {
fs: 'empty',
},
asm-dom is a minimal WebAssembly virtual DOM focused on performance. It is born from the idea to test the powerful of WebAssembly in a common use case that is not gaming, VR, AR or Image / video editing. Unfortunately, at the moment, GC / DOM / Web API Integration is a future feature
import init from 'asm-dom';
const asmDom = await init();
// or init().then(asmDom => { ... });
const { h, patch } = asmDom;
const root = document.getElementById('root');
const vnode = h('div', {
raw: { onclick: () => console.log('clicked') }
}, [
h('span', { style: 'font-weight: bold' }, 'This is bold'),
' and this is just normal text',
h('a', { href: '/foo' }, 'I\'ll take you places!')
]);
// Patch into empty DOM element – this modifies the DOM as a side effect
patch(root, vnode);
const newVnode = h('div', {
raw: { onclick: () => console.log('another click') }
}, [
h('span', { style: 'font-weight: normal; font-style: italic' }, 'This is now italic type'),
' and this is just normal text',
h('a', { href: '/bar' }, 'I\'ll take you places!')
]);
// Second `patch` invocation
patch(vnode, newVnode); // asm-dom efficiently updates the old view to the new state
Examples are available in the examples folder.
Also, here is the list of the online Demos:
By default asm-dom returns an init
function that takes an optional configuration object. This represents the Module object passed to emscripten with 3 additional props:
useWasm
: true
if you want to force the usage of WebAssemblyuseAsmJS
: true
if you want to force the usage of asm.jsclearMemory
: true
by default, set it to false
if you want to free memory manually, for more information see deleteVNode.By default asm-dom uses WebAssembly if supported, otherwise asm.js
Please note that this function creates the module only the first time that is called, the next times returns a Promise that resolve with the same, cached object.
import init from 'asm-dom';
// init returns a Promise
const asmDom = await init();
// const asmDom = await init({ useAsmJS: true });
// init().then(asmDom => { ... });
You can create vnodes using h
function. h
accepts a tag/selector as a string, an optional data object and an optional string or array of children. The data object contains all attributes and a special raw
prop that can contains callbacks and raw values applied to the DOM element with the dot notation. You should also put in raw
properties like value
or checked
. This returns the memory address of your virtual node.
const { h } = asmDom;
const vnode = h('div', { style: 'color: #000' }, [
h('h1', 'Headline'),
h('p', 'A paragraph'),
]);
const vnode2 = h('div', {
id: 'an-id', // node.setAttribute('id', 'an-id')
className: 'foo', // className is a special attribute evaluated as 'class'
'data-foo': 'bar', // a dataset attribute
raw: {
onclick: (e) => console.log('clicked: ', e.target),
foo: 'bar', // raw value: node.foo = 'bar'
},
});
The patch
takes two arguments, the first is a DOM element or a vnode representing the current view. The second is a vnode representing the new, updated view. If patch
succedeed, the new vnode (the second parameter) is returned.
If a DOM element is passed, newVnode
will be turned into a DOM node, and the passed element will be replaced by the created DOM node. If an oldVnode
is passed, asm-dom will efficiently modify it to match the description in the new vnode.
Any old vnode passed must be the resulting vnode from the previous call to patch. Otherwise, no operation is performed and undefined is returned.
const { h, patch } = asmDom;
const oldVnode = h('span', 'old node');
const newVnode = h('span', 'new node');
patch(document.getElementById('root'), oldVnode);
patch(oldVnode, newVnode);
As we said before the h
returns a memory address. This means that this memory have to be deleted manually, as we have to do in C++ for example. By default asm-dom automatically delete the old vnode from memory when patch
is called. However, if you want to create a vnode that is not patched, or if you want to manually manage this aspect (setting clearMemory: false
in the init
function), you have to delete it manually. For this reason we have developed a function that allows you to delete a given vnode and all its children recursively:
const vnode1 = h('div');
const vnode2 = h('div', [
h('span',)
]);
patch(vnode1, vnode2); // vnode1 automatically deleted
const child1 = h('span', 'child 1');
const child2 = h('span', 'child 2');
const vnode = h('span', [
child1,
child2,
]);
deleteVNode(vnode); // manually delete vnode, child1 and child2 from memory
Here is a list of things that have to be done to complete this project:
At the moment we haven't Benchmarks to show, but they'll come soon! Consider that benchmarking this library is not easy, we have to reproduce real world situations with big vnodes trees and frequent updates. Run a single patch or a sequence of patch in a for-loop might produce results that are not attributable to a real application.
asm-dom aims to be even more powerful with GC / DOM / Web API Integration. Unfortunately this is a future feature
This project adheres to Semantic Versioning.
Every release, along with the migration instructions, is documented on the Github Releases page.
Matteo Basso
Copyright for portions of project asm-dom are held by Simon Friis Vindum, 2015 as part of project snabbdom. All other copyright for project asm-dom are held by Matteo Basso.
Copyright (c) 2016, Matteo Basso.
asm-dom source code is licensed under the MIT License.