Polyfills as a service

by Sam Giles,

When you use reusable components (whether through convention, a framework like Fruit Machine or React, or directly using the emerging Web Components standard), you might find that components ship with polyfills. Your page may end up containing multiple polyfills for the same feature. You might also find that these polyfills all use slightly different implementations, and it’s not immediately obvious which is a faithful emulation of the missing feature. Even the packaging format and file structure is likely to vary between polyfills and make each one a special case.

This is far from ideal. We need some way of polyfilling browsers that avoids this duplication.

At the FT, we have a convention-based front end component system called Origami, designed to be forwards compatible with Web Components, and in designing all the various different pieces of UI, we didn’t want to end up having to embed polyfills everywhere. Instead, we built a polyfills-on-demand delivery system based on an existing open source service written by Jonathan Neal.

Essentially, what you want from a polyfill delivery system is a way of sending one single copy of each of the best polyfills, in the right order (respecting dependencies), to just the browsers that lack a native implementation. The polyfill service does this by reading the User-Agent HTTP header and then using it to find the list of polyfills that are suitable for that browser and its specific version. Typically once a browser version is released, its feature set does not change until its next release.

We’ve written a new backend in Node.JS, added aliasing features specifically to use Modernizr feature-detect names to selectively include required polyfills, and various features to make the service easier to deliver to a high level of availability, such as metrics, health checks, tests, load balancing and hosted documentation.

We’re still working on improving the API and adding more polyfills, but the service is already available to use, and thanks to the kind support and sponsorship of Fastly, we’re delighted to make it available to everyone, so you can use it too.

So, if you want some ES6 in your IE7, pop this tag into your HTML page today:

<script src="//cdn.polyfill.io/v1/polyfill.min.js"></script>

In the latest version of Chrome, this produces a virtually empty file. In IE7, it gives you a huge amount of code. This is what it produces in your browser:


Performance: Keep going forwards

Our focus for legacy browsers should be compatibility, not performance. If you sacrifice the performance of modern browsers in order to improve performance in legacy browsers, you’re doing something wrong. The best thing that a user of a legacy browser can do to improve performance would be to upgrade to a newer one. If they can’t or won’t, they still deserve to get a working website that they can read, but it stands to reason that it’s not going to be the fastest experience they’ve ever had.

So, by using the polyfill service developers can code using the latest standards that give the fastest performance in the latest browsers, and still be compatible with older browsers while they are hanging around.

But what about the blocking request that would need to be made on each page load? That is a problem, but it can be overcome by either using the polyfill service as a Node JS library or, if you’re not running a Node app, using it as a service and passing an extra ‘ua’ parameter to override the user agent. This allows you to inline your Javascript rather than requiring an extra request at the top of your page (though this prevents public caching of the page unless the cache can vary by User-Agent).

Debuggable

We realised that it would be important for developers to understand which polyfills were being included in the bundle and why. At the top of every response we include a comment that lists all the polyfills we included, their licence and the feature name that caused their inclusion:

/* Polyfill bundle includes the following polyfills.  For detailed credits
 * and licence information see http://github.com/financial-times/polyfill-service.
 * 
 * Detected: chrome/37.0.2062
 * 
 * - Array.isArray, License: CC0  (required by modernizr:es5array)
 * - Array.prototype.every, License: CC0  (required by modernizr:es5array)
 * - Array.prototype.filter, License: CC0  (required by modernizr:es5array)
 * - Array.prototype.forEach, License: CC0  (required by modernizr:es5array)
 * - Array.prototype.indexOf, License: CC0  (required by modernizr:es5array)
 * - Array.prototype.lastIndexOf, License: CC0  (required by modernizr:es5array)
 * - Array.prototype.map, License: CC0  (required by modernizr:es5array)
 * - Array.prototype.reduce, License: CC0  (required by modernizr:es5array)
 * - Array.prototype.reduceRight, License: CC0  (required by modernizr:es5array)
 * - Array.prototype.some, License: CC0  (required by modernizr:es5array)
 */

We need your help

The beauty of a canonical library of polyfills is that it becomes a much more valuable community tool than all the individual polyfills that make it up. We don’t use all the polyfills at the FT, so we need your help – if you’re a polyfill author, please take a moment to see whether we have a solution for the feature you’ve polyfilled, and let us know if yours is better (and whether we can use it!). If we don’t have it, consider making a pull request to add it to our library.