Shipping ES2015/ES6 Modules to Browsers

Good workflow fleshed out by Sam Thorogood on using ES2015/ES6 modules with browsers that support, whilst also keeping older browsers (that don’t support it) happy.

The modules

Let’s take these 2 simple modules for example:

// main.js
import {x} from ./foo.js
x().then(y => log(y));
// foo.js
export async function x() {
  let y = await fetch('...');
  y = await y.json();
  return y;
}

Shipping your code to browsers that do support ES6 Modules

  1. Include your main.js script as a module
    <script type="module" src="main.js"></script>
  2. There is no step 2

Shipping your code to browsers that don’t support ES6 Modules (and thus don’t support ES6)

  1. Use tools – like Rollup – to combine all your ES6 modules into one single file
  2. Transpile the generated module from ES6 to ES5
  3. Include the transpiled script as you’d normally do, but with a nomodule attribute so that the browsers that do support ES6 modules don’t load it (*)
    <script nomodule src="compiled.js"></script>

As both methods exclude each other, use ‘m both and you’re good to go 🙂

(*) As also detailed in Jake Archibald’s great introduction to ECMAScript modules (which you should read) there’s one nasty issue though: Safari 10.1 & Mobile Safari 10.3 don’t support the nomodule attribute. Luckily there’s a workaround to fixing this.

Elsewhere , , Leave a comment

Luke Skywalker’s Landspeeder™ Kid Electric Car

Luke Skywalker’s Landspeeder™ by Radio Flyer is modeled after the sand-pocked and sun-faded X-34 craft from Star Wars: A New Hope. With seats for 2 riders, an interactive dashboard with lights and real movie sounds, and a 5mph driving speed, this speeder provides a truly galactic driving experience.

For a whopping $499 this baby can be yours … erm, for your kids I mean.

Luke Skywalker’s Landspeeder™ by Radio Flyer →

Elsewhere , , Leave a comment

Detect unnecessary renders in React with why-did-you-update

why-did-you-update is a library that hooks into React and detects potentially unnecessary component renders. It detects when a component’s render method is called despite its props their values are the same.

Installation per npm, of course:

npm install --save-dev why-did-you-update

No need to adjust all your components either, why-did-you-update works by patching React itself:

import React from 'react'

if (process.env.NODE_ENV !== 'production') {
  const {whyDidYouUpdate} = require('why-did-you-update')
  whyDidYouUpdate(React)
}

why-did-you-update

Elsewhere , , Leave a comment

sw-toolbox – A Collection of Tools for Service Workers

Service Worker Toolbox provides some simple helpers for use in creating your own service workers. Specifically, it provides common caching strategies for dynamic content, such as API calls, third-party resources, and large or infrequently used local resources that you don’t want precached.

The code itself is very readable I must say:

importScripts('sw-toolbox.js');

toolbox.precache([
  '/css/app.css',
  '/img/logo.png'
]);

toolbox.router.get('/css*', toolbox.cacheFirst);
toolbox.router.get('/img*', toolbox.cacheFirst);
toolbox.router.get('/(.*)', toolbox.networkFirst, { networkTimeoutSeconds: 5});

A bit more advanced is to precache a “you’re offline” page first, and return that in case a user is offline (src):

importScripts('sw-toolbox.js');

toolbox.precache([
  '/offline',
  '/img/offline.png',
   // …
]);

// …

toolbox.router.get('/(.*)', function(request, values, options) {
  // networkFirst will attempt to return a response from the network,
  // then attempt to return a response from the cache.
  return toolbox.networkFirst(request, values, options).catch(function(error) {
    // If both the network and the cache fail, then `.catch()` will be triggered,
    // and we get a chance to respond with our cached fallback page.
    if (request.method === 'GET' && request.headers.get('accept').includes('text/html')) {
      return toolbox.cacheOnly(new Request('/offline'), values, options);
    }
    throw error;
  });
});

sw-toolbox
sw-toolbox (GitHub) →

A beginner’s guide to making Progressive Web Apps forms a nice introduction to implementing Service Workers using sw-toolbox.

If you’re looking for a non-library version I’d recommend starting with Implementing “Save For Offline” with Service Workers.

Elsewhere , , Leave a comment

CSS is simple, but not easy

Good observation by Jeremy Keith, after having attended (the magnificent) CSS Day:

Unlike a programming language that requires knowledge of loops, variables, and other concepts, CSS is pretty easy to pick up. Maybe it’s because of this that it has gained the reputation of being simple. It is simple in the sense of “not complex”, but that doesn’t mean it’s easy. Mistaking “simple” for “easy” will only lead to heartache.

Be sure to read the whole thing.

CSS →

