FRONTEND
microservices
Maurizio Lupo (@sithmel)
Requirements:
- optimising rendering perf.
- being efficient in loading common components
- keeping each application independent
Part 1: Javascript
Simplest case:
<div>service 1 markup</div>
<script async src="service1.js"></script>
<div>service 2 markup</div>
<script async src="service2.js"></script>
- in the same page the same code is potentially loaded more than once
- you can't cache the same libraries when navigating across the site
It is inefficient:
Common resources
<script src="common.js"></script>
<div>service 1 markup</div>
<script async src="service1.js"></script>
<div>service 2 markup</div>
<script async src="service2.js"></script>
- optimising rendering performance (we have now a synchronous bundle)
- keeping every application independent one another (what microservice should contain common.js?)
It is not compatible with 2 requirements:
Using async-define
<script async src="common_ad.js"></script>
<div>service 1 markup</div>
<script async src="service1_ad.js"></script>
<script async src="common_ad.js"></script>
<div>service 2 markup</div>
<script async src="service2_ad.js"></script>
- optimising rendering performance (everything is async)
- being efficient in loading common components (common components are factored out)
- keeping every application independent one another (common_ad is downloaded only once because of the browser caching* and executed only once because of async-define).
This restores the 2 requirements:
Loading the same resource multiple times
Most browsers load only once (Chrome IE10, Safari)
If only we had something to remove duplicated resources ...
hint: Compoxure does that
async-define
It is an AMD runner: it manage the execution order of AMD bundles
It can be added in the bundling step, no messing with the source code (plugins for browserify, webpack and rollup).
It adds 0.5 KB to a bundle
Bonus: RESOURCE PRIORITY
<link rel="preload" as="script" href="service1_ad.js" />
<link rel="preload" as="script" href="service2_ad.js" />
<script async src="common_ad.js"></script>
<div>service 1 markup</div>
... long markup with many images
<script async src="service1_ad.js"></script>
<script async src="common_ad.js"></script>
<div>service 2 markup</div>
... long markup with many images
<script async src="service2_ad.js"></script>
PART 2: CSS
SIMPLEST CASE
<link rel="stylesheet" href="service1.css" />
<div>service 1 markup</div>
<link rel="stylesheet" href="service2.css" />
<div>service 2 markup</div>
- in the same page the same code is potentially loaded more than once
- you can't cache the same libraries when navigating across the site
It is inefficient:
SINGLE BUNDLE
<link rel="stylesheet" href="main.css" />
<div>service 1 markup</div>
<div>service 2 markup</div>
It is not compatible with 2 requirements:
- optimising rendering performance (we wait for the second bundle CSS to render the first service)
- keeping every application independent one another
MICRO BUNDLES
<link rel="stylesheet" href="base.css" />
<link rel="stylesheet" href="forms.css" />
<link rel="stylesheet" href="service1.css" />
<div>service 1 markup</div>
<link rel="stylesheet" href="base.css" />
<link rel="stylesheet" href="forms.css" />
<link rel="stylesheet" href="buttons.css" />
<link rel="stylesheet" href="icons.css" />
<link rel="stylesheet" href="service2.css" />
<div>service 2 markup</div>
It looks very verbose but, compoxure spits out this:
<link rel="stylesheet" href="base.css" />
<link rel="stylesheet" href="forms.css" />
<link rel="stylesheet" href="service1.css" />
<div>service 1 markup</div>
<link rel="stylesheet" href="buttons.css" />
<link rel="stylesheet" href="icons.css" />
<link rel="stylesheet" href="service2.css" />
<div>service 2 markup</div>
MICRO BUNDLES
How browsers deal with CSS:*
It only blocks the rendering of the HTML under the CSS
*Chrome is currently being fixed
https://twitter.com/jaffathecake/status/829999531429392385
Bonus 1: RESOURCE PRIORITY
<link rel="preload" as="style" href="icons.css" />
<link rel="stylesheet" href="base.css" />
<link rel="stylesheet" href="forms.css" />
<link rel="stylesheet" href="service1.css" />
<div>service 1 markup</div>
<link rel="stylesheet" href="buttons.css" />
<link rel="stylesheet" href="icons.css" />
<link rel="stylesheet" href="service2.css" />
<div>service 2 markup</div>
Bonus 2: CSS ASYNC*
<link rel="preload" href="icons.css" as="style" onload="this.rel='stylesheet'">
<link rel="stylesheet" href="base.css" />
<link rel="stylesheet" href="forms.css" />
<link rel="stylesheet" href="service1.css" />
<div>service 1 markup</div>
<link rel="stylesheet" href="buttons.css" />
<link rel="stylesheet" href="service2.css" />
<div>service 2 markup</div>
*Requires a polyfill
Bonus 3: SERVER PUSH*
Link: </styles.css>; rel=preload; as=style
*Using HTTP2 CDN
In http header
<link rel="stylesheet" href="/style.css" />
Thanks
Maurizio Lupo (@sithmel)
Frontend microservices
By Maurizio Lupo
Frontend microservices
- 527