The Angular Application Builder pre-renders an Angular project, but is designed for deployment with a backend. By default, all requests run via server.mjs, which runs in the backend via Node. In order to be able to use the Application Builder for a deployment with only the pre-rendered files, a few things have to be taken into account.

The project is pre-rendered with the ng build command. The pre-rendered files can be found in the dist/projectname/browser/ directory. The Application Builder has created a separate directory for each route, which has the name of the route and contains an index.html. If you start an HTTP server in this directory, you can already test the pre-rendered page.

The trailing slash problem

Without further adjustments, you will encounter a problem in the network tab of the developer tools: When you call up the page, a redirect occurs. The request is made without a slash at the end of the URL and is then redirected to the URL with a trailing slash.

302 Redirect

The reason for this is that the HTTP server is looking for a file but finds a directory. When requesting domain.de/legal-notice, the HTTP server tries to find the file domain.de/legal-notice.html. Since this file does not exist, the redirection to domain.de/legal-notice/index.html occurs. To prevent the redirection, the URL domain.de/legal-notice/ should be called directly.

Now the problem remains that Angular changes the URL to domain.de/legal-notice after calling domain.de/legal-notice/. This leads again to the problem with the redirection when reloading the page. The following script in main.ts prevents Angular from removing the trailing slash:

import { Location } from "@angular/common";
import { bootstrapApplication } from "@angular/platform-browser";
import { AppComponent } from "./app/app.component";
import { appConfig } from "./app/app.config";

bootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err));

// Enables navigation with TralingSlash without removing it
const __stripTrailingSlash = (Location as any).stripTrailingSlash;
(Location as any).stripTrailingSlash = function _stripTrailingSlash(url: string): string {
  // Split the URL into two parts: the path before the question mark and the query string after the question mark
  const queryString$ = url.match(/([^?]*)?(.*)/);

  if (queryString$ && queryString$[2].length > 0) {
    // Check if the path (before the query string) ends with a slash
    // If so, add a dot before the query string
    // Otherwise, call the original stripTrailingSlash method
    return /[^\/]\/$/.test(queryString$[1]) ? queryString$[1] + "." + queryString$[2] : __stripTrailingSlash(url);
  }

  // If no query string exists or it is empty
  // Check if URL ends with slash and add dot
  // Otherwise, call the original stripTrailingSlash method
  return /[^\/]\/$/.test(url) ? url + "." : __stripTrailingSlash(url);
};

All route paths in Angular must have a trailing slash, followed by a dot.

export const routes: Routes = [
  { path: "", loadComponent: () => import("./routes/home/home.component").then((m) => m.HomeComponent) },
  { path: "legal-notice/.", loadComponent: () => import("./routes/legal-notice/legal-notice.component").then((m) => m.LegalNoticeComponent) },
  { path: "legal-notice", loadComponent: () => import("./routes/legal-notice/legal-notice.component").then((m) => m.LegalNoticeComponent) },
];

The call must also end with a period:

<a routerLink="/legal-notice/.">legal-notice</a>

Testing the pre-rendered page

The pre-rendered page should be tested before deployment.

Change to the directory

cd dist/projektname/browser

Starting the HTTP server

http-server

Deployment on GitHub Pages

The directory dist/projectname/browser/ must be uploaded to GitHub Pages. This can be done either manually or with the help of angular-cli-ghpages.

The deployment is just one command:

npx angular-cli-ghpages --dir=dist/projektname/browser --cname=domain.com