Static Site Generation (SSG) in Angular with Angular Internationalization (i18n) and Prerendering

Static Site Generation (SSG) in Angular with Angular Internationalization (i18n) and Prerendering

With the increasing demand for fast, SEO-friendly web applications, Static Site Generation (SSG) has become an essential technique in modern web development. Angular, a powerful framework for building dynamic applications, now supports SSG through Angular Universal. When combined with Angular’s internationalization (i18n) capabilities and the ability to define prerendering paths and hydration, you can create a highly optimized, multi-lingual static site.

This blog will guide you step-by-step on how to implement SSG in an Angular project with i18n, define prerendering paths, enable hydration, and deploy it on Cloudflare Pages.

Table of Contents

  1. What is SSG?
  2. Prerequisites
  3. Step 1: Setting Up an Angular Project
  4. Step 2: Adding Angular Universal for SSG
  5. Step 3: Configuring Angular i18n
  6. Step 4: Adding Prerendering Paths and Hydration
  7. Step 5: Building SSG with i18n
  8. Step 6: Deploying the SSG Build on Cloudflare Pages
  9. Complete Code Sections
  10. Conclusion

What is SSG?

Static Site Generation (SSG) is a technique where web pages are generated at build time. Instead of serving HTML dynamically for each request, pre-rendered static HTML files are served, making your website faster and more scalable.

When combined with i18n, SSG can generate static versions of your site in multiple languages. Adding prerendering paths ensures that all routes in your application are generated as static files, while hydration improves the user experience by making the static content interactive after it has been rendered.

Prerequisites

  • Node.js installed
  • Angular CLI installed (npm install -g @angular/cli)
  • Basic knowledge of Angular

Step 1: Setting Up an Angular Project

First, we need to create a new Angular project. If you already have an existing project, you can skip this step.

ng new angular-ssg-i18n
cd angular-ssg-i18n        

During project setup, Angular will ask if you want to enable Angular routing. Select “Yes” and choose CSS as your preferred style format.

Step 2: Adding Angular Universal for SSG

Angular Universal allows you to render Angular applications on the server. It is a crucial part of setting up SSG.

Add Angular Universal to your project:

ng add @nguniversal/express-engine        

This command configures Angular Universal and sets up an Express server for serving your application.

Step 3: Configuring Angular i18n

Angular’s built-in i18n module helps you support multiple languages within your app. Let’s configure it:

Add translations files:

Create translation files for the languages you want to support. For example:

  • src/locale/messages.en.xlf (for English)
  • src/locale/messages.fr.xlf (for French)

You can extract the default translations using:

ng extract-i18n --output-path src/locale        

This will generate the default messages.xlf file in the specified path.

Configure i18n in angular.json:

Add new configurations for each language in the build section of angular.json:

"build": {
  "configurations": {
    "en": {
      "aot": true,
      "outputPath": "dist/angular-ssg-i18n/en",
      "i18nFile": "src/locale/messages.en.xlf",
      "i18nLocale": "en",
      "i18nMissingTranslation": "warning"
    },
    "fr": {
      "aot": true,
      "outputPath": "dist/angular-ssg-i18n/fr",
      "i18nFile": "src/locale/messages.fr.xlf",
      "i18nLocale": "fr",
      "i18nMissingTranslation": "warning"
    }
  }
}        

Update the App Module:

In your app.module.ts, import LOCALE_ID and provide it dynamically:

import { LOCALE_ID } from '@angular/core';

@NgModule({
  providers: [
    { provide: LOCALE_ID, useValue: 'en' }
  ]
})
export class AppModule { }        

You will change this value dynamically later for different languages.

Step 4: Adding Prerendering Paths and Hydration

To enable Angular’s prerendering capabilities, you need to define which routes to prerender and ensure your application hydrates the static content into a dynamic one.

1. Defining Prerendering Routes:

Update angular.json to specify which routes should be prerendered. In the "prerender" configuration, you can define static routes for each language. Here's an example of how to specify multiple routes:

"architect": {
  "prerender": {
    "options": {
      "routes": [
        "/",
        "/about",
        "/contact"
      ]
    }
  }
}        

You can dynamically specify routes based on the languages and pages you want to prerender.

2. Hydrating the Content:

Angular Universal already handles hydration, where the pre-rendered HTML is enhanced by Angular once JavaScript is fully loaded. However, you need to ensure that lazy-loaded modules are properly handled. Make sure your AppModule and AppComponent are properly set up for hydration.

To improve hydration for dynamic content like forms or dynamic UI components, you can manually trigger rehydration using Angular services after static content has loaded.

For example, if you have a dynamic form or UI component, you can handle it this way:

export class DynamicFormComponent implements OnInit {
  isBrowser: boolean;

  constructor(@Inject(PLATFORM_ID) private platformId: Object) {
    this.isBrowser = isPlatformBrowser(this.platformId);
  }

  ngOnInit(): void {
    if (this.isBrowser) {
      // Dynamic content goes here after hydration
    }
  }
}        

Step 5: Building SSG with i18n

Now that i18n, prerendering paths, and hydration are set up, it’s time to build and generate the static pages.

Create production builds for each locale:

For each language, run the following command:

