Prerender Angular Apps with a single Command

Static websites are getting a lot of attention lately. GatsbyJS is probably the most prominent static site generator right now. It is based on React which is of course fine if you consider yourself a React developer. Unfortunately there is no readymade alternative in the Angular ecosystem. However building a static site with Angular's built-in features isn't hard and this post is about a tool which aims to make it even easier.

With the help of Angular Universal, the schematics that come with the Angular CLI and some scripting it is possible to turn an Angular app into a static website which works much like GatsbyJS for Angular.

Static sites in general have a lot of advantages: They can easily be deployed on any static hosting service. They can be indexed by any search engine. And static sites can skip at least one roundtrip to speed up the page load when compared to traditional single page apps. There are a lot more advantages but as you are reading this post, you are most likely already convinced that delivering a static site is a good idea. The main point is that this can all be achieved while keeping a lot of Angular's flexibility and composability. In the end a static site can even work without JavaScript but turns into a lively Angular app when it is available.

Nowerdays the Angular CLI makes it very easy to create a universal version of an existing app. Only one command is necessary. Let's say you have an app which is called "universe" then this will be the command in question.

ng generate universal --client-project universe

This will add a new target to your angular.json file which allows you to build the app for server side usage. To kick off the build just run:

ng run universe:server

Now all the building blocks are available to prerender the routes of the app. Usually this is solved by creating a script which needs to be customized for every app to fit the needs. This script will contain a dummy server implementation which will then be called for each route to prerender it. This is often the part where it gets a little hairy.

angular-prerender is meant to replace that custom script with a configurable command with sensible defaults. In many cases running angular-prerender without any arguments should just work.

npx angular-prerender

This command will take the output of the server side build process and uses it to create a static version of each of the routes. This static version gets merged with the client side build. Afterwards the client side build folder can be deployed as usual.

angular-prerender uses the guess-parser to retrieve the routes of an app. Oftentimes such routes will have a dynamic part. Imagine the "universe" app that was used earlier contains a route to display details about galaxies.

/galaxies/:galaxy

This route contains a parameter and therefore it is not possible for angular-prerender to render this route without any additional information. It needs to know what values the :galaxy parameter may possibly have. Those values can be handed over as a JSON object.

npx angular-prerender --parameter-values '{":galaxy":["andromeda","milky-way"]}'

This will render two routes. One for each parameter value.

/galaxies/andromeda
/galaxies/milky-way

Of course this isn't a technique which works for every app. If you are trying to build a static version of an Amazon sized online shop this is going to be very inefficient. Nevertheless I think it makes sense for many apps to prerender a static version. It remains to be a case-by-case decision.

angular-prerender is very young and therefore any feedback is very welcome. I'm curious if it proves to be useful for somebody else. Please head over to GitHub to report a bug or request a feature.