What if…?
Wednesday, 28th of July @ trivago
Jason Miller
Web DevRel @Google
Marvin Hagemeister
Consultant @AWESOME! Software
Fast 3kB framework and close to the DOM
How can we reimagine what
Preact can be?
What even is the next thing?
Long-Term vision
Short-Term thinking
Positive
prototyping
culture
No internal/external pressure
Ok to fail → learnings
Allow ideas to grow
Async collaboration
Explore alternative implementations
consequences
of a change?
What are the
change
system
used modern JS features?
What if we...
setState(update, callback) {
var s = this._state;
if (!s) {
s = this._state = assign({}, this.state);
}
assign(s, update);
if (callback) {
this._callbacks.push(callback);
}
enqueueRender(this);
}
setState(update, callback) {
let s = this._state;
if (!s) {
s = this._state = Object.assign({}, this.state);
}
Object.assign(s, update);
if (callback) {
this._callbacks.push(callback);
}
enqueueRender(this);
}
Example: JSX
transpiles to:
source code:
function Link({ href, children }) {
return <a href={href}>link: {children}</a>;
}
function Link({ href, children }) {
return h('a', { href }, 'link: ', children);
}
also known as createElement() or React.createElement()
function createElement(type, props, children) {
if (arguments.length > 3) {
children = [children]
for (let i=3; i<arguments.length, i++) {
children.push(i);
}
}
if (children != null) {
props.children = children;
}
return { type, props };
}
createElement(
'a',
{ href },
'link: ',
children
)
with modern JS
function createElement(type, props, ...children) {
if (children.length !== 0) {
props.children = children;
}
return { type, props };
}
with modern JS
function createElement(type, props, ...children) {
if (children.length === 1) {
props.children = children[0];
}
else if (children.length > 1) {
props.children = children;
}
return { type, props };
}
always allocates an Array
back to ES5
function createElement(type, props, children) {
if (arguments.length > 3) {
children = Array.prototype.slice.call(arguments, 2);
}
if (children != null) {
props.children = children;
}
return { type, props };
}
only for�2+ children
use modern JS
What did we learn?
remove workarounds
Drop workarounds
for IE11
removed recursion?
What if we...
Recursion
function diff(node, next) {
if (node.type != next.type) {
return replace(node, next);
}
for (child of children) {
let nextChild = /* find match */;
diff(child, nextChild);
}
}
repeat to walk down the tree
Recursion
Loop
diff(oldVNode, newVNode)
diff(oldVNode, newVNode)
diff(oldVNode, newVNode)
diff(oldVNode, newVNode)
// ...
const pending = [...];
let item;
while (item = pending.pop()) {
diff(item.old, item.new);
}
Recursion
Loop
only use a switch-statement?
What if we...
const operations = [];
let op, node;
while ({ op, node } = operations.pop()) {
switch (op) {
case MOUNT:
/* code for mounting `node` */���
break;
case UNMOUNT: /*...*/ break;
case PATCH: /*...*/ break;
}
}
const operations = [];
let op, node;
while ({ op, node } = operations.pop()) {
switch (op) {
case MOUNT:
/* code for mounting `node` */
for (let node of node.children) {
operations.push({ op: MOUNT, node });
}
break;
case UNMOUNT: /*...*/ break;
case PATCH: /*...*/ break;
}
}
Sequence of commands
insert
patch
set prop
swap
remove
(op-queue, stack machine)
know if this is any better?
Errr...how do we
remove all deopts?
What if we...
Your optimization insight is
only as good
as the benchmark it is obtained from
removed class components?
What if we...
Preact X: Component normalization
// Instantiate class component
if (newType.prototype.render) {
c = new newType(newProps);
} else {
// Convert function component into a class component
c = new Component(newProps);
c.constructor = newType;
c.render = doRender;
}
Same code path saves bytes
State and Hooks
render state (error, suspend, ...)
view hierarchy
Reasons:
Planning for evolution
Function Components
2018
Hooks
2020
Observables?
??
2015
createClass
Class Components
2016
Vue’s Composition API
Generator Components
Non-JS Components
??
→ component instance
→ backing node
→ component instance
split diffing from rendering
Realization:
img
img
div
a
#text
#text
DOM Layer
Virtual-DOM Layer
#text
div
a
#text
walk the DOM for position & order
Preact 10
img
#text
div
a
#text
img
div
a
#text
#text
DOM Layer
Virtual-DOM Layer
use virtual tree for position & order
Preact 11
combine approaches?
What if we...
Backing Tree
Operation Queue
Remove Legacy
Next-gen Renderer
Faster algorithms
Custom renderers + components
Better animation scheduling
Deeper tooling + debugging
Evolutionary milestones:
split diff�+ render
(attempt #1)
Reality is less linear
Trivago Sponsoring
Server Components
AOT SSR
Devtools Hook Names
split diff + render
Extract
components
Op Queue
Backing nodes
~0 deopts
split diff�+ render
(attempt #2)
today
Observable components
3 Tries
Q&A
Thanks!