You’ve got your SPA, consisting of static CSS, HTML and JS, and high-performing microservices to provide the dynamic behavior of your app. The only thing remaining is hosting the static content somewhere, point a DNS to it, and call it a day.
However, it turns out that your app needs a top menu, which is shared between all the apps in the organization, to provide a common look-and-feel and navigation. All of a sudden you’re pushed into the world of content transclusion, now loosely referred to as micro frontends
6 min read
By Jørn Ola Birkeland
December 3, 2019
Logically, this is how your index.html should look:
<html> <head> <link href=“your_app_style.css” rel=“stylesheet”/> <!-- menu css and js references go here -—> </head> <body> <!-- menu html goes here --> <div class=“your_app_container/> <script src="your_app_behaviour.js"></script> </body> </html>
The menu content (html, css, and js) is provided as a service maintained by some other team, and editors are adjusting the content every now and then. In other words, it is almost static, but not quite. The menu editors want changes to propagate quickly across all apps, as and when it happens. So what to do?
A few options are available to you as a developer, typically variations of server-side includes (SSI) and client-side includes (CSI) techniques:
AWS offers a CDN service called CloudFront, which caches static content closer to the clients, whereby offloading the origin web server and improving response times. July 2017 it became possible to run a piece of code when CloudFront receives a request or returns a response. More precisely, CloudFront offers four events that can trigger your code:
The menu problem is a good use case for Lambda@Edge. At first glance, it seems it would be a good choice to latch on to the response from the origin web server, and decorate the html before it is cached and returned to the client. However, response triggers aren't able to access the response body or provide a generated body of any kind. The next best thing is to trigger your lambda function before the request is forwarded to the origin web server because of a cache miss. The steps you need to implement, are:
The final piece in the puzzle is to configure CloudFront to access your static content and then trigger your code with the right event. Using the web console of AWS Lambda, it should look something like this:
and then click “+ Add trigger”, select “CloudFront”, and click “Deploy to Lambda@Edge”:
You need to select your CloudFront distribution and event, before clicking “Deploy”.
So what have we gained? First, our static content can be hosted as such, for example in an AWS S3 bucket (set up as a static website), and deployed by a simple directory synch operation. No complex CD pipelines or dedicated web servers are required. Second, in case of a failure during transclusion, CloudFront will continue to serve the previously cached index.html. So a temporarily unavailable menu service will not impact the end-user. Third, the performance penalty is only paid occasionally by a single user (within a CDN region), and a small lambda execution timeout value will cause a relatively quick failure, resulting in the cached index.html being returned. Fourth, the lambda function decorating the index.html can be shared by all apps (provided they are authorised to do so), maintained in one place, all the while scaling is handled for you.
Finally, leveraging a CDN for static content is A Good Thing, and should reduce the cost of serving your files, while simultaneously improving the end-user experience. As an additional benefit, if you are building immutable web apps (which you should) - and therefore getting new file names with each build - serving them through a CDN will keep the files of previous versions available for a while. The slim chance that a client with an old index.html will request unavailable files, is avoided.
There are a couple of drawbacks, of course: Getting your lambda function to work correctly can be a bit of trial and error with somewhat limited debugging possibilities. Also, index.html is cached for a certain time period (decided by you). A new deployment of your app will not be immediately available to new clients. A cache invalidation request to CloudFront may take a few minutes, so in the odd case you need to be able to rapidly make a new version of your index.html available, using a CDN in front of it may be the wrong thing to do. For everybody else, it is definitely a tool to have in your toolbox.