In the first article, we did a quick overview of some of the performance improvements in HTTP/2 and the implications this will have on the way we deploy assets to production. This post will delve a little deeper and attempt to establish some initial guidelines and workflow that could be used when deploying front-end components to HTTP/2 sites.
To try out these techniques you may want to Install NGINX and HTTP/2 in your local dev environment.
Request and Response Multiplexing
HTTP/2 supports multiplexing — Multiple requests and responses can simultaneously use the same connections. There is no longer a big performance benefit to be gained from compiling all of your individual CSS and JS files into two large application.css and application.js files.
By avoiding concatenation we can potentially make the browser cache work more efficiently, one small change no longer needs to invalidate the whole cache.
HTTP requests are much cheaper in the world of HTTP/2 — Although requests may be cheap they are not completely free. In practice, this means that you can probably forget about image spriting and make about ten times more requests per page. However, it's not wise to make hundreds more requests as there will be a memory overhead.
Building your components
In recent years component based approaches to UI development have become popular. CSS methodologies like BEM/SUIT and JavaScript frameworks like React and Vue.js have helped promote this approach.
With this in mind, how might we structure a typical template?
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" media="all" href="/css/global.css">
</head>
<body>
<link rel="stylesheet" media="all" href="/css/components/header.css">
<header class="Header">
...
</header>
<link rel="stylesheet" media="all" href="/css/components/lead.css">
<section class="Lead">
...
</section>
<link rel="stylesheet" media="all" href="/css/components/photo.css">
<article class="Photo Photo--sizeLarge">
<a class="Photo-crop Photo-crop--circle" href="photo.jpg">
<span class="Photo-icon">
<span class="Icon Icon--zoom"></span>
</span>
<img class="Photo-img u-block" src="photo.jpg" alt="">
</a>
<div class="Photo-caption u-textBreak">
A photo of <a href="/barackobama">Barack Obama</a> in the Whitehouse.
</div>
</article>
...etc
<link rel="stylesheet" media="all" href="/css/components/footer.css">
<footer class="Footer">
... etc
</footer>
</body>
</html>
This approach should work for small to medium sites. HTTP/2 multiplexing can handle the requests for each component efficiently and by avoiding file concatenation local browser caching will be more effective.
How many requests per page?
As we add components and JS modules, how many requests should we make per page before we start to run into performance bottlenecks? A modern web application can have hundreds of components with thousands of dependencies. We know it's not wise to make one request for each JavaScript module required.
Once we get to around 50 requests we'll need to look into a new concatenation and bundling strategy. We can start to concatenate files into groups of related assets. This way when we make a change, only the localized group of assets is affected while other non-related assets can remain cached locally by the browser.
For example we could create one bundle per NPM module or bundle all CSS common layout components together. For those of you using webpack there is a plugin (http2-aggressive-splitting) that can help with this task.
Another thing to bear in mind is that compression is usually more efficient in a few larger files than many small files.
Conclusion
It will take some time for clear best practices to emerge around HTTP/2 asset delivery. We hope this article provides you with some groundwork to help get you started.