How to pre-render Dynamic Routes in Angular: A Practical Guide

Explore how to pre-render pages with dynamic parameters (e.g., /products/:id) in Angular. You'll learn how to use the getPrerenderParams function to inform the Angular build process about all the dynamic routes that need to be generated into static HTML files.

How to pre-render Dynamic Routes in Angular: A Practical Guide
How to pre-render Dynamic Routes in Angular: A Practical Guide

Angular's Server-Side Rendering (SSR) is a powerful tool for creating fast, SEO-friendly applications. However, for content that rarely changes—like blog posts, product pages, or newsletters—running a full rendering cycle for every user visit can be inefficient, costing you server resources and money.

What if you could generate the static HTML for these pages just once, at build time? This is where pre-rendering shines. In this guide, we'll explore how to leverage Angular's pre-rendering capabilities, specifically for dynamic routes, using the getPrerenderParams function.

SSR vs. Pre-rendering: What's the Difference?

Before diving in, it's essential to understand the distinction between Server-Side Rendering (SSR) and pre-rendering (also known as Static Site Generation or SSG).

  • Server-Side Rendering (SSR): The HTML for a page is generated on the server in response to a user request. This is ideal for highly dynamic content that changes frequently for each user.
  • Pre-rendering (SSG): The HTML for pages is generated once, at build time. The server then simply serves these pre-built static files, which is incredibly fast and efficient for content that doesn't change often.

Here's a diagram illustrating the flow of each approach:

For static or semi-static content, pre-rendering is the clear winner for performance and cost-efficiency. The challenge, however, arises when dealing with dynamic routes, such as products/:id.

The Challenge: Pre-rendering Dynamic Routes

How can the build process possibly know all the potential product IDs to generate pages for? It can't—unless you tell it. This is precisely the problem that the getPrerenderParams function solves.

The Solution: getPrerenderParams

The getPrerenderParams function is a configuration option in Angular's server routes that allows you to provide a list of parameters for your dynamic routes. During the build process, Angular will execute this function, retrieve the list of parameters, and generate a static HTML file for each one.

Step-by-Step Guide to Pre-rendering Dynamic Routes

Let's walk through setting up a project to pre-render individual product detail pages.

1. Project Setup

First, get the starter project ready. Clone the repository and check out the starting branch.

# Clone the repository
git clone https://github.com/AhsanAyaz/ng-v20-ssr-defer-hydration.git 

# Navigate into the project directory
cd <project_directory>

# Checkout the starting branch for the tutorial
git checkout prerender-params-start

# Install dependencies
npm install

# Run the development server
npm start

The application should now be running on http://localhost:4200.

2. Create the Components


// creating a component
ng g c components/product-card

// creating a route
ng g c product-details

3. Configure the Routes

We need to configure our server routes to handle pre-rendering for our product detail pages. This is done in the app.routes.server.ts file.

Here's how to set it up:

  1. Define the Dynamic Route: Specify the path with its dynamic parameter (e.g., 'products/:id').
  2. Set the Render Mode: Set renderMode to RenderMode.Prerender.
  3. Implement getPrerenderParams: This is where the magic happens. This async function will fetch all the necessary data and return the parameters for the routes you want to pre-render.
  4. Set a Fallback: It's good practice to define a fallback strategy for any dynamic routes that might not be in your pre-rendered list. Setting it to PrerenderFallback.Client will make the app fall back to standard Client-Side Rendering (CSR) for those routes.

Here is the complete code for app.routes.server.ts:

// src/app.routes.server.ts

import { renderModule } from '@angular/platform-server';
import { ServerRoute, RenderMode, PrerenderFallback } from '@angular/ssr';
import { Routes } from '@angular/router';
import { Products } from './services/products'; // Your product service
import { inject } from '@angular/core';

export const serverRoutes: ServerRoute[] = [
  {
    path: 'products/:id',
    renderMode: RenderMode.Prerender,
    fallback: PrerenderFallback.Client, // Fallback to CSR if not pre-rendered
    async getPrerenderParams() {
      // Inject the service to fetch data
      const productsService = inject(Products);

      // Fetch the products. Use an HTTP client for real-world scenarios.
      const productIds = await productsService.getProductsForPrerendering();

      // Log the IDs to see it working during the build
      console.log({ productIds });

      return productIds; // e.g., returns [{ id: '1' }, { id: '2' }, ...]
    },
  },
  {
    path: '**',
    renderMode: RenderMode.Server,
  },
];

4. Build and Verify

Now, run the build command:

ng build

During the build process, you will see the console.log from your getPrerenderParams function in the terminal, confirming that it fetched the product IDs.

Once the build is complete, run the production server:

node ./dist/ng-v20-demo-app/server/server.mjs

Navigate to http://localhost:4000/products/1 (or any valid product ID).

To verify that it's working:

  • View Page Source: Right-click on the page and select "View Page Source." You will see the fully-rendered HTML content, not just the <app-root></app-root> placeholder. This is excellent for SEO crawlers.
  • Check the Network Tab: Open your browser's developer tools, go to the Network tab (filter by Fetch/XHR), and refresh the page. You'll notice that no network request is made to fetch the product data because it's already embedded in the initial HTML document.

Conclusion

By using getPrerenderParams, you can efficiently pre-render pages for dynamic routes in Angular, combining the raw performance of a static site with the flexibility of a dynamic application. This approach is perfect for content-heavy sites, leading to:

  • Blazing-Fast Load Times: Serving static HTML is significantly faster than rendering on demand.
  • Improved SEO: Search engines can easily crawl and index your fully rendered content.
  • Reduced Server Costs: You minimize server computation by generating pages only once at build time.

For any developer working with static or semi-static content on dynamic routes, mastering pre-rendering is a game-changer for building high-performance Angular applications.


I hope you find these helpful. If you do, please share our blog with others so they can join our amazing community on WhatsApp (link below)

Code with Ahsan
WhatsApp Group Invite

Don't miss out – join our awesome community to grow as a tech enthusiast, and to help others grow.
As always, Happy coding ❤️