Putting the "P"

in Preact

Background

Who is this guy

@_developit  on Twitter

@developit  on GitHub

Who is this guy

Background

  • Building mobile web apps since iOS 1
  • Actually earlier, Windows Mobile 5
  • Written a bunch of UI frameworks

Background

Look familiar?

This code was
written in 2008.

Background

  • "HTML5 OS"
  • Carbyn
  • custom DOM atop the real DOM​

... in IE 8, iOS 4 🤡

(artistic liberty)

  • Web Components
  • Shadow DOM
  • <style scoped>
  • CSS animations

Background

Unnecessary Terminal

Unnecessary IDE

Unnecessary Email Client

Lessons

Invention and reinvention

can appear dangerously similar

Maintenance requires large

scope of understanding

When you over-abstract,

you get nothing for free

What if...

Instead of fighting the web,

we embraced it?

Idea

Preact

Summer 2015

Origins

  • remembered: hyperscript

Accidentally wrote another template engine

Sad me

Hyperscript

<div id="one">
  Hello
</div>


<Foo hello />
h('div', { id:'one' },
  'Hello'
);


h(Foo, { hello: true })

Remember hyperscript?

It's behind everything now

JSX

From blog post "WTF is JSX"

// a "partial" that does a filtered loop
function foo(items) {
  return items.map( p => <li>{p}</li> );
}

let vdom = (
  <div id="foo">
    <p>Look, a simple JSX DOM renderer!</p>
    <ul>{ foo(ITEMS) }</ul>
  </div>
)

document.body.appendChild( render(vdom) );

I created Preact
to teach myself
how React worked

Preact

  • started out as a CodePen
  • animating hundreds of elements
  • obsessively profiled & tracked FPS
  • rapidly tested out ideas
  • recycling for memory usage?
  • cache props on DOM elements?
  • cache normalized nodeName?
  • cost of attributes vs properties

Paul Lewis (@aerotwist)

Pot Stirrer

"React + Performance = ?"

I wonder...

Results

Decent

Surprisingly Decent

Debounced rendering

Preact

Turns out,

Preact works a lot like Paul's Vanilla JS baseline.

Preact

  • hey, that's a tiny, simplified React!
  • added support for "transient" components
  • started adding React-isms:
  • stateful components (classes)
  • lifecycle methods
  • compositional components
  • refs
  • context

this was super

annoying to do

Paul Lewis

...again!

"The Cost of Frameworks"

It seems to me that developer ergonomics should be less important than our users’ needs.

Preact

  • Small modules / publish all the things
  • Needed a catchy name
  • All the good ones taken

Performance

Just keep profiling

Performance

  • Chrome Dev Tools Timeline, so good

Something to obsess over.

Performance

  • IRHydra2
  • @mraleph
  • see how/why
  • shows deopts

git.io/hydraosx

making changes

based on actual data

YOU

Lessons from IRHydra

  • monomophism
  • guard property access
  • inline helpers
  • short-circuit / fast path
  • when in doubt: benchmark!

Monomorphism

monomorphic

fn({ a: 1 })
fn({ a: 2 })

megamorphic

fn({ a: 1, b: 2 })
fn({ b: 2, a: 1 })
fn('a', 1)
fn(div)
fn(span)

polymorphic

fn({ a: 1 })
fn({ b: 2 })
fn({ a: 1 })
fn({ a: 1 }, 1)

best

worst

better


  fn = o => o.a

Guard Property Access

Help your friendly engine out a bit:


 let value = typeof dom.key!=='undefined' && dom.key

 // don't write this:
 if (obj.props)

 // if you mean this:
 if (typeof obj.props!=='undefined')

could be 0, '', null...

Inline Helpers

Functions can know too much.


 function hook(obj, name, a, b) {
   return obj[name] && obj[name](a, b);
 }

 hook(obj, 'foo', 1, 2);



 obj.foo(1, 2);

deopt after a few different values

has its own inline cache

Short-Circuitting

The cheapest function call
is the one you never make

- unknown

Benchmark!

Monomorphic

Guarded property access

*here be dragons

Quick DOM Tips

  • 💯 Text.nodeValue
  • 🍲 Batch writes
  • 📚 Avoid reads
  • 🎤 Avoid Live NodeLists

requestAnimationFrame

setTimeout

MutationObserver

Promise.then()

Today

Today

  • a growing community
  • expanding focus to Developer Experience
  • lots of discussion & contribution
  • in use at many companies

Use-Cases

  • Self-contained web widgets / embeds
  • Progressive Web Apps
  • Pieces of an existing application
  • Component-by-component migration
  • Web Components

Non-Use-Cases

  • React Native
  • Alternative Renderers
  • Certain 3rd-party libs
  • Uncomfortable with the DOM

New Use-Cases

Fin

Made with Slides.com