Skip to content

Instantly share code, notes, and snippets.

@OliverJAsh
Created February 7, 2016 16:40
Show Gist options
  • Save OliverJAsh/edd12600366132da9a8d to your computer and use it in GitHub Desktop.
Save OliverJAsh/edd12600366132da9a8d to your computer and use it in GitHub Desktop.
Using virtual DOM for progressive enhancement
System.config({
baseURL: "/",
defaultJSExtensions: true,
transpiler: "babel",
babelOptions: {
"optional": [
"runtime",
"optimisation.modules.system"
]
},
paths: {
"github:*": "jspm_packages/github/*",
"npm:*": "jspm_packages/npm/*"
},
map: {
"babel": "npm:babel-core@5.8.35",
"babel-runtime": "npm:babel-runtime@5.8.35",
"core-js": "npm:core-js@1.2.6",
"redux": "npm:redux@3.3.1",
"udc": "npm:udc@1.0.1",
"vdom-virtualize": "npm:vdom-virtualize@1.0.5",
"virtual-dom": "npm:virtual-dom@2.1.1",
"vtree-select": "npm:vtree-select@2.0.0",
"github:jspm/nodelibs-assert@0.1.0": {
"assert": "npm:assert@1.3.0"
},
"github:jspm/nodelibs-buffer@0.1.0": {
"buffer": "npm:buffer@3.6.0"
},
"github:jspm/nodelibs-events@0.1.1": {
"events": "npm:events@1.0.2"
},
"github:jspm/nodelibs-path@0.1.0": {
"path-browserify": "npm:path-browserify@0.0.0"
},
"github:jspm/nodelibs-process@0.1.2": {
"process": "npm:process@0.11.2"
},
"github:jspm/nodelibs-stream@0.1.0": {
"stream-browserify": "npm:stream-browserify@1.0.0"
},
"github:jspm/nodelibs-util@0.1.0": {
"util": "npm:util@0.10.3"
},
"npm:assert@1.3.0": {
"util": "npm:util@0.10.3"
},
"npm:babel-runtime@5.8.35": {
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:buffer@3.6.0": {
"base64-js": "npm:base64-js@0.0.8",
"child_process": "github:jspm/nodelibs-child_process@0.1.0",
"fs": "github:jspm/nodelibs-fs@0.1.2",
"ieee754": "npm:ieee754@1.1.6",
"isarray": "npm:isarray@1.0.0",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:core-js@1.2.6": {
"fs": "github:jspm/nodelibs-fs@0.1.2",
"path": "github:jspm/nodelibs-path@0.1.0",
"process": "github:jspm/nodelibs-process@0.1.2",
"systemjs-json": "github:systemjs/plugin-json@0.1.0"
},
"npm:core-util-is@1.0.2": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0"
},
"npm:cssauron@1.2.0": {
"through": "npm:through@2.3.8"
},
"npm:error@4.4.0": {
"assert": "github:jspm/nodelibs-assert@0.1.0",
"camelize": "npm:camelize@1.0.0",
"string-template": "npm:string-template@0.2.1",
"xtend": "npm:xtend@4.0.1"
},
"npm:ev-store@7.0.0": {
"individual": "npm:individual@3.0.0"
},
"npm:global@4.3.0": {
"process": "npm:process@0.5.2"
},
"npm:inherits@2.0.1": {
"util": "github:jspm/nodelibs-util@0.1.0"
},
"npm:lodash@4.2.1": {
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:loose-envify@1.1.0": {
"js-tokens": "npm:js-tokens@1.0.2",
"process": "github:jspm/nodelibs-process@0.1.2",
"stream": "github:jspm/nodelibs-stream@0.1.0",
"util": "github:jspm/nodelibs-util@0.1.0"
},
"npm:next-tick@0.2.2": {
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:path-browserify@0.0.0": {
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:process@0.11.2": {
"assert": "github:jspm/nodelibs-assert@0.1.0"
},
"npm:readable-stream@1.1.13": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
"core-util-is": "npm:core-util-is@1.0.2",
"events": "github:jspm/nodelibs-events@0.1.1",
"inherits": "npm:inherits@2.0.1",
"isarray": "npm:isarray@0.0.1",
"process": "github:jspm/nodelibs-process@0.1.2",
"stream-browserify": "npm:stream-browserify@1.0.0",
"string_decoder": "npm:string_decoder@0.10.31"
},
"npm:redux@3.3.1": {
"lodash": "npm:lodash@4.2.1",
"lodash-es": "npm:lodash-es@4.2.1",
"loose-envify": "npm:loose-envify@1.1.0",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:stream-browserify@1.0.0": {
"events": "github:jspm/nodelibs-events@0.1.1",
"inherits": "npm:inherits@2.0.1",
"readable-stream": "npm:readable-stream@1.1.13"
},
"npm:string_decoder@0.10.31": {
"buffer": "github:jspm/nodelibs-buffer@0.1.0"
},
"npm:through@2.3.8": {
"process": "github:jspm/nodelibs-process@0.1.2",
"stream": "github:jspm/nodelibs-stream@0.1.0"
},
"npm:util@0.10.3": {
"inherits": "npm:inherits@2.0.1",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:vdom-virtualize@1.0.5": {
"virtual-dom": "npm:virtual-dom@2.1.1"
},
"npm:virtual-dom@2.1.1": {
"browser-split": "npm:browser-split@0.0.1",
"error": "npm:error@4.4.0",
"ev-store": "npm:ev-store@7.0.0",
"global": "npm:global@4.3.0",
"is-object": "npm:is-object@1.0.1",
"next-tick": "npm:next-tick@0.2.2",
"x-is-array": "npm:x-is-array@0.1.0",
"x-is-string": "npm:x-is-string@0.1.0"
},
"npm:vtree-select@2.0.0": {
"assert": "github:jspm/nodelibs-assert@0.1.0",
"cssauron": "npm:cssauron@1.2.0"
}
}
});
<script src="jspm_packages/system.src.js"></script>
<script src="config.js"></script>
<script>
System.import('main');
</script>
<p>The server rendered element below will be enhanced to a counter.</p>
<hr>
<div id="root">Enhanced: <span class="enhanced-status">no</span></div>
const udc = require('udc')
const h = require('virtual-dom/h');
const diff = require('virtual-dom/diff');
const patch = require('virtual-dom/patch');
const VText = require('virtual-dom/vnode/vtext');
const virtualizeDom = require('vdom-virtualize');
const select = require('vtree-select');
const Redux = require('redux');
const { createStore } = Redux;
const counter = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}
const store = createStore(counter)
// 1: Create a function that declares the delta
const render = (currentTree, count) => {
// Ultra deep clone then mutate. I wish we had an immutable virtual dom
const tree = udc(currentTree);
const enhancedStatusT = select('.enhanced-status')(tree)[0];
enhancedStatusT.children = [new VText('yes')]
tree.children[2] = h('div', [
h('p', `Counter: ${count}`),
h('button', { onclick: () => store.dispatch({ type: 'INCREMENT' }) }, 'Increment'),
h('button', { onclick: () => store.dispatch({ type: 'DECREMENT' }) }, 'Decrement')
]);
return tree;
}
// 2: Initialise the document
let count = 0;
let rootNode = document.querySelector('#root'); // Create an initial root DOM node ...
let tree = virtualizeDom(rootNode) // We need an initial tree
// 3: Wire up the update logic
const updateDom = function (state) {
const newTree = render(tree, state);
const patches = diff(tree, newTree);
rootNode = patch(rootNode, patches);
tree = newTree;
};
updateDom(store.getState());
store.subscribe(() => updateDom(store.getState()));
{
"dependencies": {
"jspm": "^0.16.27"
},
"jspm": {
"dependencies": {
"redux": "npm:redux@^3.3.1",
"udc": "npm:udc@^1.0.1",
"vdom-virtualize": "npm:vdom-virtualize@^1.0.5",
"virtual-dom": "npm:virtual-dom@^2.1.1",
"vtree-select": "npm:vtree-select@^2.0.0"
},
"devDependencies": {
"babel": "npm:babel-core@^5.8.24",
"babel-runtime": "npm:babel-runtime@^5.8.24",
"core-js": "npm:core-js@^1.1.4"
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment