Filtered by JavaScript

Page 12

Reset

Ultrafast loading of CSS

September 1, 2017
3 comments Web development, JavaScript

tl;dr; The ideal web performance, with regards to CSS, is to inline the minimal CSS and lazy load the rest after load.

Two key things to understand/appreciate:

  1. The fastest performing web page is one that isn't blocked on rendering.

  2. You use some CSS framework kitchen sink because you're not a CSS guru.

How to deal with this?

Things like HTTP2 and CDNs and preload are nice because they make the network lookup for your main.88c468ef.css file as fast as possible. But what's even faster is to include the CSS with the HTML that the server responds in the first place. Why? Because when the browser downloads your HTML (e.g. GET /) as it parses the HTML document it sees that <link rel="stylesheet" href="/main.88c468ef.css"> there and decides to not render any DOM to screen until that CSS file has been downloaded and parsed. It does this because it doesn't want to have to paint the DOM (as it would look like without CSS) and then repaint the DOM again, this time with CSS rules.

Point number 2 basically boils down to the likely fact that your app depends on somecssframework.min.css like Bootstrap, Bulma or Foundation. They're large blobs of CSS for doing all sorts of types of HTML (e.g. cards, tables, navbar menus etc.). These CSS frameworks are super useful because they make your app look pretty. But they're usually big. Really big.

Popular CSS frameworks:

Framework Size Gzipped
bootstrap.min.css 122K 18K
foundation.min.css 115K 16K
semantic.min.css 553K 93K
bulma.min.css 141K 18K

Actually the size difference isn't hugely important. What's important is that it's yet another thing that needs to be downloaded before the page can start to render. If the URL is in the user's cache, great. Even better, if it's cached by a service worker. However if you care about loading performance (judging by the fact that you're still reading), you know that a large majority of your visitors only come to your site sometimes (according to Google Analytics, 92.7% of my visitors are "new visitors"). Perhaps from a Google search. Or perhaps they visit sometimes but rarely enough that by the time they return their browser cache will have "moved on" and reset (to save disk space) what was previously cached.

CSS is a render blocking resource

With and without render blocking CSS
See Ilya Grigorik's primer on Render Blocking CSS.

It's also easy to demonstrate. Check out this Webpagetest Visual Comparison that compares two pages that are both styled with bootstrap.min.css except one of them uses a piece of JavaScript at the bottom of the page that enables the stylesheet after the page has loaded.

So if it's blocking. What to do about it? Well, make it not blocking. But how?

Solution 1

The simplest solution is to simply move any <link rel="stylesheet" href="bootstrap.min.css"> out of the <head> and put them just before the </body> tag. Here's an example of that.

It's valid HTML5 and seems to work just fine in Safari iOS. The only problem is that pesky "Flash of Unstyled Content" (aka. "FOUT") effect where the user is presented with the page very briefly without any styling, then the whole page re-renders onces the stylesheets have loaded. Chrome and iOS actually block the rendering still. So it's not like JavaScript whereby putting it late in the DOM. In other words, not really a good solution at all.

You can see in this Webpagetest that the "Start render" happens after the .css files have been loaded and parsed.

Solution 2

With JavaScript you can put in code that's definitely going to be executed after the rendering starts and, also, after the first rendering is finished (i.e. "DOM Content Loaded").

This technique is best done with loadCSS which can be done really well if you tune it. In particular the rel="preload" feature is getting more and more established. It used to only work in Chrome and Opera but will soon work in Firefox and iOS Safari too. Note, loadCSS contains a polyfill solution to the rel="preload" thing.

The basics is that you load a piece of JavaScript late which, as soon as it can, puts the <link rel="stylesheet" href="bootstrap.min.css"> into the DOM. You still have the Flash of Unstyled Content effect to confront and that's annoying.

Here's an example implementation. It uses the scripts and techniques laid out by filamentgroup's loadCSS.

It works and the rel="preload" is a bonus for Chrome and Opera users because once the JavaScript "kicks in" the network loading is quite possible already done. As seen in this Webpagetest using Chrome the .css files start downloading before the lazyloadcss.js file has even started downloading.

It's not as hot in Firefox because all the .css files downloading is delayed until after the lazyloadcss.js has loaded and executed.

Solution 3

Just inline all the CSS. Instead of <link rel="stylesheet" href="bootstrap.min.css"> you just make it inline. Like:


<style type="text/css">
/*!
 * Bootstrap v4.0.0-beta (https://getbootstrap.com)
 * Copyright 2011-2017 The Bootstrap Authors
 * Copyright 2011-2017 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 */@media print{*,::after,::before{text-shadow:none!important;box-shadow:none!important}......
</style>

All 123KB of it. Why not?! It has to be downloaded sooner or later anyway, might as well nip it in the bud straight away. The Flash of Unstyled Content problem goes away. So does the problem of having to load JavaScript tricks to make the CSS loading non-blocking.

The obvious and immediate caveat is that now the whole HTML document is huge! In this example page the whole HTML document is 127KB (20KB gzipped) whence the regular one is 4.1KB (1.4KB gzipped). And if your visitors, if you're so lucky, click on any other internal link that's another 127KB that has to be downloaded again.

The biggest caveat is that downloading a large HTML document is bad because no other resources (images for example) can be downloaded in parallel whilst the browser is working on rendering the page with what it's downloaded so far. If you compare this Webpagetest with the regular traditional one, you can see that it takes almost 354ms to download the HTML with all CSS inlined compared to 262ms when the CSS was linked. That's roughly 100ms wasted where the browser could start download other resources, like images.

Solution 4

Solution 3 was kinda good because it avoided the Flash of Unstyled Content and it avoided all extra resource loading. However, we can do better.

Instead of inlining all CSS, how about we take out exactly only the CSS we need out of bootstrap.min.css and just inline that. Then, after the page has loaded, we can download the rest of bootstrap.min.css and that way it's ready with all the other selectors and stuff it needs as the page probably changes and morphs depending on interactive JavaScript which is stuff that can and will happen after the initial load.

But how do you know exactly which CSS you need for that initial load? Really, you don't. You have two options:

  1. Manually inspected what DOM elements you have in your initial HTML and start slowly plucking that out of the Bootstrap CSS file.

  2. Automate the inspection of what DOM elements you have in your initial HTML.

Before we dig deeper into the how to automate the inspection let's look at what it'd look like: This page and when Webpagetested. What's cool here is that the DOM is ready in 265ms (it was 262ms when there was no linked CSS).

Notice that there's no Flash of Unstyled Content. No external dependencies. It's basically an inline <style> block with exactly the selectors that are needed and nothing more. The HTML is larger, at 13KB (3.3KB gzipped), but remember it was 4.1KB when we started and the solution where we inlined everything was 127KB.

The immediate problem with this is that we're missing some nice CSS for things that haven't been needed yet. For example, there might be some JavaScript that changes the DOM based on something the user does with the page. For example, clicking on something that adds more elements to the DOM. Or, equally likely, after the the DOM has loaded, an XHR query is made to download some data and display it in a way that needs CSS selectors that weren't included in the minimal set.

By the way, this very blog post builds on this solution. If you're on your desktop browser you can view source and see that there's only inline style blocks.

Solution 5

This builds on Solution 4. The HTML contains the minimal CSS needed for that first render and as soon as possible we additionally download the whole bootstrap.min.css so that it's available if/when the DOM mutates and needs the full CSS not in the minimal CSS.

Basically, let's take Solution 2 (JavaScript lazy loads in the CSS) + Solution 4 (the minimal CSS inlined). Here is one such solution

And there we have it! The ideal solution. The only thing remaining is to verify that it actually makes a difference.

The Webpagetest Final Showdown

We have 5 solutions. Each one different from the next. Let's compare them against each other.

Here it is in its full glory

Visual comparison on WebPagetest.org
(image if you can't open the Webpagetest page right now)

What we notice:

  1. The regular do-nothing solution is 50% slower than the best solution. 3.2 seconds verus 2.2 sceonds.
  2. Putting the <link rel="stylesheet" ...> tags at the bottom of the document doesn't work in Chrome and doesn't do anything good.
  3. Lazy loading the CSS with JavaScript (with no initial CSS) displays content very early but the repaint means it takes unnecessarily longer to load the whole thing.
  4. The ideal solution (Solution 5) loads as fast, visually, as Solution 4 but has the advantage that all CSS is there, eventually.
  5. Inlining all CSS (Solution 3) is only 23% slower than the ideal solution (Solution 5). But, it's much easier to implement. Seriously consider this if your tooling is limited.

Conclusion

One humbling thing to notice is that the difference isn't actually that huge. In this particular example we managed to go from 3.2 seconds to 2.2 seconds (using a 3G connection). The example playground used in this experiment is very far from a real site. Most possibly, a real site is a lot more complex and full of lots more potential bottlenecks that slows things down. For example, instead of obsessing over the CSS payload, perhaps you can make a bigger impact by simply dropping some excessive JavaScript plugins that might not necessarily be needed. Or you can focus on your 2.5MB total of big images.

However, a key ingredient to web performance is to leverge the loading time the best possible way. If you get the CSS un-blocking rendering right, your users' browsers can spend more time, sooner, on other resources such as images and XHR.

UPDATE March 2018

A lot of this work of figuring out the minimal CSS from a DOM has now been put in a rapidly maturing and well tested Nodejs project called minimalcss.

React lifecycle hooks must-have

August 13, 2017
1 comment Web development, JavaScript, React

I don't know who made this flowchart originally, but whoever you are: Thank you!

At this point, in my React learning I think I've memorized much of this but it's taken me a lot of time and having to dig up the documentation again. (Also, not to mention the number of times I've typo'ed componentWillReciveProps and componentWillRecevieProps etc.)

Remember this; You don't need to know all of these by heart to be good at React. In fact, there's several of these that I almost never use.

React lifecycle hooks flowchart

UPDATE

The above link is dead. Use this blog post instead.

UPDATE April 2018

Here's an even better one from @dan_abramov:

React life-cycle hooks

Web Console trick to get all URLs into your clipboard

April 27, 2017
0 comments Web development, JavaScript

This isn't rocket science in the world of Web Development but I think it's so darn useful that if you've been unlucky to miss this, it's worth mentioning one more time.

Suppose you're on a site with lots of links. Like https://www.peterbe.com/plog.
And you want to get a list of all URLs that contain word "react" in the URL pathname.
And you want to get this into your clipboard.

Here's what you do:

  1. Open your browsers Web Console. In Firefox it's Alt+Cmd+K on OSX (or F12). In Chrome it's Alt+Cmd+J.

  2. Type in the magic: copy([...document.querySelectorAll('a')].map(a => a.href).filter(u => u.match(/react/i)))

  3. Hit Enter, go to a text editor and paste like regular.

It should look something like this:

[
  "https://www.peterbe.com/plog/10-reasons-i-love-create-react-app",
  "https://www.peterbe.com/plog/how-to-deploy-a-create-react-app",
  "https://www.peterbe.com/plog/4-different-kinds-of-react-component-styles",
  "https://www.peterbe.com/plog/onchange-in-reactjs",
  "https://www.peterbe.com/plog/tips-on-learning-react",
  "https://www.peterbe.com/plog/visual-speed-comparison-of-angularjs-and-reactjs",
  "https://www.peterbe.com/plog/600-billion-challenge-reactions",
  "https://www.peterbe.com/plog/active-reactor-watches"
]

Web Console in Firefox
The example is just that. An example. The cool thing about this is:

  • The Web Console built-in command copy().
  • That [...document.querySelectorAll('a')] turns the NodeList object into a regular array.
  • That the .map(a => a.href) is super simple and it turns each Node into its href attribute value.
  • That you could have used a more advanced CSS selector like document.querySelectorAll(a[target="_blank"]) for example.

The limit is your imagination. You can also do things like copy([...document.querySelectorAll('a')].filter(a => a.textContent.match(/react/i)).map(a => a.href)) and you filter by the links' text.

Public Class Fields saves sooo many keystrokes in React code

April 14, 2017
1 comment JavaScript, React

tl;dr; I'm not a TC39 member and I barely understand half of what those heros are working on but there is one feature they're working on that really stands out, in my view, for React coders; Public Class Fields.

The Problem?

Very common pattern in React code is that have a component that has methods that are tied to DOM events (e.g. onClick) and often these methods need acess to this. The component's this. So you can reach things like this.state or this.setState().

You might have this in your code:


class App extends Component {
  state = {counter: 0}

  constructor() {
    super()

    // Like homework or situps; something you have to do :(
    this.incrementCounter = this.incrementCounter.bind(this) 
  }

  incrementCounter() {
    this.setState(ps => {
      return {counter: ps.counter + 1}
    })
  }

  render() {
    return (
      <div>
        <p>
          <button onClick={this.incrementCounter}>Increment</button>
        </p>
        <h1>{this.state.counter}</h1>
      </div>
    )
  }
}

Demo

If you don't bind the class method to this in the constructor, this will be undefined inside the class instance field incrementCounter. Buu!

Suppose you don't like having the word incrementCounter written in 4 placecs, you might opt for this shorthand notation where you create a new unnamed function inside the render function:


class App extends Component {
  state = {counter: 0}

  render() {
    return (
      <div>
        <p>
          <button onClick={() => {
            this.setState(ps => {
              return {counter: ps.counter + 1}
            })
          }}>Increment</button>
        </p>
        <h1>{this.state.counter}</h1>
      </div>
    )
  }
}

Demo

Sooo much shorter and kinda nice that the code can be so close in proximity to the actual onClick event definition.

But this notation has a horrible side-effect. It creates a new function on every render. If instead of a regular DOM jsx object <button> it might be a sub-component like <CoolButton/> then that sub-component would be forced to re-render every time (unless you write your own shouldComponentUpdate.

Also, this notation works when the code is small and light but it might get messy quickly if you need that functionality on other element's onClick. Or it might become mess with really deep indentation.

The Solution?

Public Class Fields.

That new feature is currently in the "Draft" stage at TC39. Aka. stage 1.

However, I discovered that you can use stage-2 in Babel to use this particular feature.

Note! I don't understand why you only have to put on your stage-2-brave socks for this feature when it's part of a definition that is stage 1.

Anyway, what it means is that you can define your field (aka method) like this instead:


class App extends Component {
  state = {counter: 0}

  incrementCounter = () => {
    this.setState(ps => {
      return {counter: ps.counter + 1}
    })
  }

  render() {
    return (
      <div>
        <p>
          <button onClick={this.incrementCounter}>Increment</button>
        </p>
        <h1>{this.state.counter}</h1>
      </div>
    )
  }
}

Demo

Now it's only mentioned by name incrementCounter twice. And no need for that manual binding in a constructor.
And since it's automatically bound, the function isn't recreated and those can easily make sub-components be pure.

So, let's always write our React methods this way from now on.

Oh, and in case you wonder. Inheritence works the same with these public class fields as the regular class instance fields.

More CSS load performance experiments (of a React app)

March 25, 2017
0 comments Web development, JavaScript, React

tl;dr; More experiments with different ways to lazy load CSS with and without web fonts. Keeping it simple is almost best but not good enough.

Background

Last week I blogged about Web Performance Optimization of a Single-Page-App and web fonts in which I experimented with tricks to delay the loading of some massive CSS file. The app is one of those newfangled single-page-app where JavaScript (React in this case) does ALL the DOM rendering, which is practical but suffers the first-load experience.

Again, let's iterate that single-page-apps built with fully fledged JavaScript frameworks isn't the enemy. The hope is that your visitors will load more than just one page. If users load it once, any further click within the app might involve some "blocking" AJAX but generally the app feels great since a click doesn't require a new page load.

Again, let's iterate what the ideal is. Ideally the page should load and be visually useful by the server sending all the DOM you almost need and once loaded, some JavaScript can turn the app "alive" so that further clicks just update the DOM instead of reloading. But that's not trivial. Things like react-router (especially version 4) makes it a lot easier but you now need a NodeJS server to render the pages server-side and you can't just easily take your "build" directory and put into a CDN like Firebase or CloudFront.

When I first started these experiements I was actually looking at what I can do with the JavaScript side to make first loads faster. Turns out fixing your CSS render blocking load and assessing use of web fonts has a bigger "bang for the buck".

Go Straight to the Results

Visual comparison on WebPagetest.org
Visual comparison of 6 different solutions

Same visual but as a comparative video

Stare at that for a second or two. Note that some versions start rendering something earlier than others. Some lose some of their rendered content and goes blank. Some change look significantly more than once before the final rendered result. As expected they almost all take the same total time till the final thing is fully rendered with DOM and all CSS loaded.

What Each Experimental Version Does

Original

A regular webapp straight out of the ./build directory built with Create React App. Blocking CSS, blocking JS and no attempts to show any minimal DOM stuff first.

Optimized Version 1

Inline CSS with basic stuff like background color and font color. CSS links are lazy loaded using tricks from loadCSS.

Optimized Version 2

Same as Optimized version 1 but both the JavaScript that lazy loads the CSS and the React JavaScript has a defer on it to prevent render blockage.

Optimized Version 3

Not much of an optimization. More of a test. Takes the original version but moves the <link rel="stylesheet" ... tags to just above the </body> tag. So below the <script src="..."> tags. Note how, around the 15 second mark, this renders the DOM (by the JavaScript code) before the CSS has loaded and it gets ugly. Note also how much longer this one takes because it has to context switch and go back to CSS loading and re-rendering after the DOM is built by the JavaScript.

Optimized Version 4

All custom web font loading removed. Bye bye "Lato" font-family. Yes you could argue that it looks worse but I still believe performance makes users more happy ultimately than prettiness (not true for all sites, e.g. a fashion web app).
Actually this version is copied from the Optimized version 1 but with the web fonts removed. The final winner in my opinion.

Optimized Version 5

Out of curiousity, let's remove the web fonts one more time but do it based on the Original. So no web fonts but CSS still render blocking.

So, Which Is Best?

I would say Optimized version 4. Remove the web font and do the loadCSS trick of loading the CSS after some really basic rendering but do that before loading the JavaScript. This is what I did to Podcast Time except slightly improved the initial server HTML so that it says "Loading..." immediately and I made the header nav look exactly like the one you get when everything is fully loaded.

Also, Chrome is quite a popular browser after all and the first browser that supports <link rel="preload" ...>. That means that when Chrome (and Opera 43 and Android Browser) parses the initial HTML and sees <link rel="preload" href="foo.css"> it can immediately start downloading that file and probably start parsing it too (in parallel). The visual comparison I did here on WebPagetest used Chrome (on 3G Emerging Markets) so that gives the optimized versions above a slight advantage only for Chrome.

What's Next?

To really make your fancy single-page-app fly like greased lightning you should probably do two things:

  1. Server-side render the HTML but perhaps do it in such a way that if your app depends on a lot of database data, skip that so you at least send a decent amount of HTML so when React/Angular/YouNameIt starts executing it doesn't have to do much DOM rendering and can just go straight to a loading message whilst it starts fetching the actual AJAX data that needs to be displayed. Or if it's a news article or blog post, include that in the server rendered HTML but let the client-side load other things like comments or a sidebar with related links.

  2. Tools like critical that figures out the critical above-the-fold CSS don't work great with single-page-apps where the DOM is generated by loaded JavaScript but you can probably hack around that by writing some scripts that generate a DOM as a HTML string by first loading the app in PhantomJS in various ways. That way you can inline all the CSS needed even after the JavaScript has built the DOM. And once that's loaded, then you can lazy load in the remaining CSS (e.g. bootstrap.min.css) to have all styles ready when the user starts clicking around on stuff.

Most important is the sites' functionality and value but hopefully these experiments have shown that you can get pretty good mileage from your standard build of a single-page-app without having to do too much tooling.

Web Performance Optimization of a Single-Page-App and web fonts

March 16, 2017
0 comments Web development, JavaScript, React

tl;dr; Don't worry so much about your bloated JavaScript and how to async it. Worry about your CSS and your Web fonts. Here I demonstrate a web performance optimization story with Webpagetest.org results demonstrating the improvements.

The app playground

I have a little app called Podcast Time. It's a single-page-app that renders all the functionality in React with the help of MobX and I use Bootstrap 4 and Bootswatch to make it "pretty". And that Bootswatch theme I chose depends on the Lato font by Google Fonts.

I blogged about it last month. Check it out if you're curious what it actually does. As with almost all my side-projects, it ultimately becomes a playground to see how I can performance optimize it.

sourcemap of combined .js file
The first thing I did was add a Service Worker so that consecutive visits all draws from a local cache. But I fear most visitors (all 52 of them (I kid, I don't know)) come just once and don't benefit from the Service Worker. The compiled and minified JavaScript weighs 124 KB gzipped (440 KB uncompressed) and the CSS weighs 20 KB gzipped (151 KB uncompressed). Not only that but the bootstrap.min.css contained an external import to Google Fonts's CSS that loads the external font files. And lastly, the JavaScript is intense. It's almost 0.5 MB of heavy framework machinery. Of that JavaScript about 45 KB which is "my code". By the way, as ES6 code it's actually 66 KB that my fingers have typed. So that's an interesting factoid about the BabelJS conversion to ES5 code.

Anyway, to make site ultra fast the bestest thing would be to rewrite all the JavaScript in vanilla JavaScript and implement, with browser quirks (read: polyfills), HTML5 pushState etc. Also, I guess I should go through the bootstrap.css file and extract exactly only the selectors I'm actually using. But I'm not going to do that. That would be counter productive and I wouldn't have a chance to add the kind of features I have and can add. So that fat JavaScript and that fat CSS needs to be downloaded.

So what can I do to make that slightly less painful? ...when Service Workers isn't an option.

1. The baseline

Here's the test results on Webpagetest.org

Click on the first Filmstrip View and notice that the rendering both starts and finishes between the 3.0 and 3.5 second mark. The test is done using Chrome on what they call "Mobile 3G Fast".

2. Have some placeholder content whilst it's downloading

I poked around at the CSS to get some really basics out of it. The background color, the font color, the basic grid. I then copied that into the index.html as an inline stylesheet. You can see it here.

The second thing I did was to replace all <link rel="stylesheet" href="..."> meta tags with this:


<link rel="preload" href="FOO.css" as="style" onload="this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="FOO.css"></noscript>

Also, near the bottom of the index.html I took the loadCSS.js and cssrelpreload.js scripts from Filament Group's loadCSS solution.

And lastly I copied the header text and the sub-title from the DOM, once rendered, plus added a little "Loading..." paragraph and put that into the DOM element that React mounts into once fully loaded.

Now the cool effect is that the render blocking CSS is gone. CSS loads AFTER some DOM rendering has happened. Yes, there's going to be an added delay when the browser has to re-render everything all over again, but at least now it appears that the site is working whilst you're waiting for the site to fully load. Much more user-friendly if you ask me.

Here's the test results on Webpagetest.org

A lot of blankness
Click on the first Filmstrip View and notice that some rendering started at the 0.9 second mark (instead of 3 seconds in the previous version). Then, after the browser notices that it's not the right font so it blanks the DOM, waits for the web font to load and around the time the web font is loaded, the JavaScript is loaded and ready so it starts rendering the final version at around the 2.8 second mark.

Note that the total time from start to finish is still the same. 3.1 second vs. 3.5 second. It's just that in this second version the user gets some indication that the site is alive and loading. I think the pulsating "Loading..." message puts the user at ease and although they're unhappy it still hasn't loaded I think it buys me a smidge of patience.

3. Hang on! Are web fonts really that important?

That FOIT is still pretty annoying though. When the browser realizes that the font is wrong, it makes the DOM blank until the right font has been loaded. My poor user has to stare at a blank screen for 1.3 seconds instad of seeing the "Loading..." message. Not only that but instead of just saying "Loading..." this could be an opportunity to display something more "constructive" that the user can actually start consuming with their eyes and brains. Then, by the time the full monty has been downloaded and ready the user will not have been waiting in vain.

So how important are those web fonts really? It's a nerdy app where search, content and aggregates matter more than the easthetic impression. Sure, a sexy looking site (no matter what the context/environment) does yield a better impression but there's tradeoffs to be made. If I can load it faster, my hunch is that that'll be more impressive than a pretty font. Secs sells.

I know there are possible good hacks to alleviate these FOIT problems. For example, in "How We Load Web Fonts Progressively" they first set the CSS to point to a system font-family, then, with a JavaScript polyfill they can know when the external web font has been downloaded and then they change the CSS. Cute and cool but it means yet another piece of JavaScript that has to be loaded. It also means "FOUT" (Flash Of Unstyled Text) which can disturb the view quite a lot if the changed font changes layout shifts.

Anyway, I decided I'll prefer fast loading over pretty font so I removed all font family hacks and references to the external font. Bye bye!

Here's the test results on Webpagetest.org

Click on the first Filmstrip View and notice that the rendering starts already at 1.2 seconds and stay with the "Loading..." message all the way till around 3.0 seconds when both the CSS and the full JavaScript has been loaded.

Side note; Lato vs. Helvetica Neue vs. Helvetica

You decide, is the Lato font that much prettier?

Lato

Lato

Helvetica Neue

Helvetica Neue

Helvetica

Helvetica

In Conclusion

PageSpeed Insights
I started this exploration trying to decide if there are better ways I can load my JavaScript files. I did some experiments with some server-side loading and async and defer. I scrutinized my ES6 code to see if there are things I can cut out. Perhaps I should switch to Preact instead of React but then I'd have to own the whole es-lint, babel and webpack config hell that create-react-app has eliminated and I'd get worried about not being able to benefit from awesome libraries like MobX and various routing libraries. However, when I was doing various measurements I noticed that all the tricks I tried, for a better loading experience, dwarfed in comparison to the render blocking CSS and the web font loading.

Service Workers is to web apps, what smartphone native apps are to mobile web pages in terms of loading performance. But Service Workers only work if you have a lot of repeat users.

If you want a fast loading experience and still have the convenience of building your app in a powerful JavaScript framework; focus on your CSS and your web font loading.

Podcasttime.io - How Much Time Do Your Podcasts Take To Listen To?

February 13, 2017
3 comments Python, Web development, Django, JavaScript, React

tl;dr; It's a web app where you search and find the podcasts you listen to. It then gives you a break down how much time that requires to keep up, per day, per week and per month. Podcasttime.io

Podcasttime.io on Firefox iOS
First I wrote some scripts to scrape various sources of podcasts. This is basically a RSS feed URL from which you can fetch the name and an image. And with some cron jobs you can download and parse each podcast feed and build up an index of how many episodes they have and how long each episode is. Together with each episodes "publish date" you can easily figure out an average of how much content each podcast puts out over time.

Suppose you listen to JavaScript Air, Talk Python To Me and Google Cloud Platform Podcast for example, that means you need to listen to podcasts for about 8 minutes per day to keep up.

The Back End

The technology is exciting. The backend is a Django 1.10 server. It manages a PostgreSQL database of all the podcasts, episodes, cron jobs etc. Through Django ORM signals is packages up each podcast with its metadata and stores it in an Elasticsearch database. All the communication between Django and ElasticSearch is done with Elasticsearch DSL.

Also, all the downloading and parsing of feeds is done as background tasks in Celery. This got really interesting/challenging because sooo many podcasts are poorly marked up and many a times the only way to find out how long an episode is is to use ffmpeg to probe it and that takes time.

Another biggish challenge is that fact that often things simply don't work because of networks being what they are, unreliable. So you have to re-attempt network calls without accidentally getting caught in infinite loops of accidentally putting a bad/broken RSS feed back into the background queue again and again and again.

The Front End

Actually, the first prototype of this app was written with Django as the front end plus some jQuery to tie things together. On a plane ride, and as an excuse to learn it, I re-wrote the whole thing in React with Redux. To be honest, I never really enjoyed that and it felt like everything was hard and I had to do more jumping-around-files than actual coding. In particular, Redux is nice but when you have a lot of AJAX both inside components and upon mounting it gets quite messy in my humble opinion.

So, on another plane ride (to Hawaii, so I had more time) I re-wrote it from scratch but this time using three beautiful pieces of front end technology: create-react-app, Mobx and mobx-router. Suddenly it became fun again. Mobx (or Redux or something "fluxy") is necessary if you want fancy pushState URLs AND a central (aka global) state management.

To be perfectly honest, I never actually tried combining Mobx with something like react-router or if it's even possible. But with mobx-router it's quite neat. You write a "views route map" (see example) where you can kick off AJAX before entering (and leaving) routes. Then you use that to populate a global store and now all components can be almost entirely about simply rendering the store. There is some AJAX within the mounted components (e.g. the search and autocomplete).

Plotly graph
On the home page, there's a chart that rather unscientifically plots episode durations over time as a line chart. I'm trying a library called Plotly which is actually a online app for building charts but they offer a free JavaScript library too for generating graphs. Not entirely sure how I feel about it yet but apart from looking a big crowded on mobile, it's working really well.

A Killer Feature

This is a pattern I've wanted to build but never managed to get right. The way to get data about a podcast (and its episodes) is to do an Elasticsearch search. From the homepage you basically call /find?q=Planet%20money when you search. That gives you almost all the information you need. So you store that in the global store. Then, if the user clicks on that particular podcast to go to its "perma page" you can simply load that podcast's individual route and you don't need to do something like /find?id=727 because you already have everything you need. If the user then opens that page in a new tab or reloads you now have to fetch just the one podcast, so you simply call /find?id=727. In other words, subsequent page loads load instantly! (Basically, it updates the store's podcast object upon clicking any of the podcasts iterated over from the listing. Code here)

And to top that - and this is where a good router shines - if you make a search or something, click something and click back since you have a global store of state, you can simply reuse that without needing another AJAX query.

The State of the Future

First of all, this is a fun little side project and it's probably buggy. My goal is not to make money on it but to build up a graph. Every time someone uses the site and finds the podcasts they listen to that slowly builds up connections. If you listen to "The Economist", "Planet Money" and "Freakonomics", that tie those together loosely. It's hard to programmatically know that those three podcasts are "related" but they are by "peoples' taste".

The ultimate goal of this is; now I can recommend other podcasts based on a given set. It's a little bit like LastFM used to work. Using Audioscrobbler LastFM was able to build up a graph based on what people preferred to listen to and using that network of knowledge they can recommend things you have not listened to but probably would appreciate.

At the moment, there's a simple Picks listing of "lists" (aka "picks") that people have chosen. With enough time and traffic I'll try to use Elasticsearch's X-Pack Graph capabilities to develop a search engine based on this.

At the time of writing, I've indexed 4,669 podcasts, spanning 611,025 episodes which equates to 549,722 hours of podcast content.

The Code

The front end code is available on github.com/peterbe/podcasttime2 and is relatively neat and tidy. The most interesting piece is probably the views/index.js which is the "controller" of things. That's where it decides which component to render, does the AJAX queries and manages the global store.

The back end code is a bit messier. It's done as an "app" as part of this very blog. The way the Elasticsearch indexing is configured is here and the hotch potch code for scraping and parsing RSS feeds is here.

Please try it out and show me your selection. You can drop feedback here.

10 Reasons I Love create-react-app

January 4, 2017
4 comments Web development, JavaScript

I now have two finished side projects (1 & 2) done and deployed based on create-react-app which I've kinda fallen in love with. Here are my reasons why I love create-react-app:

1. It Just Works

That wonderful Applesque feeling of "Man! That wasn't hard at all!". It's been such a solid experience with so few hiccups that I'm tickled really impressed. I think it works so well because it's a big project (174 contributors at the time of writing) and the scope is tight. Many other modern web framework boilerplatey projects feels like "This is how I do it. See if you like it. But you better think like I do."

2. No Hard Decisions To Be Made

Webpack still intimidates me. Babel still intimidates me. ESlint still intimidates me. I know how to use all three but whenever I do I feel like I'm not doing it right and that I'm missing out on something that everyone else knows. create-react-app encompasses all of these tools with a set of hard defaults. I know the Babel it ships with just works and I know that it isn't configured to support decorators but it works nicely and so far I've not had any desires to extend it.

Some people will get claustrophic not being able to configure things. But I'm "a making kinda person" so I like this focus on shipping rather than doing it the rightest way. In fact, I think it's a feature that you can't configure things in create-react-app. The option to yarn run eject isn't really an option because once you've ejected, and now can configure, you're no longer using create-react-app.

3. I Feel Like I'm Using Up-to-date Tech/Tools

I've tried other React (and AngularJS) boilerplate projects before and once started you always get nervous upgrading underlying bits with fear that it's going to stop working. Once you start a create-react-app project there are only two (three technically) things you need to update in your package.json and that's react-scripts and react (and react-dom technically).

If you read about a new cool way of doing something with Webpack|Babel|ESlint most likely that will be baked into react-scripts soon for you. So just stay cool and stay up to date.

By the way, as a side-note. If you've gotten used to keeping your package.json up to date with npm outdated make sure you switch to yarn and run yarn outdated. With yarn outdated it only checks the packages you've listed in package.json against npmjs.com. With npm oudated it will mention dependencies within listed packages that are outdated and that's really hard to evaluate.

4. The Server Proxy

Almost all my recent projects are single-page apps that load a behemoth of .js code and once started it starts getting data from a REST server built in Django or Go or something. So, realistically the app looks like this:


  componentDidMount() {
    fetch('/api/userdata/')
    .then(r = r.json())
    .then(response => {
      this.setState({userData: response.user_data})
    })
  }

With create-react-app you just add this line to your package.json:

"proxy": "http://localhost:8000"

Now, when you open http://localhost:3000 in the browser and the AJAX kicks off the browser thinks it's talking to http://localhost:3000/api/userdata/ but the Node server that create-react-app ships with just automatically passes that on to http://localhost:8000/api/userdata/. (This example just changes the port but note that it's a URL so the domain can be different too).

Now you don't have to worry about CORS or having to run everything via a local Nginx and use rewrite rules to route the /api/* queries.

5. One Page Documentation

This single page is all you need.

At the time of writing that documentation uses npm instead of yarn and I don't know why that is but, anyways, it's nice that it's all there in one single page. To find out how to do something I can just ⌘-f and find.

6. Has Nothing To Do With SCSS, Less or PostCSS

SCSS, Less and PostCSS are amazing but don't work with create-react-app. You have to use good old CSS. Remember that one? This is almost always fine by me because the kinds of changes I make to the CSS are mainly nudging one margin here or floating one div there. For that it's fine to keep is simple.

Although I haven't used it yet I'm very intrigued to use styled components as a really neat trick to style things in a contained and decentralized way that looks neat.

7. Has Nothing To Do With Redux, react-router or MobX

I'm sure you've seen it too. You discover some juicy looking React boilerplate project that looks really powerful but then you discover that it "forces" you to use Redux|react-router|MobX. Individually these are amazing libraries but if the boilerplate forces a choice that will immediately put some people off and the boilerplate project will immediately suffer from lack of users/contributors because it made a design decision too early.

It's really not hard to chose one of the fancier state management apps or other fancy routing libraries since your create-react-app project starts from scratch. They're all good but since I get to start from scratch and I build with my chosen libraries and learn how they work since I have to do it myself.

8. You Still Get Decent Hot Module Reloading

I have never been comfortable with react-hot-loader. Even after I tried the version 3 branch there were lots of times where I had to pause to think if I have to refresh the page or not.

By default, when you start a create-react-app project, it has a websocket thing connected to the server that notices when you edit source files and when doing so it refreshes the page you're on. That might feel brutish compared to the magic of proper hot module reloading. But for a guy who prefers console.log over debugger breakpoints this feels more than good enough to me.

In fact, if you add this to then bottom of your src/index.js now, when you edit a file, it won't refresh the page. Just reload the app:


if (module.hot) {
  module.hot.accept()
}

It will reload the state but the web console log doesn't disappear and a full browser refresh is usually slower.

9. Running Tests Included

I'll be honest and admit that I don't write tests. Not for side projects. Reason being that I'm almost always a single developer plus the app is most likely more a proof of concept than something supposed to stand the test of time.

But usually writing tests in JavaScript projects is scary. Not because it's hard but because it's tricky to get started. Which libraries should I use? Usually when you have a full suite up and running you realize that you depend on so many different libraries and once it works you cry a little when you read on Hacker News about some new fancy suite runner that literally has bells and whistles. create-react-app builds on jest but the documentation carefully takes you through the steps to start with simple unit tests to start rendering components, code coverage and continuous CI.

10. Dan Abramov

Dan is a powerhouse in the React community. Not just because he wrote Hot Reloading, redux and most of create-react-app, but because he's so incredibly nice.

I follow him on Twitter and his humble persona (aka #juniordevforlife) and positive attitude makes me feel close to him. And he oozes both-feet-on-the-ground-ism when it comes to the crazy world of JavaScript framework/library frenzy we're going through.

The fact that he built most of create-react-app, and that he encourages its uptake, makes me feel like I'm about to climb up on the shoulder of a giant.

Using Fanout.io in Django

December 13, 2016
1 comment Python, Web development, Django, Mozilla, JavaScript

Earlier this year we started using Fanout.io in Air Mozilla to enhance the experience for users awaiting content updates. Here I hope to flesh out its details a bit to inspire others to deploy a similar solution.

What It Is

First of all, Fanout.io is basically a service that handles your WebSockets. You put in some of Fanout's JavaScript into your site that handles a persistent WebSocket connection between your site and Fanout.io. And to push messages to your user you basically send them to Fanout.io from the server and they "forward" it to the WebSocket.

The HTML page looks like this:


<html>
<body>

  <h1>Web Page</h1>

<!-- replace the FANOUT_REALM_ID with the ID you get in the Fanout.io admin page -->
<script 
  src="https://{{ FANOUT_REALM_ID }}.fanoutcdn.com/bayeux/static/faye-browser-1.1.2-fanout1-min.js"
></script>
<script src="fanout.js"></script>
</body>
</html>

And the fanout.js script looks like this:


window.onload = function() {
  // replace the FANOUT_REALM_ID with the ID you get in the Fanout.io admin page
  var client = new Faye.Client('https://{{ FANOUT_REALM_ID }}.fanoutcdn.com/bayeux')
  client.subscribe('/mycomments', function(data) {  
     console.log('Incoming updated data from the server:', data);
  })
};

And in server it looks something like this:


from django.conf import settings
import fanout

fanout.realm = settings.FANOUT_REALM_ID
fanout.key = settings.FANOUT_REALM_KEY


def post_comment(request):
    """A django view function that saves the posted comment"""
   text = request.POST['comment']
   saved_comment = Comment.objects.create(text=text, user=request.user)
   fanout.publish('mycomments', {'new_comment': saved_comment.id})
   return http.JsonResponse({'comment_posted': True})

Note that, in the client-side code, there's no security since there's no authentication. Any client can connect to any channel. So it's important that you don't send anything sensitive. In fact, you should think of this pattern simply as a hint that something has changed. For example, here's a slightly more fleshed out example of how you'd use the subscription.


window.onload = function() {
  // replace the FANOUT_REALM_ID with the ID you get in the Fanout.io admin page
  var client = new Faye.Client('https://{{ FANOUT_REALM_ID }}.fanoutcdn.com/bayeux')
  client.subscribe('/mycomments', function(data) {  
    if (data.new_comment) {
      // server says a new comment has been posted in the server
      $.json('/comments', function(response) {
        $('#comments .comment').remove();
        $.each(response.comments, function(comment) {        
          $('<div class="comment">')
          .append($('<p>').text(comment.text))
          .append($('<span>').text('By: ' + comment.user.name))
          .appendTo('#comments');
        });
      });
    }
  })
};

Yes, I know jQuery isn't hip but it demonstrates the pattern well. Also, in the real world you might not want to ask the server for all comments (and re-render) but instead do an AJAX query to get all new comments since some parameter or something.

Why It's Awesome

It's awesome because you can have a simple page that updates near instantly when the server's database is updated. The alternative would be to do a setInterval loop that frequently does an AJAX query to see if there's new content to update. This is cumbersome because it requires a lot heavier AJAX queries. You might want to make it secure so you engage sessions that need to be looked up each time. Or, since you're going to request it often you have to write a very optimized server-side endpoint that is cheap to query often.

And last but not least, if you rely on an AJAX loop interval, you have to pick a frequency that your server can cope with and it's likely to be in the range of several seconds or else it might overload the server. That means that updates are quite delayed.

But maybe most important, you don't need to worry about running a WebSocket server. It's not terribly hard to do one yourself on your laptop with a bit of Node Express or Tornado but now you have yet another server to maintain and it, internally, needs to be connected to a "pub-sub framework" like Redis or a full blown message queue.

Alternatives

Fanout.io is not the only service that offers this. The decision to use Fanout.io was taken about a year ago and one of the attractive things it offers is that it's got a freemium option which is ideal for doing local testing. The honest truth is that I can't remember the other justifications used to chose Fanout.io over its competitors but here are some alternatives that popped up on a quick search:

It seems they all (including Fanout.io) has freemium plans, supports authentication, REST APIs (for sending and for querying connected clients' stats).

There are also some more advanced feature packed solutions like Meteor, Firebase and GunDB that act more like databases that are connected via WebSockets or alike. For example, you can have a database as a "conduit" for pushing data to a client. Meaning, instead of sending the data from the server directly you save it in a database which syncs to the connected clients.

Lastly, I've heard that Heroku has a really neat solution that does something similar whereby it sets up something similar as an extension.

Let's Get Realistic

The solution sketched out above is very simplistic. There are a lot more fine-grained details that you'd probably want to zoom in to if you're going to do this properly.

Throttling

In Air Mozilla, we call fanout.publish(channel, message) from a post_save ORM signal. If you have a lot of saves for some reason, you might be sending too many messages to the client. A throttling solution, per channel, simply makes sure your "callback" gets called only once per channel per small time frame. Here's the solution we employed:


window.Fanout = (function() {
  var _locks = {};
  return {
    subscribe: function subscribe(channel, callback) {
      _client.subscribe(channel, function(data) {
          if (_locks[channel]) {
              // throttled
              return;
          }
          _locks[channel] = true;
          callback(data);
          setTimeout(function() {
              _locks[channel] = false;
          }, 500);
      });        
    };
  }
})();

Subresource Integrity

Subresource integrity is an important web security technique where you know in advance a hash of the remote JavaScript you include. That means that if someone hacks the result of loading https://cdn.example.com/somelib.js the browser compares the hash of that with a hash mentioned in the <script> tag and refuses to load it if the hash doesn't match.

In the example of Fanout.io it actually looks like this:


<script 
  src="https://{{ FANOUT_REALM_ID }}.fanoutcdn.com/bayeux/static/faye-browser-1.1.2-fanout1-min.js"
  crossOrigin="anonymous"
  integrity="sha384-/9uLm3UDnP3tBHstjgZiqLa7fopVRjYmFinSBjz+FPS/ibb2C4aowhIttvYIGGt9"
></script>

The SHA you get from the Fanout.io documentation. It requires, and implies, that you need to use an exact version of the library. You can't use it like this: <script src="https://cdn.example/somelib.latest.min.js" ....

WebSockets vs. Long-polling

Fanout.io's JavaScript client follows a pattern that makes it compatible with clients that don't support WebSockets. The first technique it uses is called long-polling. With this the server basically relys on standard HTTP techniques but the responses are long lasting instead. It means the request simply takes a very long time to respond and when it does, that's when data can be passed.

This is not a problem for modern browsers. They almost all support WebSocket but you might have an application that isn't a modern browser.

Anyway, what Fanout.io does internally is that it first creates a long-polling connection but then shortly after tries to "upgrade" to WebSockets if it's supported. However, the projects I work only need to support modern browsers and there's a trick to tell Fanout to go straight to WebSockets:


var client = new Faye.Client('https://{{ FANOUT_REALM_ID }}.fanoutcdn.com/bayeux', {
    // What this means is that we're opting to have
    // Fanout start with fancy-pants WebSocket and
    // if that doesn't work it falls back on other
    // options, such as long-polling.
    // The default behaviour is that it starts with
    // long-polling and tries to "upgrade" itself
    // to WebSocket.
    transportMode: 'fallback'
});

Fallbacks

In the case of Air Mozilla, it already had a traditional solution whereby it does a setInterval loop that does an AJAX query frequently.

Because the networks can be flaky or because something might go wrong in the client, the way we use it is like this:


var RELOAD_INTERVAL = 5;  // seconds

if (typeof window.Fanout !== 'undefined') {
    Fanout.subscribe('/' + container.data('subscription-channel-comments'), function(data) {
        // Supposedly the comments have changed.
        // For security, let's not trust the data but just take it
        // as a hint that it's worth doing an AJAX query
        // now.
        Comments.load(container, data);
    });
    // If Fanout doesn't work for some reason even though it
    // was made available, still use the regular old
    // interval. Just not as frequently.
    RELOAD_INTERVAL = 60 * 5;
}
setInterval(function() {
    Comments.reload_loop(container);
}, RELOAD_INTERVAL * 1000);

Use Fanout Selectively/Progressively

In the case of Air Mozilla, there are lots of pages. Some don't ever need a WebSocket connection. For example, it might be a simple CRUD (Create Update Delete) page. So, for that I made the whole Fanout functionality "lazy" and it only gets set up if the page has some JavaScript that knows it needs it.

This also has the benefit that the Fanout resource loading etc. is slightly delayed until more pressing things have loaded and the DOM is ready.

You can see the whole solution here. And the way you use it here.

Have Many Channels

You can have as many channels as you like. Don't create a channel called comments when you can have a channel called comments-123 where 123 is the ID of the page you're on for example.

In the case of Air Mozilla, there's a channel for every single page. If you're sitting on a page with a commenting widget, it doesn't get WebSocket messages about newly posted comments on other pages.

Conclusion

We've now used Fanout for almost a year in our little Django + jQuery app and it's been great. The management pages in Air Mozilla use AngularJS and the integration looks like this in the event manager page:


window.Fanout.subscribe('/events', function(data) {
    $scope.$apply(lookForModifiedEvents);
});

Fanout.io's been great to us. Really responsive support and very reliable. But if I were to start a fresh new project that needs a solution like this I'd try to spend a little time to investigate the competitors to see if there are some neat features I'd enjoy.

UPDATE

Fanout reached out to help explain more what's great about Fanout.io

"One of Fanout's biggest differentiators is that we use and promote open technologies/standards. For example, our service supports the open Bayeux protocol, and you can connect to it with any compatible client library, such as Faye. Nearly all competing services have proprietary protocols. This "open" aspect of Fanout aligns pretty well with Mozilla's values, and in fact you'd have a hard time finding any alternative that works the same way."

How to deploy a create-react-app

November 4, 2016
2 comments Web development, JavaScript, React

First of all, create-react-app is an amazing kit. It's a zero configuration bundle that gives you a react app boilerplate with a dev server, linting and a deployment tool. All are awesome but not perfect.

I could go on giving this project praise but if you're here reading this you might be convinced already.

Anyway, the way you deploy a create-react-app project is actually stunningly simple, but there is one major caveat to look out for. Basically running yarn run build will first delete existing files in the ./build/ directory. Files that it indents to replace. For example your ./build/index.html or your ./build/static/js/main.94a86fe3.js.

So, what I suggest is that you deploy it like this:

#!/bin/bash

# Go into the project where the package.json exists
cd myproject
# Upgrade any libraries
yarn
# Use 
yarn run build
mv build build_final

Note! This tip is only applicable if you deploy "in place" as opposed to building a whole new container/image and swapping an old container/image for a new one.

Now, for your Nginx point to the ./build_final directory instead. For example:

# /etc/nginx/sites-enabled/mysite.conf
server {
    server_name mydomain.example.com;
    root /full/path/to/myproject/build_final;

    location / {
        try_files $uri /index.html;
        add_header   Cache-Control public;
        expires      1d;
    }
}

The whole point of this tip is that it's a good idea to not point Nginx to the ./build directory (but to a copy of it instead) because otherwise, during the seconds that yarn run build runs (1-5 seconds) a bunch of files will be missing and Nginx will send 404 errors to the clients unlucky enought to connect during the deployment.