Elsewhere , Leave a comment

Jamie xx Boiler Room Reykjavík DJ Set

Quite enjoyed this set during work today 🙂

Elsewhere , , Leave a comment

The Hidden Oil Patterns on Bowling Lanes

There’s more to the oil on a bowling lane than meets the eye. Knowing what it is, and knowing how it affects things makes you look at it – and play – differently. Seasoned players recognise it automatically, like a sort of instinct, whilst I just see a shiny surface.

Elsewhere , Leave a comment

justify-content: space-evenly; for Flexbox

A new alignment mode for Flex-containers is justify-content: space-evenly;

The alignment subjects are distributed so that the spacing between any two adjacent alignment subjects, before the first alignment subject, and after the last alignment subject is the same.

Currently supported in Firefox, and in Chrome Canary.

Box Alignment justify-content: space-evenly; for Flex-Containers →

Elsewhere , , 2 Comments

What’s new in JavaScript? ES2017/“ES8” Language Features

The ECMAScript 2017 Language Specification – the 8th edition of the spec – was officially released at the end of June by TC39.

💁‍♂️ ICYWW: Should we say ES2017 or ES8?

→ Say ES2017. Back in the day ES6 was (and still is) used a lot to refer to ES2015, but one should be referring to the standard using the year references (or refer to a language feature using its name)

One of the top additions – which I’ve been using for quite a while now thanks to babel-polyfill and its included core-js – is Object.entries()/Object.values(), as they have rather big effect on the way I write my code.

const obj = { x: 'xxx', y: 1 };
Object.values(obj); // ['xxx', 1]

const obj = { x: 'xxx’, y: 1 };
Object.entries(obj); // [[’x’, 'xxx’], [’y’, 1]]

As it’s an array, one can easily append a .forEach(…) to each one of these beauties to get going … And don’t forget about map/reduce/filter either 😉

Async functions is also at the top of my list of influential features:

function fetchTextByPromise() {
  return new Promise(resolve => { 
    setTimeout(() => { 
      resolve("es8");
    }, 2000);
  });
}
async function sayHello() { 
  const externalFetchedText = await fetchTextByPromise();
  console.log(`Hello, ${externalFetchedText}`); // Hello, es8
}
sayHello();

Furthermore some new string padding functions, Object.getOwnPropertyDescriptors(obj), “Trailing commas in function parameter lists and calls”, and “Shared memory and atomics” has been added.

ES8 was Released and here are its Main New Features →
ECMAScript 2017 Language Specification (PDF) →

Elsewhere , Leave a comment

PngPong Image Manipulation Library

For the recent UK Elections the folks The Guardian wanted to show big images along with their push notifications. Being bandwidth-aware they wanted a solution in which they could use a template image (which could then be cached) and then draw some stuff onto it. Only problem: Service Workers don’t have access to the Canvas API.

Enter PngPong, an basic image manipulation library, they’ve created:

PngPong is a very, very basic replacement for the Canvas API in environments that do not support it – primarily, service workers. Instead, it manually manipulates the bytes of a PNG file to copy the contents of another image, or draw basic shapes (currently only rectangles).

Their code to handle push notifications looked something like this:

self.addEventListener('push', (e) => {
    e.waitUntil(
        caches.match('/notification_template.png')
        .then((res) => res.arrayBuffer())
        .then((arrayBuffer) => {
            addResultsToTemplate(arrayBuffer, e.data);
            return blobToDataURL(new Blob([arrayBuffer]))
        })
        .then((imageURL) => {
            return self.registration.showNotification("Title", {
                image: imageURL
            })
        })
    )
})

Inside addResultsToTemplate they heavy lifting would be done by PngPong, drawing some small rectangles onto the template pictured below, yielding a push notification as pictured at the top of this post.


The template used

Example PngPong usage:

import {
  PngPong,
  PngPongShapeTransformer,
  PngPongImageCopyTransformer
} from 'png-pong';

// Create new PngPong instance
const pngPong = new PngPong(imageArrayBuffer);

// Draw a 30px red square 10px from the top and 10px from the left
const shape = new PngPongShapeTransformer(pngPong);
shape.drawRect(10, 10, 30, 30, [255, 0, 0])

// Copy a 50x50 image 10px from the top left of the source image,
// and draw it 30px into our target image. 
const toCopyFrom = new ArrayBuffer();
const imageCopy = new PngPongImageCopyTransformer(toCopyFrom, pngPong);
imageCopy.copy(10, 10, 50, 50, 30, 30);

// Run the transforms
pngPong.run();

PngPong (GitHub) →
PngPong Use Case: Generating Images in JavaScript Without Using the Canvas API →

Elsewhere , , , Leave a comment