How to prerender your Angular app using Angular Universal
Tags: angular, ssr, typescript, tutorial
Published: 2019-12-27 21:43:04

Angular Universal has always supported prerender, but setting it up was a little difficult. Recently, I was intrigued by [Scully](https://github.com/scullyio/scully), a new static site generator on top of regular Angular. It allows you to use Angular in a JAM stack, and I was amazed. It have schematic, allowing to do `ng add @scullyio/init` and it will add everything it needs to do its job. There are a couple of things that I didn't quite like, as for example you can't prerender the main `index.html`. It was created with one goal in mind, and it does that very well, allow you to use Angular in a JAM site.

## Angular to the rescue

As I said before, I try to use Angular Universal to do prerender likely a year ago. It did work, but much of the work had to be done by hand. And as we know, every code we write is likely to have errors. So, it was not as straightforward as it is now with Scully, but it does allow you some better flexibility.

So, I though to myself

> It's been a year since I try that the last time, sure there a new easy way to do it.

Oh! Man, they are. 

## Universal Prerender

We are going to create a new Angular app, so you should have installed the latest LTS version of Node, currently Node 12.14.0. We are going to use `npx` to execute the latest preview version of the Angular CLI, that's until Angular 9 gets released.

```shell
npx -p @angular/cli@next ng new static-app
```

Using that, we are saying to `npx` it should download the latest version of Angular using the `next` tag. Currently, 9-RC.7. Be sure to use routing, and select the style language you prefer. After that, you should have a new ready to go Angular application. Then, we use schematics to add the Angular Universal module in our project.

```shell
ng add @nguniversal/express-engine@next
```

Notice that we are also using the `next` tag here because neither of them is stable yet. If you are like me, you can notice now several modified files since the latest git commit (the one Angular CLI does by default). This even setup some npm scripts now, one of those is `prerender`.


There is only one more thing for you to do to use that command. Open `angular.json`, and go to the new prerender build options, in `projects.[your project name].architect.prerender`. You should see something like this:

```json
        "prerender": {
          "builder": "@nguniversal/builders:prerender",
          "options": {
            "browserTarget": "static-app:build:production",
            "serverTarget": "static-app:server:production",
            "routes": [] // <-- Here you should put the routes you want to prender
          },
          "configurations": {
            "production": {}
          }
        }
```

As the comment said, you have to put the routes you want to render right there. Right now, the application only has one route, so let's use that. Update the `options.routes` to `["/"]`.

Run
```shell
npm run prerender
```

You should see now some buildings and some stuff. But the latest it's the most important part:

```shell
Prerendering 1 route(s) to ~~~\static-app\dist\static-app\browser
CREATE ~~~\static-app\dist\static-app\browser\index.html (27563 bytes)
```

Now, if you go to that folder, you will notice both, an `index.html` file and an `index.original.html` file. The first is the newly created file prerendered, and the later is the original index file of the application. Serve that folder with a static server such as [http-server](https://www.npmjs.com/package/http-server).

```shell
npx http-server
```

Now open that url in a browser, and better if you disable Javascript. You should see the same page that Angular shows by default, but instantly and also if you disable JS, without any usage of JS. This allows site crawlers to see your pages as your user would.

## That's all folks!

I'm going to continue hacking with that but seems promising. I hope you enjoy the reading, and if you want to try it out, let me know in the comments how it went for you.

## PS:

The `prerender` script only worked for me in the latest version of Angular Universal. I don't know if that's going to change, but if it does, I'll update the entry with those changes.