RAIL encouraged loading a site in under 1000ms on cable and (not well documented) between 3000ms and 5000ms on 3G. Loading is a pretty broad term and we don'the think it's enough for the page to "look" done. It should be engagable.

There are many different "key moments" in loading a page however that offer us more nuance.

  • “is it happening?” (i.e. time to first paint)
  • “is it useful?” (i.e. time to first meaningful paint)
  • “is it usable?” (i.e. time to stable layout / time to interactive)

Route-based chunking

Many of us building single-page apps today use JavaScript module bundling tools that trend towards a monolithic "bundle.js" file including the full app and vendor code for multiple routes. This means if a user lands on any arbitrary route they need to wait for a large bundle of JS to be fetched, parsed and executed before the application is fully rendered and interactive.

screen shot 2016-09-28 at 4 45 52 pm

This is a little backwards, especially when apps are used under real-world network (3G) and device


Problem: "Is there a nice pattern for using Critical via Gulp for CSS across a site with many pages which might be subtly different?"

The way I've tackled this in the past is breaking down the pages that might be slightly different into groups which each have their own Gulp task. For the sake of simplicity, we could have a set of pages that fall under red-theme, blue-theme etc. For each group, run critical.generate() against the set of URLs for the group (so, red-theme URLs) and allow it to inline the CSS for just that group. The benefit of thinking about this problem in a group for each task is if you need to apply additional customisations, config or build-time fixes per variation of page/theme, it's pretty trivial to do so. You then just run all of the critical group tasks near the end of your build and this should work.


Ember.js currently doesn't have baked in support for Service Worker. They want this and there's an ember-cli RFCS thread discussing strategies however a number of tooling efforts exist to help fill in this gap today.

Note: you can of course just write vanilla Service Worker code for your Ember.js apps and that will work just fine. This doc tracks tooling and libraries that lower the friction for getting this setup

Service Worker Libraries

These static resource precaching and runtime caching libraries are lower-level than Broccoli, but can be used directly



Modern JavaScript engines support an increasing intersection of ES2015 (and above) features which simply don't require transpilation in order to be successfully parsed and executed. This project lays out a proposal for a lightweight Autoprefixer-style tool that takes as input a target set of browsers (A) which check against a source of data for supported ES features (Kangax ES6 tables (B) (see and generate a mapping to Babel transforms for features requiring transpilation that are not supported (C) or not fully supported (e.g behind flags or staged but not flipped on to default).

To avoid the introduction of even more configuration files, this tool could piggyback off of some config we could

# if you do not have access to run the script, run "chmod 755 throttling"
# to run enter in terminal "./throttling [speed]"
# full (no throttling)
# fast (3000Kbit)
# medium (100Kbit)
# slow (10Kbit)
# wwdc (1Kbit)
# off (blocks connection)
View 12-days.js
// adapted from
// full credit to n3dst4. I just rewrote this to be browser developer tools friendly.
const pressies = [
"🐦🍳 ",
View app.yaml
application: your-app-name
version: 1
runtime: python27
api_version: 1
threadsafe: true
default_expiration: "30d"
# web files

tl;dr: no / it's quite hard :'(

Afaik, it's incredibly difficult to restore a highly multi-threaded system to a set state in time - doing so is non-trivial, but also comes with a heavy cost as quite a few different systems need to be in a relatively stable/safe state so you know what to save. For V8, saving state doesn't guarantee that it's possible to gather all of the information necessary to get you back to where you were in a random point in time given the various execution contexts your code is likely running in. You also need to factor in somehow serializing the different contexts in which your closures and other constructs exist in which is again not straight-forward.

For example, we might not be able to traverse the heap at that point, there may be threads that are still locked, not fully-initialized objects and so on. So at best you would be capturing an incomplete state of the world which may not scale when trying to restore the state of something quite complex. If it were possible to save state,