How to prerender your Angular app using Angular Universal

Michael De Abreu - Dec 27 '19 - - Dev Community

Angular Universal has always supported prerender, but setting it up was a little difficult. Recently, I was intrigued by 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.

npx -p @angular/cli@next ng new static-app
Enter fullscreen mode Exit fullscreen mode

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.

ng add @nguniversal/express-engine@next
Enter fullscreen mode Exit fullscreen mode

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:

        "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": {}
          }
        }
Enter fullscreen mode Exit fullscreen mode

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

npm run prerender
Enter fullscreen mode Exit fullscreen mode

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

Prerendering 1 route(s) to ~~~\static-app\dist\static-app\browser
CREATE ~~~\static-app\dist\static-app\browser\index.html (27563 bytes)
Enter fullscreen mode Exit fullscreen mode

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.

npx http-server
Enter fullscreen mode Exit fullscreen mode

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.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .