AngularAngular est un framework de développement JavaScript populaire basé sur TypeScript., c'est l'un des framework JavaScriptLangage de scripting orienté objet les plus utilisés en 2025. Et on comprend vite pourquoi ! Mais imaginez la scène : vous développez votre site, vous le mettez en ligne… et là, mauvaise surprise : impossible de le trouver facilement sur Google. Rassurez-vous, ce n'est pas (forcément) de votre faute ! Angular regorge de qualités, mais il n'a pas été conçu à l'origine pour briller en référencement naturel (SEO). Heureusement, les équipes d'Angular ont anticipé le problème et proposent aujourd'hui plusieurs solutions pour rendre vos applications bien plus visibles sur les moteurs de recherche. On vous explique tout !
Sans rentrer dans le détail, pour que votre site soit bien référencé sur les moteurs de recherche, il faut que le code HTML soit bien rempli, mais surtout performant et rapide à charger. Malheureusement, une application Angular ne coche pas beaucoup de ces cases…
A quoi ca ressemble une application AngularAngular est un framework de développement JavaScript populaire basé sur TypeScript. basique, vu par un moteur de recherche ? Eh bien, pas grand chose. Une page vide. Si vous affichez le code source de la page de votre site, vous verrez quelque chose ressemblant à ceci :
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Mon super site Angular !</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/png" href="favicon.png">
<link rel="stylesheet" href="styles.css">
</head>
<body>
<app-root></app-root>
<script src="runtime.js" type="module"></script>
<script src="polyfills.js" type="module"></script>
<script src="styles.js" defer></script>
<script src="scripts.js" defer></script>
<script src="vendor.js" type="module"></script>
<script src="main.js" type="module"></script>
</body>
</html>
Un HTML vierge de tout contenu, qui ne fait qu'appeler vos fichiers CSSFeuilles de style qui permettent de mettre en forme des pages web. et JS. Et c'est le chargement de ces fichiers JS qui vont remplir ensuite votre HTMLHTML (HyperText Markup Language) est un langage permettant de décrire le découpage d'une page web. pour y ajouter du contenu. Sauf qu'un moteur de recherche n'exécute pas les fichiers JS, il regarde seulement le HTML !
Et niveau performance, on n'y est pas trop. Quand un utilisateur veut accéder à votre site, il doit :
Cela fait un grand nombre d'étapes, dépendante de beaucoup de facteurs (performance du serveur où est hébergé votre front, réseau de l'utilisateur, performance de votre API, performance de la machine de l'utilisateur).
Pour remédier à ce problème, Angular a sorti initialement la librairie Angular Universal. Cette librairie a pour mission de proposer des fonctionnalités de SSR et de Prerendering.
Petit point définition avant de continuer :
Ces 2 méthodes ont pour but de faire en sorte que l'utilisateur (ainsi que les moteurs de recherche), aient directement un fichier HTML rempli avec les informations de la page qu'ils ont demandé. La seule différence et que l'un génère à la volée (SSR), alors que l'autre génère une seule fois pour tout le site (Prerendering).
Depuis Angular 17, la librairie Angular Universal est devenu obsolète, car ces deux fonctionnalités sont maintenant disponible nativement dans Angular !
Dans la suite de cet article, nous nous concentreront principalement sur le Prerendering.
Pour ajouter le module de prerender à une application existante, un simple ng add suffit :
ng add @angular/ssr
Pour l'incorporer dès la création d'un projet, il suffit de rajouter l'option - - ssr :
ng new --ssr
Une fois ajouté, vous remarquerez que certains fichiers de config ont été changé et des fichiers *.server.ts ont été créé. La commande ng build
a également un nouveau comportement. Elle va désormais faire un prerender à la place d'un build classique.
Par défaut, Angular va essayer de deviner toutes les routes qu'il doit prerender, en fonction de ce qui est présent dans les fichiers de routing.
Apres un build, vous allez maintenant générer un fichier html pour chacune de vos pages. Chacun de ces fichiers HTML contiendra l'entièreté de la page, telle qu'elle aurait été généré par Angular lorsqu'un client accède à votre site.
Build classique : Un fichier html vide comportant seulement un lien vers les fichiers JS, qui s'occuperont de charger Angular, et afficher les composants nécessaire suivant l'url où l'on se situe.
Build avec prerender : Un fichier index.html pour chacune des URLUniform Ressource Locator, chacun ayant déjà le DOM rempli comme si on avait déjà chargé Angular et tous les composants.
Exemple avec un projet vide comportant la starting page d'Angular :
Il faut également bien penser à parametrer son NGINX, de façon à ce qu'il aille chercher le fichier index.html correspondant à notre URL, et non plus le fichier index.html présent à la racine. Mettre à jour la location
comme suit :
location / {
try_files $uri/index.html $uri /index.html;
}
On essaie d'aller chercher le html de la page demandée, ou on prend celui présent de base à la racine, qui correspond à un build classique.
Prenons un exemple concret : la page http://mon-super-site-prerender.com/article/276
Si tout s'est bien passé lors du déploiement, cet article a déjà été pré-rendu (prerender). Il existe donc un fichier index.html
dans le dossier /dist/my-app/browser/article/276/index.html
.
Grâce à un serveur Nginx correctement configuré, ce fichier HTML est directement renvoyé au navigateur. Résultat :
Mais côté utilisateur, les choses ne s'arrêtent pas là. Plusieurs actions se déroulent en parallèle :
index.html
;Mais alors, dans quel cas Angular pourrait-il détecter une différence ? Cela signifie-t-il qu'il y a eu une erreur pendant le prerender ? Pas du tout !
Imaginons que notre article n°276 ait été prerender à minuit, avec un prix affiché de 100 €.\nÀ 10h30, le prix passe à 80 €. Le fichier HTML contient donc encore l'ancienne valeur.\nLorsque l'application Angular se charge, elle détecte cette différence et met à jour le prix affiché côté utilisateur.
Cependant, les moteurs de recherche, eux, ne voient que le HTML prerender et n'exécutent pas le code Angular. Ils continueront donc d'indexer le prix à 100 €.
Il est donc essentiel d'effectuer des prerenders réguliers afin de conserver un HTML à jour et cohérent avec les données réelles.
Plus l'application est grosse, plus il peut devenir compliqué d'ajouter le prerendering. Certaines librairie peuvent ne pas être compatibles avec ce dernier.
Il est possible de dire à Angular quelles pages il doit prerender, plutot que de le laisser deviner vos pages.
Pour cela, modifier comme il suit le fichier angular.json
:
"prerender": {
"options": {
[...]
"routesFile": "./routes.txt",
"discoverRoutes": false
}
}
Puis créer un fichier routes.txt
à la racine du projet et renseigner chacune des pages à générer. Exemple de fichier :
/home
/contact
/mentions-legal
/articles
/article/1
/article/2
/article/3
On peut également pousser le mécanisme plus loin en créant un petit code Typescript qui s'exécute avant le build (un "prebuild"). Ce dernier va appeler notre APIUne API est un programme permettant à deux applications distinctes de communiquer entre elles et d’échanger des données. pour qu'elle nous renvoie le fichier .txt avec toutes les routes de l'application, selon les articles que l'on a en BDD.
Exemple d'implémentation :
L'étape prebuild
définie dans package.json
sera lancé automatiquement lorsque l'on fera un build et exécutera le fichier generate-routes-txt.ts
:
{
"name": "my-app",
"version": "0.0.1",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"prebuild": "ts-node ./generate-routes-txt.ts",
}
}
Le fichier generate-routes-txt.ts
permettant de récupérer les routes depuis l'API :
downloadFile('./routes.txt', 'http://mon-api.com/generate-routes')
function downloadFile(dest: string, path: string){
const http = require('http')
const fs = require('fs')
const file = fs.createWriteStream(dest);
http
.get(
path,
function (response: any) {
response.pipe(file)
file.on('finish', function () {
file.close()
})
},
)
.on('error', function (err: Error) {
fs.unlink(dest)
})
}
On peut imaginer faire le même appel à downloadFile()
mais pour cette fois demander à notre api de générer le sitemap du site, utile pour les moteurs de recherche.
Afin d'éviter des désynchro entre ce qui est prérender et ce qui est présent en BDD, il peut être envisagé de ne pas prérender certains éléments des pages. Par exemple, si on veut ignorer la balise <div>{{ price }}</div>
qui comporte le prix des articles, on peut la conditionner comme suit :
<div *ngIf="isBrowser">{{ price }}</div>
import {Component, Inject, PLATFORM_ID} from '@angular/core';
import {isPlatformBrowser} from "@angular/common";
@Component({
selector: 'my-component',
templateUrl: './my-component.html',
styleUrls: ['./my-component.scss']
})
export class MyComponent {
isBrowser = false;
price = 100; // Price should be fetched from the API
constructor(
@Inject(PLATFORM_ID) platformId: Object
) {
this.isBrowser = isPlatformBrowser(platformId);
}
}
isBroswer
sera vrai lorsqu'un utilisateur accèdera au site, mais faux lors du build qui fera le prerender.
Le prix ne sera donc pas présent lors du prerender, mais affiché lorsqu'un utilisateur accèdera au site.
Le prerender s'execute sur un serveur, et non pas sur un navigateur.
De ce fait, si lors du prerender d'une page, votre code (ou une de vos librairie) fait appel à des éléments du navigateur tel que window
ou document
, le prerender va planter et vous obtendrez le message d'erreur suivant : ERROR ReferenceError: window is not defined
. Essayez de refacto votre code pour ne pas faire ces appels, ou conditionnez les de façon à ce qu'ils ne s'exécutent pas lors du prerender (voir juste au dessus comment faire).
Il est possible que certaines librairies fassent planter un composant lors de son hydration (mise à jour), car elles ne sont pas forcément compatible avec ce genre de mise à jour du DOM.
Il est possible de forcer la reconstruction complète du composant plutôt que la mise à jour de ses éléments, grâce à l'attribut html ngSkipHydration
.
Voir la doc complète ici.
Si votre application implémente le système de Service Worker, faites bien attention à la configuration de ce dernier. Un prerender complet, suivant la taille du site, peut facilement faire jusqu'à plusieurs centaines de mo. Vous ne voudriez pas que chaque utilisateur qui arrive sur votre site mette en cache l'entièreté de toutes les pages que vous avez prerender.
Il est plutôt recommandé de mettre en cache les fichier prerender seulement lorsque l'utilisateur cherche à y accéder, voir à les ignorer.
Le prerendering est un excellent moyen de permettre aux moteurs de recherche de découvrir et d'indexer efficacement votre site Angular. Mais attention : ce n'est pas une solution magique !
Mettre en place le prerendering ne garantit pas à lui seul un bon référencement naturel ni des performances optimales. Pour aller plus loin, il est essentiel d'analyser vos indicateurs de performance (PageSpeed Insights, Lighthouse, etc.) et d'identifier les points à améliorer : poids des ressources, gestion du cache, lazy loading, compression, ou encore optimisation des images.
En combinant un prerendering bien configuré avec un travail régulier sur la performance front, vous obtiendrez un site rapide, bien référencé et agréable à utiliser.
N'hésitez pas à nous contacter directement pour parler SEO et développement !
Malgré le fait que le Javascript soit considéré dans l’imaginaire collectif comme un langage dynamique... Javascript est en fait un langage compilé !
Dans le monde de Microsoft, les choses bougent ! La plateforme .NET comporte maintenant deux déclinaisons : .NET Framework et .NET Core. Mais alors, quel framework .NET utiliser pour mon projet ? Un versus s'impose ! Au programme : définitions, spécificit
Découvrez la planche #11 !