AngularChef
AngularChef

Reputation: 14077

How to pre-render pages in static HTML for an Angular app?

WHAT: I am building a website with Angular and I’d like to deploy it on a purely static server (such as Amazon S3). I need to pre-render all HTML pages for the site before deployment and I’m not sure how to proceed.

HOW: My current idea is to have some crawler read a file like sitemap.xml to retrieve a list of all the site’s URLs, then send requests for these URLs to a server where Node.js is installed and an instance of my Angular (Universal) app is running.

QUESTION: Does it sound like the proper way to do it? Am I missing an important step? Are there any libraries or npm packages that could help in this task?

Surprisingly, I couldn’t find any documentation about pre-rendering for Angular (only RE-rendering). I’ve also looked at static site generators for inspiration, but they all use a bunch of static files as their starting point (NOT a list of URLs). Also, I don't want to use a third-party service like prerender.io.

Upvotes: 12

Views: 7275

Answers (2)

Nirav Ghodadra
Nirav Ghodadra

Reputation: 352

I have done the similar task in Angular 13. First change your angular.json file as

  "prerender": {
      "builder": "@nguniversal/builders:prerender",
      "options": {
        "browserTarget": "my-app:build:build",
        "serverTarget": "my-app:server:server",
        "routes": [
          "/"
        ],
        "guessRoutes": false
      },
      "configurations": {
        "production": {
          "browserTarget": "my-app:build:production",
          "serverTarget": "my-app:server:production"
        },
        "staging": {
          "browserTarget": "my-app:build:staging",
          "serverTarget": "my-app:server:staging"
        }
      },
      "defaultConfiguration": "production"
    }

I have passed specific routes to the prerender command. If you choose this option, make sure to turn off the guessRoutes option.

In package.json in scripts add build command like this:

"build:prod": "ng build --configuration production --aot && ng run my-app:prerender:production --no-guess-routes --routes /",
"build:staging": "ng build --configuration staging --aot && ng run my-app:prerender:staging --no-guess-routes --routes / ",

As SSR is done at runtime it will take some time to render the HTML page on the fly but Pre-rendering directly serve the pre-rendered HTML page on request. So basically it'll improve the performance even better than SSR.

Upvotes: 1

I've just completed similar task using Angular 4. Site is hosted using Github pages and has no backend. Feel free to use it as example: repo and commit which implements pre-rendering: 0d81d28

I had to implement following changes:

  • Create server app module and update browser app module as described in angular universal guide
  • Implement pre-renderer script. Pre-renderer inspects router configuration and retrieve available app routes.
  • For each URL pre-render generates html file using renderModuleFactory from @angular/platform-server module and saves generated html in appropriate location.
  • As Bhargav mentioned static files server won't support any URL. So if you need to have URL like /community/overview then html should be saved into /community/overview/index.html. Angular matrix params wan't work :( . I had to move matrix params into URL route e.g. instead of /docs;doc=overview.html use /docs/overview.html
  • In order to fix annoying flickering after page loading, add initialNavigation: 'enabled' into router configuration: RouterModule.forRoot([{ path: '', ...}], { initialNavigation: 'enabled' }). I still have no idea what initialNavigation is and why it helps.

Hope this helps.

Upvotes: 6

Related Questions