Server side rendering via Angular Universal
A normal Angular application executes in the browser, rendering pages in the DOM in response to user actions. Angular Universal executes on the server, generating static application pages that later get bootstrapped on the client. This means that the application generally renders more quickly, giving users a chance to view the application layout before it becomes fully interactive. This technique is popularly known as “Server-side rendering” (SSR).
Why use Server-side rendering
There are three main reasons to create a Universal version of your app.
- Facilitate web crawlers through search engine optimization (SEO)
- Improve performance on mobile and low-powered devices
- Show the first page quickly with a first-contentful paint (FCP)
How it works?
A Universal web server (this guide is based on the popular Express framework) responds to application page requests with static HTML rendered by the Universal template engine. The server receives and responds to HTTP requests from clients (usually browsers), and serves static assets such as scripts, CSS, and images. It may respond to data requests, either directly or as a proxy to a separate data server.
What we are trying to solve here?
Serving web app involves serving in-app static assets via web server. While this is a standard process, this puts up burden on the web server.
These static assets such as scripts, CSS, and images can be served better via AWS S3 with caching and compression enabled.
How we can solve it?
Step 1: Move static assets to AWS S3
We can achieve this in many ways but to support CI/CD pipeline, we can modify in the pipeline for moving browser directory to AWS S3. (Note: Usually the browser directory is a distribution folder that gets generated after successful completion of the Angular Universal build).
Please checkout here about Deploying Static Web Applications using AWS S3
Step 2: Update the behaviour setting in AWS CloudFront
Amazon CloudFront is a fast content delivery network (CDN) service that securely delivers data, videos, applications, and APIs to customers globally with low latency, high transfer speeds, all within a developer-friendly environment. It helps in speeding up the distribution of our static and dynamic web content to users. It stores a cached copy of your static site around the world, delivering it to your users from the nearest location to reduce latency. We can behaviours where we can specify the conditions to sever the different type of request from different origins (S3, Node server, etc)
In the above image shows that static resource requests like JS, CSS, Images and other resources from assets folders are served from S3, any other application routes are be served from web server.
What are all the challenges with this approach?
When we serve the static files through Cloud Front + S3 (with cache enabled), there might be an issue that the latest contents are not reflecting if your application referring to any file (which is not versioned).
We can solve this issue using any one of the following ways
1. Use version (like settings_v1.json) in your custom configuration files so that it won’t be cached but always served with latest content.
2. Also we can use cache-busting techniques like using query params with application version (ie setting.json?cb=1.0.2) or enable hashing technique feature in the angular.json.
What we achieved?
Reduced load on web server
We reduced load on web server upto 90%. Only the application routes are served with web server and all other static resources are served from S3.
Enable cache & compression to the static resources
The first time a browser loads a web page, it stores the page resources in the HTTP Cache. The next time the browser hits that page, it can look in the cache for resources that were previously fetched and retrieve them from disk, often faster than it can download them from the network.
The browser issues a request to the server for this file, the server returns the file and also tells the browser to cache it for 30 days. we can make it the CloudFront behaviour for all the static resources like JS, CSS and images as shown in the below.
Using static files compression sometimes really helps to improve your web performance. which can significantly reduce the amount of time to download the resource, reduce data usage for the client, and improve the time to first render of your pages.
CloudFront currently support both gzip as well as Brotli compression techniques to text-based content files like js, css, svg and json etc. Brotli is a compression algorithm, developed by Google and serves best for text compression.
- HTML files are 21% smaller than gzip.
- CSS files are 17% smaller than gzip.
Reducing load on web server also helped us saving cost by reducing the no of instances hosting our web servers (from c5.large with count of 5 to t2.medium with count 3).
Without any doubt this approach definitely help you to reduce the load on the web server and generally caching and compression for the static resources of a website can largely solve the long TTFB we had in our SSR website and at the same time without sacrificing SEO performance. Besides, the price of hosting our website on AWS S3 with CloudFront is relatively low.