Static site generation with angular
The angular framework allows for static site generation (SSG). This means that the html pages of an application will be generated at build time, or prerendered. This can be very useful to improve SEO and reduce initial page load time of the application.
We‘ll see SSG in action with a sample application. The sample application we will be putting together has two pages: one with a list of products and another page with the details of a product.
Let’s put together the application:
It is possible to add SSG capabilities to an existing application as follows:
ng add @angular/ssr
One can also enable SSG when creating a new application with the CLI:
ng new myApp
...
? Do you want to enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)? (y/N)
Our application relies on dynamic routes:
export const routes: Routes = [
{
path: '',
pathMatch: 'full',
redirectTo: 'products'
},
{
path: 'products', component: ProductsComponent
},
{
path: 'products/:productId', component: ProductComponent // Relies on routes.txt for SSG
}
];
Angular therefore requires us to use a text file that contains all the actual routes:
from routes.txt
/products/1
/products/2
/products/3
It is configured in the angular.json
build options as follows:
"prerender": {
"routesFile": "routes.txt"
}
We’ll use a mock backend (json-server)
as an API; For the sake of completeness, here is the data returned from our API:
"products": [
{
"id": 1,
"name": "Silver plates set",
"description": "Beautiful set of silver plates"
},
{
"id": 2,
"name": "Wooden chair",
"description": "Art-deco wooden chair"
},
{
"id": 3,
"name": "Flower vase",
"description": "China flower vase"
}
]
In order to build the application, we’ll need the backend running. Let’s start the backend:
json-server --watch db.json
> static-site-generation-demo-ng@0.0.0 start:backend
> json-server --watch db.json
\{^_^}/ hi!
Loading db.json
Done
Resources
http://localhost:3000/products
Home
http://localhost:3000
Type s + enter at any time to create a snapshot of the database
Watching...
Now, we can build the application:
➜ static-site-generation-demo-ng git:(master) ✗ npm run build
> static-site-generation-demo-ng@0.0.0 build
> ng build
Initial chunk files | Names | Raw size | Estimated transfer size
main-EJWDCKVZ.js | main | 229.06 kB | 62.04 kB
polyfills-FFHMD2TL.js | polyfills | 34.52 kB | 11.28 kB
styles-5INURTSO.css | styles | 0 bytes | 0 bytes
| Initial total | 263.58 kB | 73.32 kB
Prerendered 5 static routes.
Application bundle generation complete. [2.720 seconds]
The 5 static routes mentioned above are:
- the home page route
- the products list route
- the 3 product detail routes
We can notice from the backend console, that data was requested by the angular build:
\{^_^}/ hi!
Loading db.json
Done
Resources
http://localhost:3000/products
Home
http://localhost:3000
Type s + enter at any time to create a snapshot of the database
Watching...
GET /products 200 6.299 ms - 290
GET /products 200 3.882 ms - 290
GET /products/2 200 2.942 ms - 81
GET /products/3 200 4.356 ms - 76
GET /products/1 200 4.697 ms - 95
GET /products 200 3.009 ms - 290
Here are the contents of the dist
directory after the build:
├── dist
│ └── static-site-generation-demo-ng
│ ├── 3rdpartylicenses.txt
│ ├── browser
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── main-EJWDCKVZ.js
│ │ ├── polyfills-FFHMD2TL.js
│ │ ├── products
│ │ │ ├── 1
│ │ │ │ └── index.html
│ │ │ ├── 2
│ │ │ │ └── index.html
│ │ │ ├── 3
│ │ │ │ └── index.html
│ │ │ └── index.html
│ │ └── styles-5INURTSO.css
│ └── prerendered-routes.json
It is possible to check that all of the index.html
pages contain the data from our backend.
Let’s now start the application with npm start
, then open http://localhost:4200/products/1
and inspect the Chrome devtools:

We notice that the ressource served is of type document and that product data is indeed present within the html. Subsequent requests will actually be of type Fetch/XHR.
We have seen that angular offers interesting capabilities for prerendering the html pages of an application. One important limitation though, is the need to provide the routes.txt
file with the hard-coded routes. This is in contrast with other frameworks such as next.js which allows for dynamic generation of the routes configuration.
Related links and resources:
- https://angular.dev/guide/prerendering (official documentation about angular prerendering)
- https://github.com/balteo/static-site-generation-demo-ng (full code source for above sample)