Are you using progressive booting already? What about tree-shaking and code-splitting in React and Angular? Have you set up Brotli or Zopfli compression, OCSP stapling and HPACK compression? Also, how about resource hints, client hints and CSS containment — not to mention IPv6, HTTP/2 and service workers?
Back in the day, performance was often a mere afterthought. Often deferred till the very end of the project, it would boil down to minification, concatenation, asset optimization and potentially a few fine adjustments on the server’s
config file. Looking back now, things seem to have changed quite significantly.
Performance isn’t just a technical concern: It matters, and when baking it into the workflow, design decisions have to be informed by their performance implications. Performance has to be measured, monitored and refined continually, and the growing complexity of the web poses new challenges that make it hard to keep track of metrics, because metrics will vary significantly depending on the device, browser, protocol, network type and latency (CDNs, ISPs, caches, proxies, firewalls, load balancers and servers all play a role in performance).
So, if we created an overview of all the things we have to keep in mind when improving performance — from the very start of the process until the final release of the website — what would that list look like? Below you’ll find a (hopefully unbiased and objective) front-end performance checklist for 2017 — a brief overview of the issues you might need to consider to ensure that your response times are fast and your website smooth.
Front-End Performance Checklist 2017 Link
Micro-optimizations are great for keeping a performance on track, but it’s critical to have clearly defined targets in mind — measurable goals that would influence any decisions made throughout the process. There are a couple of different models, and the ones discussed below are quite opinionated — just make sure to set your own priorities early on.
Getting Ready And Setting Goals Link
- Be 20% faster than your fastest competitor.
According to psychological research1, if you want users to feel that your website is faster than any other website, you need to be at least 20% faster. Full-page loading time isn’t as relevant as metrics such as start rendering time, the first meaningful paint2 (i.e. the time required for a page to display its primary content) and the time to interactive3 (the time at which a page — and primarily a single-page application — appears to be ready enough that a user can interact with it).
Measure start rendering (with WebPagetest1664) and first meaningful paint times (with Lighthouse1705) on a Moto G, a mid-range Samsung device and a good middle-of-the-road device like a Nexus 4, preferably in an open device lab6 — on regular 3G, 4G and Wi-Fi connections.
Look at your analytics to see what your users are on. You can then mimic the 90th percentile’s experience for testing. Collect data, set up a spreadsheet8, shave off 20%, and set up your goals (i.e. performance budgets9) this way. Now you have something measurable to test against. If you’re keeping the budget in mind and trying to ship down just the minimal script to get a quick time-to-interactive value, then you’re on a reasonable path.
Share the checklist with your colleagues. Make sure that the checklist is familiar to every member of your team to avoid misunderstandings down the line. Every decision has performance implications, and the project would hugely benefit from front-end developers being actively involved when the concept, UX and visual design are decided on. Map design decisions against performance budget and the priorities defined in the checklist.
- 100-millisecond response time, 60 frames per second.
The RAIL performance model12 gives you healthy targets: Do your best to provide feedback in less than 100 milliseconds after initial input. To allow for <100 milliseconds response, the page must yield control back to main thread at latest after every <50 milliseconds. For high pressure points like animation, it’s best to do nothing else where you can and the absolute minimum where you can’t.
Also, each frame of animation should be completed in less than 16 milliseconds, thereby achieving 60 frames per second (1 second ÷ 60 = 16.6 milliseconds) — preferably under 10 milliseconds. Because the browser needs time to paint the new frame to the screen your code should finish executing before hitting the 16.6 milliseconds mark. Be optimistic13 and use the idle time wisely. Obviously, these targets apply to runtime performance, rather than loading performance.
- First meaningful paint under 1.25 seconds, SpeedIndex under 1000.
Although it might be very difficult to achieve, your ultimate goal should be a start rendering time under 1 second and a SpeedIndex14 value under 1000 (on a fast connection). For the first meaningful paint, count on 1250 milliseconds at most. For mobile, a start rendering time under 3 seconds for 3G on a mobile device is acceptable15. Being slightly above that is fine, but push to get these values as low as possible.
Defining the Environment Link
- Choose and set up your build tools.
Don’t pay much attention to what’s supposedly cool these days. Stick to your environment for building, be it Grunt, Gulp, Webpack, PostCSS or a combination of tools. As long as you are getting results fast and you have no issues maintaining your build process, you’re doing just fine.
- Progressive enhancement.
Keeping progressive enhancement16 as the guiding principle of your front-end architecture and deployment is a safe bet. Design and build the core experience first, and then enhance the experience with advanced features for capable browsers, creating resilient17 experiences. If your website runs fast on a slow machine with a poor screen in a poor browser on a suboptimal network, then it will only run faster on a fast machine with a good browser on a decent network.
- Angular, React, Ember and co.
- AMP or Instant Articles?
Depending on the priorities and strategy of your organization, you might want to consider using Google’s AMP25 or Facebook’s Instant Articles26. You can achieve good performance without them, but AMP does provide a solid performance framework with a free content delivery network (CDN), while Instant Articles will boost your performance on Facebook. You could build progressive web AMPs27, too.
- Choose your CDN wisely.
Depending on how much dynamic data you have, you might be able to “outsource” some part of the content to a static site generator28, pushing it to a CDN and serving a static version from it, thus avoiding database requests. You could even choose a static-hosting platform29 based on a CDN, enriching your pages with interactive components as enhancements (JAMStack30).
Notice that CDNs can serve (and offload) dynamic content as well? So, restricting your CDN to static assets is not necessary. Double-check whether your CDN performs content compression and conversion, smart HTTP/2 delivery, edge-side includes, which assemble static and dynamic parts of pages at the CDN’s edge (i.e. the server closest to the user), and other tasks.
Build Optimizations Link
- Set your priorities straight.
Set up a spreadsheet. Define the basic core experience for legacy browsers (i.e. fully accessible core content), the enhanced experience for capable browsers (i.e. the enriched, full experience) and the extras (assets that aren’t absolutely required and can be lazy-loaded, such as web fonts, unnecessary styles, carousel scripts, video players, social media buttons, large images). We published an article on “Improving Smashing Magazine’s Performance31,” which describes this approach in detail.
- Use the “cutting-the-mustard” technique.
Use the cutting-the-mustard technique32 to send the core experience to legacy browsers and an enhanced experience to modern browsers. Be strict in loading your assets: Load the core experience immediately, the enhancements on
DomContentLoadedand the extras on the
Note that the technique deduces device capability from browser version, which is no longer something we can do these days. For example, cheap Android phones in developing countries mostly run Chrome and will cut the mustard despite their limited memory and CPU capabilities. Beware that, while we don’t really have an alternative, use of the technique has become more limited recently.
- Consider micro-optimization and progressive booting.
In some apps, you might need some time to initialize the app before you can render the page. Display skeleton screens33 instead of loading indicators. Look for modules and techniques to speed up the initial rendering time (for example, tree-shaking34 and code-splitting35), because most performance issues come from the initial parsing time to bootstrap the app. Also, use an ahead-of-time compiler36 to offload some of the client-side rendering37 to the server38 and, hence, output usable results quickly. Finally, consider using Optimize.js39 for faster initial loading by wrapping eagerly invoked functions (it might not be necessary40 any longer, though).
- Are HTTP cache headers set properly?
max-ageand other HTTP cache headers have been set properly. In general, resources should be cacheable either for a very short time (if they are likely to change) or indefinitely (if they are static) — you can just change their version in the URL when needed.
If possible, use
Cache-control: immutable, designed for fingerprinted static resources, to avoid revalidation (as of December 2016, supported only in Firefox45 on
https://transactions). You can use Heroku’s primer on HTTP caching headers46, Jake Archibald’s “Caching Best Practices47” and Ilya Grigorik’s HTTP caching primer48 as guides.
asyncattributes in HTML.
In practice, it turns out we should prefer
async49 (at a cost to users of Internet Explorer50 up to and including version 9, because you’re likely to break scripts for them). Also, limit the impact of third-party libraries and scripts, especially with social sharing buttons and
<iframe>embeds (such as maps). You can use static social sharing buttons51 (such as by SSBG52) and static links to interactive maps53 instead.
- Are images properly optimized?
As far as possible, use responsive images54 with
<picture>element. While you’re at it, you could also make use of the WebP format55 by serving WebP images with the
<picture>element and a JPEG fallback (see Andreas Bovens’ code snippet56) or by using content negotiation (using
Acceptheaders). Sketch natively supports WebP, and WebP images can be exported from Photoshop using a WebP plugin for Photoshop57. Other options are available58, too.
You can also use client hints61, which are now gaining browser support62. Not enough resources to bake in sophisticated markup for responsive images? Use the Responsive Image Breakpoints Generator6360 or a service such as Cloudinary64 to automate image optimization. Also, in many cases, using
sizesalone will reap significant benefits. On Smashing Magazine, we use the postfix
-optfor image names — for example,
brotli-compression-opt.png; whenever an image contains that postfix, everybody on the team knows that it’s been optimized.
- Take image optimization to the next level.
When you’re working on a landing page on which it’s critical that a particular image loads blazingly fast, make sure that JPEGs are progressive and compressed with mozJPEG65 (which improves the start rendering time by manipulating scan levels), Pingo66 for PNG, Lossy GIF67 for GIF and SVGOMG68 for SVG. Blur out unnecessary parts of the image (by applying a Gaussian blur filter to them) to reduce the file size, and eventually you might even start to remove colors or make a picture black and white to reduce the size further. For background images, exporting photos from Photoshop with 0 to 10% quality can be absolutely acceptable as well.
- Are web fonts optimized?
Chances are high that the web fonts you are serving include glyphs and extra features that aren’t being used. You can ask your type foundry to subset web fonts or subset them yourself73 if you are using open-source fonts (for example, by including only Latin with some special accent glyphs) to minimize their file sizes. WOFF2 support74 is great, and you can use WOFF and OTF as fallbacks for browsers that don’t support it. Also, choose one of the strategies from Zach Leatherman’s “Comprehensive Guide to Font-Loading Strategies7875,” and use a service worker cache to cache fonts persistently. Need a quick win? Pixel Ambacht has a quick tutorial and case study76 to get your fonts in order.
If you can’t serve fonts from your server and are relying on third-party hosts, make sure to use Web Font Loader79. FOUT is better than FOIT80; start rendering text in the fallback right away, and load fonts asynchronously — you could also use loadCSS81 for that. You might be able to get away with locally installed OS fonts82 as well.
- Push critical CSS quickly.
To ensure that browsers start rendering your page as quickly as possible, it’s become a common practice83 to collect all of the CSS required to start rendering the first visible portion of the page (known as “critical CSS” or “above-the-fold CSS”) and add it inline in the
<head>of the page, thus reducing roundtrips. Due to the limited size of packages exchanged during the slow start phase, your budget for critical CSS is around 14 KB. If you go beyond that, the browser will need addition roundtrips to fetch more styles. CriticalCSS84 and Critical85 enable you to do just that. You might need to do it for every template you’re using. If possible, consider using the conditional inlining approach86 used by the Filament Group.
With HTTP/2, critical CSS could be stored in a separate CSS file and delivered via a server push without bloating the HTML. The catch is that server pushing isn’t supported consistently and has some caching issues (see slide 114 onwards of Hooman Beheshti’s presentation87). The effect could, in fact, be negative88 and bloat the network buffers, preventing genuine frames in the document from being delivered. Server pushing is much more effective on warm connections89 due to the TCP slow start. So, you might need to create a cache-aware HTTP/2 server push mechanism90. Keep in mind, though, that the new
cache-digestspecification91 will negate the need to manually build these “cache-aware” servers.
- Use tree-shaking and code-splitting to reduce payloads.
Tree-shaking92 is a way to clean up your build process by only including code that is actually used in production. You can use Webpack 2 to eliminate unused exports93, and UnCSS94 or Helium95 to remove unused styles from CSS. Also, you might want to consider learning how to write efficient CSS selectors96 as well as how to avoid bloat and expensive styles97.
Code-splitting98 is another Webpack feature that splits your code base into “chunks” that are loaded on demand. Once you define split points in your code, Webpack takes care of the dependencies and outputted files. It basically enables you to keep the initial download small and to request code on demand, when requested by the application.
Note that Rollup99 shows significantly better results than Browserify exports. While we’re at it, you might want to check out Rollupify100, which converts ECMAScript 2015 modules into one big CommonJS module — because small modules can have a surprisingly high performance cost101 depending on your choice of bundler and module system.
- Improve rendering performance.
Isolate expensive components with CSS containment102 — for example, to limit the scope of the browser’s styles, of layout and paint work for off-canvas navigation, or of third-party widgets. Make sure that there is no lag when scrolling the page or when an element is animated, and that you’re consistently hitting 60 frames per second. If that’s not possible, then at least making the frames per second consistent is preferable to a mixed range of 60 to 15. Use CSS’
will-change103 to inform the browser of which elements and properties will change.
Also, measure runtime rendering performance104 (for example, in DevTools105). To get started, check Paul Lewis’ free Udacity course on browser-rendering optimization106. We also have a lil’ article by Sergey Chikuyonok on how to get GPU animation right107.
- Warm up the connection to speed up delivery.
dns-prefetch109 (which performs a DNS lookup in the background),
preconnect110 (which asks the browser to start the connection handshake (DNS, TCP, TLS) in the background),
prefetch111 (which asks the browser to request a resource),
prerender112 (which asks the browser to render the specified page in the background) and
preload113 (which prefetches resources without executing them, among other things). Note that in practice, depending on browser support, you’ll prefer
dns-prefetch, and you’ll be cautious with using
prerender— the latter should only be used if you are very confident about where the user will go next (for example, in a purchasing funnel).
- Get ready for HTTP/2.
With Google moving towards a more secure web114 and eventual treatment of all HTTP pages in Chrome as being “not secure,” you’ll need to decide on whether to keep betting on HTTP/1.1 or set up an HTTP/2 environment115. HTTP/2 is supported very well116; it isn’t going anywhere; and, in most cases, you’re better off with it. The investment will be quite significant, but you’ll need to move to HTTP/2 sooner or later. On top of that, you can get a major performance boost117 with service workers and server push (at least long term).
The downsides are that you’ll have to migrate to HTTPS, and depending on how large your HTTP/1.1 user base is (that is, users on legacy operating systems or with legacy browsers), you’ll have to send different builds, which would require you to adapt a different build process120. Beware: Setting up both migration and a new build process might be tricky and time-consuming. For the rest of this article, I’ll assume that you’re either switching to or have already switched to HTTP/2.
- Properly deploy HTTP/2.
Again, serving assets over HTTP/2121 requires a major overhaul of how you’ve been serving assets so far. You’ll need to find a fine balance between packaging modules and loading many small modules in parallel.
Still, you can try to load CSS progressively127126. Obviously, by doing so, you are actively penalizing HTTP/1.1 users, so you might need to generate and serve different builds to different browsers as part of your deployment process, which is where things get slightly more complicated. You could get away with HTTP/2 connection coalescing128, which allows you to use domain sharding while benefiting from HTTP/2, but achieving this in practice is difficult.
What to do? If you’re running over HTTP/2, sending around 10 packages seems like a decent compromise (and isn’t too bad for legacy browsers). Experiment and measure to find the right balance for your website.
- Make sure the security on your server is bulletproof.
All browser implementations of HTTP/2 run over TLS, so you will probably want to avoid security warnings or some elements on your page not working. Double-check that your security headers are set properly129, eliminate known vulnerabilities130, and check your certificate131.
Haven’t migrated to HTTPS yet? Check The HTTPS-Only Standard132 for a thorough guide. Also, make sure that all external plugins and tracking scripts are loaded via HTTPS, that cross-site scripting isn’t possible and that both HTTP Strict Transport Security headers133 and Content Security Policy headers134 are properly set.
- Do your servers and CDNs support HTTP/2?
Different servers and CDNs are probably going to support HTTP/2 differently. Use Is TLS Fast Yet?137135 to check your options, or quickly look up how your servers are performing and which features you can expect to be supported.
- Is Brotli or Zopfli compression in use?
Last year, Google introduced138Brotli139, a new open-source lossless data format, which is now widely supported140 in Chrome, Firefox and Opera. In practice, Brotli appears to be more effective141 than Gzip and Deflate. It might be slow to compress, depending on the settings, and slower compression will ultimately lead to higher compression rates. Still, it decompresses fast. Because the algorithm comes from Google, it’s not surprising that browsers will accept it only if the user is visiting a website over HTTPS — and yes, there are technical reasons for that as well. The catch is that Brotli doesn’t come preinstalled on most servers today, and it’s not easy to set up without self-compiling NGINX or Ubuntu. However, you can enable Brotli even on CDNs that don’t support it142 yet (with a service worker).
Alternatively, you could look into using Zopfli’s compression algorithm143, which encodes data to Deflate, Gzip and Zlib formats. Any regular Gzip-compressed resource would benefit from Zopfli’s improved Deflate encoding, because the files will be 3 to 8% smaller than Zlib’s maximum compression. The catch is that files will take around 80 times longer to compress. That’s why it’s a good idea to use Zopfli on resources that don’t change much, files that are designed to be compressed once and downloaded many times.
- Is OCSP stapling enabled?
By enabling OCSP stapling on your server144, you can speed up your TLS handshakes. The Online Certificate Status Protocol (OCSP) was created as an alternative to the Certificate Revocation List (CRL) protocol. Both protocols are used to check whether an SSL certificate has been revoked. However, the OCSP protocol does not require the browser to spend time downloading and then searching a list for certificate information, hence reducing the time required for a handshake.
- Have you adopted IPv6 yet?
Because we’re running out of space with IPv4145 and major mobile networks are adopting IPv6 rapidly (the US has reached146 a 50% IPv6 adoption threshold), it’s a good idea to update your DNS to IPv6147 to stay bulletproof for the future. Just make sure that dual-stack support is provided across the network — it allows IPv6 and IPv4 to run simultaneously alongside each other. After all, IPv6 is not backwards-compatible. Also, studies show148 that IPv6 made those websites 10 to 15% faster due to neighbor discovery (NDP) and route optimization.
- Is HPACK compression in use?
If you’re using HTTP/2, double-check that your servers implement HPACK compression149 for HTTP response headers to reduce unnecessary overhead. Because HTTP/2 servers are relatively new, they may not fully support the specification, with HPACK being an example. H2spec150 is a great (if very technically detailed) tool to check that. HPACK works151.
- Are service workers used for caching and network fallbacks?
No performance optimization over a network can be faster than a locally stored cache on user’s machine. If your website is running over HTTPS, use the “Pragmatist’s Guide to Service Workers155” to cache static assets in a service worker cache and store offline fallbacks (or even offline pages) and retrieve them from the user’s machine, rather than going to the network. Also, check Jake’s Offline Cookbook156 and the free Udacity course “Offline Web Applications157.” Browser support? It’s getting there158, and the fallback is the network anyway.
Testing and Monitoring Link
- Monitor mixed-content warnings.
If you’ve recently migrated from HTTP to HTTPS, make sure to monitor both active and passive mixed-content warnings, with a tool such as Report-URI.io159. You can also use Mixed Content Scan160 to scan your HTTPS-enabled website for mixed content.
- Is your development workflow in DevTools optimized?
- Have you tested in proxy browsers and legacy browsers? Testing in Chrome and Firefox is not enough. Look into how your website works in proxy browsers and legacy browsers. UC Browser and Opera Mini, for instance, have a significant market share in Asia163 (up to 35% in Asia). Measure average Internet speed164 in your countries of interest to avoid big surprises down the road. Test with network throttling, and emulate a high-DPI device. BrowserStack165 is fantastic, but test on real devices as well.
- Is continuous monitoring set up?
Having a private instance of WebPagetest1664 is always beneficial for quick and unlimited tests. Set up continuous monitoring of performance budgets with automatic alerts. Set your own user-timing marks to measure and monitor business-specific metrics. Look into using SpeedCurve167 to monitor changes in performance over time, and/or New Relic168 to get insights that WebPagetest cannot provide. Also, look into SpeedTracker169, Lighthouse1705 and Calibre171.
Quick Wins Link
This list is quite comprehensive, and completing all of the optimizations might take quite a while. So, if you had just 1 hour to get significant improvements, what would you do? Let’s boil it all down to 10 low-hanging fruits. Obviously, before you start and once you finish, measure results, including start rendering time and SpeedIndex on a 3G and cable connection.
- Your goal is a start rendering time under 1 second on cable and under 3 seconds on 3G, and a SpeedIndex value under 1000.
- Prepare critical CSS for your main templates, and include it in the
<head>of the page. (Your budget is 14 KB).
- Add resource hints to speed up delivery with faster
- Subset web fonts and load them asynchronously (or just switch to system fonts instead).
- Optimize images, and consider using WebP for critical pages (such as landing pages).
- Check that HTTP cache headers and security headers are set properly.
- Enable Brotli or Zopfli compression on the server. (If that’s not possible, don’t forget to enable Gzip compression.)
- If HTTP/2 is available, enable HPACK compression and start monitoring mixed-content warnings. If you’re running over LTS, also enable OCSP stapling.
Download The Checklist (PDF, Apple Pages) Link
With this checklist in mind, you should be prepared for any kind of front-end performance project. Feel free to download the print-ready PDF of the checklist as well as an editable Apple Pages documents to customize the checklist for your needs:
- Download the checklist PDF172 (PDF, 0.129 MB)
- Download the checklist in Apple Pages173 (.pages, 0.236 MB)
Off We Go! Link
Some of the optimizations might be beyond the scope of your work or budget or might just be overkill given the legacy code you have to deal with. That’s fine! Use this checklist as a general (and hopefully comprehensive) guide, and create your own list of issues that apply to your context. But most importantly, test and measure your own projects to identify issues before optimizing. Happy performance results in 2017, everyone!
Huge thanks to Anselm Hannemann, Patrick Hamann, Addy Osmani, Andy Davies, Tim Kadlec, Yoav Weiss, Rey Bango, Mariana Peralta, Jacob Groß, Tim Swalling, Bob Visser, Kev Adamson and Rodney Rehm for reviewing this article, as well as our fantastic community, which has shared techniques and lessons learned from its work in performance optimization for everybody to use. You are truly smashing!
- 1 https://www.smashingmagazine.com/2015/09/why-performance-matters-the-perception-of-time/#the-need-for-performance-optimization-the-20-rule
- 2 https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint
- 3 https://developers.google.com/web/tools/lighthouse/audits/time-to-interactive
- 4 http://www.webpagetest.org/
- 5 https://github.com/GoogleChrome/lighthouse
- 6 https://www.smashingmagazine.com/2016/11/worlds-best-open-device-labs/
- 7 https://github.com/GoogleChrome/lighthouse
- 8 http://danielmall.com/articles/how-to-make-a-performance-budget/
- 9 http://bradfrost.com/blog/post/performance-budget-builder/
- 10 http://bradfrost.com/blog/post/performance-budget-builder/
- 11 http://bradfrost.com/blog/post/performance-budget-builder/
- 12 https://www.smashingmagazine.com/2015/10/rail-user-centric-model-performance/
- 13 http://info.meteor.com/blog/optimistic-ui-with-meteor-latency-compensation
- 14 https://sites.google.com/a/webpagetest.org/docs/using-webpagetest/metrics/speed-index
- 15 https://www.soasta.com/blog/google-mobile-web-performance-study/
- 16 https://www.aaron-gustafson.com/notebook/insert-clickbait-headline-about-progressive-enhancement-here/
- 17 https://resilientwebdesign.com/
- 18 https://www.youtube.com/watch?v=6I_GwgoGm1w
- 20 https://developers.google.com/web/fundamentals/performance/prpl-pattern/
- 21 https://developers.google.com/web/updates/2015/11/app-shell
- 22 https://developers.google.com/web/fundamentals/performance/prpl-pattern/
- 23 https://developers.google.com/web/updates/2015/11/app-shell
- 24 https://developers.google.com/web/updates/2015/11/app-shell
- 25 https://www.ampproject.org/
- 26 https://instantarticles.fb.com/
- 27 https://www.smashingmagazine.com/2016/12/progressive-web-amps/
- 28 https://www.smashingmagazine.com/2015/11/static-website-generators-jekyll-middleman-roots-hugo-review/
- 29 https://www.smashingmagazine.com/2015/11/modern-static-website-generators-next-big-thing/
- 30 https://jamstack.org/
- 31 https://www.smashingmagazine.com/2014/09/improving-smashing-magazine-performance-case-study/
- 32 http://responsivenews.co.uk/post/18948466399/cutting-the-mustard
- 33 https://twitter.com/lukew/status/665288063195594752
- 34 https://medium.com/@richavyas/aha-moments-from-ngconf-2016-part-1-angular-2-0-compile-cycle-6f462f68632e#.8b9afnsub
- 35 https://webpack.github.io/docs/code-splitting.html
- 36 https://www.lucidchart.com/techblog/2016/09/26/improving-angular-2-load-times/
- 37 https://www.smashingmagazine.com/2016/03/server-side-rendering-react-node-express/
- 38 http://redux.js.org/docs/recipes/ServerRendering.html
- 39 https://github.com/nolanlawson/optimize-js
- 40 https://twitter.com/tverwaes/status/809788255243739136
- 41 https://www.smashingmagazine.com/wp-content/uploads/2016/12/fmp-and-tti-opt.jpeg
- 42 https://aerotwist.com/blog/when-everything-is-important-nothing-is/
- 43 https://aerotwist.com/blog/when-everything-is-important-nothing-is/
- 44 https://aerotwist.com/blog/when-everything-is-important-nothing-is/#which-to-use-progressive-booting
- 45 https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
- 46 https://devcenter.heroku.com/articles/increasing-application-performance-with-http-cache-headers
- 47 https://jakearchibald.com/2016/caching-best-practices/
- 48 https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=en
- 49 http://calendar.perfplanet.com/2016/prefer-defer-over-async/
- 50 https://github.com/h5bp/lazyweb-requests/issues/42
- 51 https://www.savjee.be/2015/01/Creating-static-social-share-buttons/
- 52 https://simplesharingbuttons.com
- 53 https://developers.google.com/maps/documentation/static-maps/intro
- 54 https://www.smashingmagazine.com/2014/05/responsive-images-done-right-guide-picture-srcset/
- 55 https://www.smashingmagazine.com/2015/10/webp-images-and-performance/
- 56 https://dev.opera.com/articles/responsive-images/#different-image-types-use-case
- 57 http://telegraphics.com.au/sw/product/WebPFormat#webpformat
- 58 https://developers.google.com/speed/webp/docs/using
- 59 https://www.smashingmagazine.com/wp-content/uploads/2016/12/responsive-image-breakpoints-generator-large-opt.jpeg
- 60 http://www.responsivebreakpoints.com/
- 61 https://www.smashingmagazine.com/2016/01/leaner-responsive-images-client-hints/
- 62 http://caniuse.com/#search=client-hints
- 63 http://www.responsivebreakpoints.com/
- 64 http://cloudinary.com/documentation/api_and_access_identifiers
- 65 https://github.com/mozilla/mozjpeg
- 66 http://css-ig.net/pingo
- 67 https://kornel.ski/lossygif
- 68 https://jakearchibald.github.io/svgomg/
- 69 http://csswizardry.com/2016/10/improving-perceived-performance-with-multiple-background-images/
- 70 https://jmperezperez.com/medium-image-progressive-loading-placeholder/
- 71 https://manu.ninja/dominant-colors-for-lazy-loading-images#tiny-thumbnails
- 72 https://css-tricks.com/the-blur-up-technique-for-loading-background-images/
- 73 https://www.fontsquirrel.com/tools/webfont-generator
- 74 http://caniuse.com/#search=woff2
- 75 https://www.zachleat.com/web/comprehensive-webfonts/
- 76 https://pixelambacht.nl/2016/font-awesome-fixed/
- 77 https://www.zachleat.com/web/comprehensive-webfonts/
- 78 https://www.zachleat.com/web/comprehensive-webfonts/
- 79 https://github.com/typekit/webfontloader
- 80 https://www.filamentgroup.com/lab/font-events.html
- 81 https://github.com/filamentgroup/loadCSS
- 82 https://www.smashingmagazine.com/2015/11/using-system-ui-fonts-practical-guide/
- 83 https://www.smashingmagazine.com/2015/08/understanding-critical-css/
- 84 https://github.com/filamentgroup/criticalCSS
- 85 https://github.com/addyosmani/critical
- 86 https://www.filamentgroup.com/lab/performance-rwd.html
- 87 http://www.slideshare.net/Fastly/http2-what-no-one-is-telling-you
- 88 http://calendar.perfplanet.com/2016/http2-push-the-details/
- 89 https://docs.google.com/document/d/1K0NykTXBbbbTlv60t5MyJvXjqKGsCVNYHyLEXIxYMv0/edit
- 90 https://css-tricks.com/cache-aware-server-push/
- 91 http://calendar.perfplanet.com/2016/cache-digests-http2-server-push/
- 93 http://www.2ality.com/2015/12/webpack-tree-shaking.html
- 94 https://github.com/giakki/uncss
- 95 https://github.com/geuis/helium-css
- 96 http://csswizardry.com/2011/09/writing-efficient-css-selectors/
- 97 https://benfrain.com/css-performance-revisited-selectors-bloat-expensive-styles/
- 98 https://webpack.github.io/docs/code-splitting.html
- 99 http://rollupjs.org/
- 100 https://github.com/nolanlawson/rollupify
- 101 https://nolanlawson.com/2016/08/15/the-cost-of-small-modules/
- 102 http://caniuse.com/#search=contain
- 103 http://caniuse.com/#feat=will-change
- 104 https://aerotwist.com/blog/my-performance-audit-workflow/#runtime-performance
- 105 https://developers.google.com/web/tools/chrome-devtools/rendering-tools/
- 106 https://www.udacity.com/course/browser-rendering-optimization–ud860
- 107 https://www.smashingmagazine.com/2016/12/gpu-animation-doing-it-right/
- 108 https://w3c.github.io/resource-hints
- 109 http://caniuse.com/#search=dns-prefetch
- 110 http://www.caniuse.com/#search=preconnect
- 111 http://caniuse.com/#search=prefetch
- 112 http://caniuse.com/#search=prerender
- 113 https://www.smashingmagazine.com/2016/02/preload-what-is-it-good-for/
- 114 https://security.googleblog.com/2016/09/moving-towards-more-secure-web.html
- 115 https://http2.github.io/faq/
- 116 http://caniuse.com/#search=http2
- 117 https://www.youtube.com/watch?v=RWLzUnESylc&t=1s&list=PLNYkxOF6rcIBTs2KPy1E6tIYaWoFcG3uj&index=25
- 118 https://security.googleblog.com/2016/09/moving-towards-more-secure-web.html
- 119 https://security.googleblog.com/2016/09/moving-towards-more-secure-web.html
- 120 https://rmurphey.com/blog/2015/11/25/building-for-http2
- 121 https://www.youtube.com/watch?v=yURLTwZ3ehk
- 122 https://rmurphey.com/blog/2015/11/25/building-for-http2
- 123 http://engineering.khanacademy.org/posts/js-packaging-http2.htm
- 124 https://www.chromium.org/developers/design-documents/inter-process-communication
- 125 https://jakearchibald.com/2016/link-in-body/
- 126 https://jakearchibald.com/2016/link-in-body/
- 127 https://jakearchibald.com/2016/link-in-body/
- 128 https://daniel.haxx.se/blog/2016/08/18/http2-connection-coalescing/
- 129 https://securityheaders.io/
- 130 https://www.smashingmagazine.com/2016/01/eliminating-known-security-vulnerabilities-with-snyk/
- 131 https://www.ssllabs.com/ssltest/
- 132 https://https.cio.gov/faq/
- 133 https://www.owasp.org/index.php/HTTP_Strict_Transport_Security_Cheat_Sheet
- 134 https://content-security-policy.com/
- 135 https://istlsfastyet.com
- 136 https://istlsfastyet.com
- 137 https://istlsfastyet.com
- 138 https://opensource.googleblog.com/2015/09/introducing-brotli-new-compression.html
- 139 https://github.com/google/brotli
- 140 http://caniuse.com/#search=brotli
- 141 https://samsaffron.com/archive/2016/06/15/the-current-state-of-brotli-compression
- 142 http://calendar.perfplanet.com/2016/enabling-brotli-even-on-cdns-that-dont-support-it-yet/
- 143 https://blog.codinghorror.com/zopfli-optimization-literally-free-bandwidth/
- 144 https://www.digicert.com/enabling-ocsp-stapling.htm
- 145 https://en.wikipedia.org/wiki/IPv4_address_exhaustion
- 146 https://www.google.com/intl/en/ipv6/statistics.html#tab=ipv6-adoption&tab=ipv6-adoption
- 147 https://www.paessler.com/blog/2016/04/08/monitoring-news/ask-the-expert-current-status-on-ipv6
- 148 https://www.cloudflare.com/ipv6/
- 149 https://blog.cloudflare.com/hpack-the-silent-killer-feature-of-http-2/
- 150 https://github.com/summerwind/h2spec
- 151 https://www.keycdn.com/blog/http2-hpack-compression/
- 152 https://www.smashingmagazine.com/wp-content/uploads/2016/12/h2spec-example-large-opt.png
- 153 https://www.smashingmagazine.com/wp-content/uploads/2016/12/h2spec-example-large-opt.png
- 154 https://github.com/summerwind/h2spec
- 155 https://github.com/lyzadanger/pragmatist-service-worker
- 156 https://jakearchibald.com/2014/offline-cookbook/
- 157 https://www.udacity.com/course/offline-web-applications–ud899
- 158 http://caniuse.com/#search=serviceworker
- 159 https://report-uri.io/
- 160 https://github.com/bramus/mixed-content-scan
- 161 https://umaar.github.io/devtools-optimise-your-web-development-workflow-2016/#/
- 162 https://www.youtube.com/watch?v=N33lYfsAsoU
- 163 http://gs.statcounter.com/#mobile_browser-as-monthly-201511-201611
- 164 https://www.webworldwide.io/
- 165 https://www.browserstack.com
- 166 http://www.webpagetest.org/
- 167 https://speedcurve.com/
- 168 https://newrelic.com/browser-monitoring
- 169 https://speedtracker.org
- 170 https://github.com/GoogleChrome/lighthouse
- 171 https://calibreapp.com
- 172 http://provide.smashingmagazine.com/performance-checklist/performance-checklist-1.0.pdf
- 173 http://provide.smashingmagazine.com/performance-checklist/performance-checklist-1.0.pages
- 174 https://github.com/drublic/checklist
- 175 http://jonyablonski.com/designers-wpo-checklist/