PLAIN WRONG?

$(foo)

$(foo)

"Is this PHP?"

The tri-arrow function

The tri-arrow function (AKA “the gun rack”), executes three times.

const booms = (boom = 'boom') ⇶ boom += ' ' + boom console.log(`${booms()} (I want you in my room)`)

(British Broadcasting Company)

I am not a JavaScript engineer.

But I don't have to be to write JavaScript.

PLAIN?

JQuery

JQuery

React

JQuery

React

Angular

JQuery

React

Angular

Vanilla?

vanilla == plain // true

UNCOMPOSED?

const a = document.querySelector(a);
const b = document.querySelector(b);
const c = document.querySelector(c);
const d = document.querySelector(d);
const e = document.querySelector(e);

const Ꮂ = n => document.querySelector(n)

 

 

Ꮂ('body').onclick = () => alert('wow!')

Honey and Candied Thyme?

const Ꮂ = n => document.querySelector(n)

 

 

Ꮂ('body').onclick = () => alert('wow!')

Helper
functions

Libraries /

frameworks

(that you copy/pasted from Stack Overflow)

(that you installed with npm)

INDEPENDENT!

Great for
interaction design
consultants
(like me!)

{{<demo>}} 
  <button aria-pressed="false">Toggle Me</button> 
  <style> 
    button { 
      border-width: 0 .25rem .25rem 0; 
    } 
    
    [aria-pressed="true"] { 
      border-width: .25rem 0 0 .25rem; 
    } 
  </style> 
  <script> 
    const toggle = document.querySelector('[aria-pressed]') 

    toggle.onclick = function () { 
      var pressed = this.getAttribute('aria-pressed') === 'true'
      this.setAttribute('aria-pressed', !pressed) 
    } 
  </script> 
{{</demo>}}

<button :aria-pressed="theState">Toggle me</button>

<button aria-pressed={theState}>Toggle me</button>

<button :aria-pressed="theState">Toggle me</button>

<button aria-pressed={theState}>Toggle me</button>

# Component name

## Recommended markup

## Recommended layout

## Recommended behavior

## Reference implementation

React
Design
System

React stuff only :-(

WEB COMPONENTS!

(plain / native)

<button is="toggle-button">Toggle me</button>

A universal toggle button...

import Toggle from '../components/Toggle.js'
<button 
  is="toggle-button" 
  pressed={foo}
  ontoggle={bar}>
  Toggle me!
</button>
<button 
  is="toggle-button" 
  :pressed="foo"
  v-on:toggle="bar">
  Toggle me!
</button>

<script src="js/components.js" type="module">

# Markdown
<%template%>
<html>

BEST PRACTICES

  • Mirror attributes and props
  • Emit custom events
get pressed() {
  return this.hasAttribute('pressed')
}
  
set pressed(val) {
  if (val) {
    this.setAttribute('pressed', 'pressed')
    this.setAttribute('aria-pressed', 'true')
  } else {
    this.removeAttribute('pressed')
    this.setAttribute('aria-pressed', 'false')
  }
}

get and set

Observed state

static get observedAttributes() {
  return ['pressed']
}

 

attributeChangedCallback(name) {
 
if (name === 'pressed') {

    const event = new Event('toggle')
    this.dispatchEvent(event)
  }
}

onToggle="console.log(this.pressed)"

elem.pressed = true
elem.setAttribute('pressed', 'pressed')

DO A LOT
WITH A LITTLE

JavaScript increase:

2011

2018

109 KB → 399 KB

  • Transmission
  • Decompression
  • Parsing
  • Compiling

(1MB median)

“As much as I love JavaScript, it’s always the most expensive part of your site.”
— Addy Osmani, Google

  • Custom elements
  • Native imports
  • Vanilla CSS

(with custom properties + a bit of houdini)

"dependencies": {},
"devDependencies": {}

package.json 😱

"dependencies": {},
"devDependencies": {}

package.json 😱

demo?

Approx 35kb payload

  • Not the JS bundle; everything
  • Not initial; total
  • Includes 24 web components
  • Includes template parser
CLI "Empty"
production build
Vue CLI 106KB
Preact CLI 37.5KB

AI?

Drawing library?

probability(fraction) {
 
return Math.random() <= fraction
}


// TODO: A couple of for loops

Statefulness

function mutilator(obj, name = "m", context = window) {
  const mutilated = {}
  for (let prop in obj) {
    let ref = `m-${prop}`
    mutilated[ref] = obj[prop]
    Object.defineProperty(mutilated, prop, {
      set: function(v) {
        this[ref] = v
        context.dispatchEvent(
          new CustomEvent(`${name}:${prop}`, {
            detail: { value: v }
          })
        );
      },
      get: function() {
        return this[ref]
      }
    });
  }
  return mutilated;
}
const mutable = mutilator({
  string: 'foo',
  num: 6,
  etc: 'etc'
})
const mutable = mutilator({
  string: 'foo',
  num: 6,
  etc: 'etc'
})
context.addEventListener('m:string', function(e) {
    console.log(e.detail.value);
})

START WITH
NO JS

Progressive enhancement:

“Do stuff with JavaScript
if it's available”

“Do stuff with JavaScript
if it's available
AND YOU FUCKING NEED IT

Progressive enhancement:

<button is="toggle-button">Toggle me</button>

customElements.define(
  'toggle-button',
  ToggleButton,
  {
extends: 'button'}
);

HTMLButtonElement

Native buttons
already have:

 

  • Implicit button role
  • Focus capability
  • Key bindings
  • The disabled prop
  • etc

Smooth scrolling with...

youscroll.js
fluid-scroll.js
Scroll.js
pfSmoothScroll.js
smoothScroll.js
js-navbar-scroll.js
moveTo.js
AnimateScroll.js
scrollmenu.js
scrollToAnchor.js

body {
 
scroll-behavior: smooth;
}

Or...

body {
 
scroll-behavior: smooth;
}

Unrecognized?
Just skipped over

Or...

Meanwhile: JavaScript's error handling

JavaScript

JengaScript

All
JS??

Just for this?

Static SSR >
SSR + Rehydration

Rendering On The Web
— Addy Osmani & Jason Miller

Can see the thing

Can actually use the thing

START

As long as 14 seconds!

Approx 200b IIFE, embedded: "Critical JavaScript"

interstitials

trackers

scrolljacking

self-rotating
carousels

Retweeted by... Brendan Eich
Inventor Of JavaScript

Thank you!

With special thanks to Tim Holman, Rob Dodson, Jason Miller, Nick Colley, Jen Simmons, Adam Silver, Christian Schaefer, Chris Ferdinandi, and Andy Bell for inspiration.