ng build --configuration=en
ng build --configuration=fr        

Generate server-side rendering builds:

You also need to build the server part of your application:

ng run angular-ssg-i18n:server:production        

Prerender the static content:

Angular provides a command to prerender the application:

npm run prerender        

The prerendering process will generate static HTML files for each route in your application and for each language.

Step 6: Deploying the SSG Build on Cloudflare Pages

Cloudflare Pages is an ideal platform for deploying static sites. Here’s how to deploy your multi-lingual static site generated by Angular with SSG.

Create a new Git repository: First, initialize a Git repository for your Angular project (if not already done):

git init
git add .
git commit -m "Initial commit"        

Push the project to GitHub: Create a repository on GitHub and push your project:

git remote add origin https://github.com/your-username/angular-ssg-i18n.git
git push -u origin master        

Set up Cloudflare Pages:

  • Log in to Cloudflare and navigate to Pages.
  • Click on Create a Project.
  • Select your GitHub repository, angular-ssg-i18n.
  • For the build command, use the following:

npm run prerender        

  • For the output directory, enter the path to your build output. For example:

dist/angular-ssg-i18n        

Customize build settings for each language: If needed, you can create additional deployments for each language (e.g., dist/angular-ssg-i18n/en, dist/angular-ssg-i18n/fr) or configure routing rules in Cloudflare Pages to automatically serve the correct language based on the request’s locale.

Deploy the project: Once everything is set up, click Save and Deploy. Cloudflare will build and deploy your project automatically. Once completed, your static, multi-lingual Angular site will be live!

Complete Code Sections

Here are the final configurations for your key files:

In the angular.json, you should include multiple language configurations and define the prerendering options:

{
  "projects": {
    "angular-ssg-i18n": {
      "architect": {
        "build": {
          "configurations": {
            "en": {
              "aot": true,
              "outputPath": "dist/angular-ssg-i18n/en",
              "i18nFile": "src/locale/messages.en.xlf",
              "i18nLocale": "en",
              "i18nMissingTranslation": "warning"
            },
            "fr": {
              "aot": true,
              "outputPath": "dist/angular-ssg-i18n/fr",
              "i18nFile": "src/locale/messages.fr.xlf",
              "i18nLocale": "fr",
              "i18nMissingTranslation": "warning"
            }
          }
        },
        "prerender": {
          "builder": "@nguniversal/builders:prerender",
          "options": {
            "routes": [
              "/",
              "/about",
              "/contact"
            ]
          }
        }
      }
    }
  }
}        

This setup defines builds for both English and French and configures prerendering for the routes /, /about, and /contact.

app.module.ts

Here’s an updated app.module.ts that supports dynamic locale setting using LOCALE_ID:

import { NgModule, LOCALE_ID } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { registerLocaleData } from '@angular/common';
import localeEn from '@angular/common/locales/en';
import localeFr from '@angular/common/locales/fr';

registerLocaleData(localeEn);
registerLocaleData(localeFr);

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule],
  providers: [
    {
      provide: LOCALE_ID,
      useFactory: () => {
        const defaultLocale = 'en';
        return localStorage.getItem('locale') || defaultLocale;
      }
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}        

In this example, LOCALE_ID is dynamically determined using localStorage or defaults to 'en' if not set.

Dynamic Form Component for Hydration

import { Component, Inject, PLATFORM_ID, OnInit } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';

@Component({
  selector: 'app-dynamic-form',
  templateUrl: './dynamic-form.component.html'
})
export class DynamicFormComponent implements OnInit {
  isBrowser: boolean;

  constructor(@Inject(PLATFORM_ID) private platformId: Object) {
    this.isBrowser = isPlatformBrowser(this.platformId);
  }

  ngOnInit(): void {
    if (this.isBrowser) {
      // Hydrate the static content with dynamic interactions here
      console.log('Hydration complete for dynamic form');
    }
  }
}        

Step 7: Deploying the SSG Build on Cloudflare Pages (continued)

After configuring your prerendered routes, i18n settings, and dynamic content hydration, you are ready to deploy the application to Cloudflare Pages.

Set Build Commands in Cloudflare Pages

When setting up Cloudflare Pages, ensure you use the right build commands for both the server-side rendering and static site generation.

Build Command:

npm run prerender        

Output Directory:

For example, if you’re generating output for English:

dist/angular-ssg-i18n/en        

If deploying multiple locales, create separate deployments or manage them through routing rules on Cloudflare Pages, depending on your deployment strategy.

Conclusion

By following the steps in this article, you can implement Static Site Generation (SSG) in an Angular application with Angular Universal, support multiple languages with Angular’s i18n, and optimize for performance and SEO through prerendering and hydration. Additionally, deploying the final build to Cloudflare Pages allows you to serve a blazing-fast, SEO-friendly website to a global audience.

Stefano Marchisio

?? Sviluppatore web | Programmatore web | Freelance ? Front-end: Angular/TypeScript ? Back-end: ASP.NET MVC CORE C# ? Fullstack Software Engineer

6 个月

Thanks for sharing. ??

要查看或添加评论,请登录

Sehban Alam的更多文章

社区洞察

其他会员也浏览了