-
Objectifs
- Compiler une application avec
ng build et savoir ce que contient le dossier dist/
- Lire le rapport de compilation : fichiers initiaux, taille brute et taille transférée
- Distinguer la configuration de production et celle de développement
- Comprendre les noms de fichiers avec empreinte (
main-7W7XMOG5.js) et leur effet sur le cache
- Utiliser des fichiers d'environnement pour changer l'adresse d'une API selon la cible
- Régler les budgets de taille et tester la version compilée sur sa machine
-
Présentation
- Pendant le développement,
ng serve compile l'application en mémoire, surveille les fichiers et recharge le navigateur. Rien n'est écrit sur le disque, et ce serveur n'est pas fait pour être exposé sur Internet.
- Pour publier, on lance
ng build: Angular transforme le TypeScript, les templates et les styles en quelques fichiers statiques (HTML, JavaScript, CSS) optimisés. Ces fichiers suffisent : le serveur qui les héberge n'a besoin ni de Node.js ni d'Angular, un simple serveur web (Apache, Nginx, GitHub Pages…) fait l'affaire.
- Cette leçon décrit la compilation ; les deux suivantes montrent où déposer le résultat : sur un hébergement web ou un serveur dédié, puis sur GitHub Pages.
- Pour suivre ce chapitre, continuez dans le projet
premiers-pas-angular. Les exemples utilisent trois pages reliées par le routeur : /, /cours et /cours/:id. Toutes les commandes ont été exécutées et testées avec Angular 22.2 (Angular CLI 22.2.6, Node.js 22).

-
La commande ng build
- Placez-vous à la racine du projet (le dossier qui contient
angular.json) et lancez :
ng build
- Angular affiche un rapport, puis l'emplacement du résultat :
✔ Building...
Initial chunk files | Names | Raw size | Estimated transfer size
main-7W7XMOG5.js | main | 215.64 kB | 59.17 kB
styles-5INURTSO.css | styles | 0 bytes | 0 bytes
| Initial total | 215.64 kB | 59.17 kB
Application bundle generation complete. [3.296 seconds]
Output location: /home/claude/ng/premiers-pas-angular/dist/premiers-pas-angular

- Initial chunk files: les fichiers chargés dès l'ouverture de la page. Si vous chargez des routes à la demande (
loadComponent), une seconde partie Lazy chunk files apparaît.
- Raw size: la taille réelle des fichiers sur le disque.
- Estimated transfer size: la taille estimée après compression par le serveur (gzip ou brotli). C'est elle qui compte pour l'utilisateur : ici, environ 59 kB à télécharger.
- La compilation est confiée au builder
@angular/build:application, déclaré dans angular.json; il s'appuie sur esbuild et ne prend que quelques secondes.
-
Le contenu du dossier dist
- Le résultat est écrit dans
dist/<nom-du-projet>/. Seul le sous-dossier browser/ est à publier :
dist/
└── premiers-pas-angular/
├── 3rdpartylicenses.txt ← licences des bibliothèques utilisées (ne pas publier)
└── browser/ ← LE DOSSIER À PUBLIER
├── index.html
├── main-7W7XMOG5.js
├── styles-5INURTSO.css
└── favicon.ico ← copié depuis le dossier public/
- Le fichier
index.html produit est très court : il déclare l'adresse de base (<base href="/">), charge la feuille de style et le script principal, et contient la balise <app-root> que l'application va remplir :
<!doctype html>
<html lang="en" data-beasties-container>
<head>
<meta charset="utf-8">
<title>PremiersPasAngular</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="stylesheet" href="styles-5INURTSO.css"></head>
<body>
<app-root></app-root>
<script src="main-7W7XMOG5.js" type="module"></script></body>
</html>
- Chaque compilation vide d'abord le dossier de sortie : ne rangez jamais de fichiers personnels dans
dist/. Ce dossier est d'ailleurs ignoré par Git (.gitignore), car on peut toujours le recréer.
- Les fichiers du dossier
public/ (images, favicon, polices…) sont recopiés tels quels à la racine de browser/.
-
Production ou développement
- Dans
angular.json, la cible build possède deux configurations, et defaultConfiguration indique laquelle est utilisée quand on n'en précise aucune :
"build": {
"builder": "@angular/build:application",
"options": {
"browser": "src/main.ts",
"tsConfig": "tsconfig.app.json",
"assets": [{ "glob": "**/*", "input": "public" }],
"styles": ["src/styles.css"]
},
"configurations": {
"production": {
"budgets": [ … ],
"outputHashing": "all"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
}
},
"defaultConfiguration": "production"
}
ng build compile donc en production. Pour obtenir une version lisible, à déboguer, on demande l'autre configuration :
ng build --configuration development
Initial chunk files | Names | Raw size
main.js | main | 1.36 MB
styles.css | styles | 95 bytes
| Réglage |
production (par défaut) |
development |
| Optimisation (code minifié, code mort supprimé) |
Oui |
Non (optimization: false) |
| Noms de fichiers |
Avec empreinte : main-7W7XMOG5.js |
Fixes : main.js |
Source maps (.map) |
Non |
Oui (débogage du TypeScript dans le navigateur) |
Taille de main pour notre projet |
215,64 kB (59 kB transférés) |
1,36 MB |
| Budgets vérifiés |
Oui |
Non |
| Usage |
Publication |
Déboguer un problème qui n'apparaît qu'après compilation |
- Publiez toujours la version de production : six fois plus légère, elle ne livre pas votre code source aux visiteurs à travers les source maps.
-
Les noms de fichiers avec empreinte et le cache
- En production, chaque nom de fichier contient une empreinte (hash) calculée à partir de son contenu :
main-7W7XMOG5.js. Modifiez une ligne de code, recompilez : le fichier s'appelle autrement, et index.html pointe vers le nouveau nom.
- C'est le réglage
"outputHashing": "all". Il permet au serveur de demander au navigateur de garder ces fichiers en cache très longtemps: un fichier modifié changera de nom, il ne sera jamais confondu avec l'ancien.
- Seul
index.html garde toujours le même nom : c'est lui qui ne doit pas être mis en cache, sinon le navigateur continuerait à charger les anciens scripts. La leçon suivante montre comment le régler sur le serveur.

-
Les fichiers d'environnement
- Une application appelle souvent une API dont l'adresse diffère entre la machine du développeur et le serveur de production. Angular crée deux fichiers d'environnement avec :
ng generate environments
CREATE src/environments/environment.ts (31 bytes)
CREATE src/environments/environment.development.ts (31 bytes)
UPDATE angular.json (2250 bytes)
- Remplissez-les avec les mêmes propriétés:
// src/environments/environment.ts : utilisé par ng build (production)
export const environment = {
production: true,
apiUrl: 'https://api.mon-site.tn',
};
// src/environments/environment.development.ts : utilisé par ng serve et --configuration development
export const environment = {
production: false,
apiUrl: 'http://localhost:8000',
};
- La commande a ajouté une règle de remplacement dans la configuration
development de angular.json: pendant la compilation, le premier fichier est remplacé par le second.
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true,
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.development.ts"
}
]
}
- Dans le code, on importe toujours
environment.ts, jamais la version .development:
import { Component } from '@angular/core';
import { RouterLink, RouterOutlet } from '@angular/router';
import { environment } from '../environments/environment';
@Component({
imports: [RouterOutlet, RouterLink],
selector: 'app-root',
styleUrl: './app.css',
templateUrl: './app.html',
})
export class App {
protected readonly api = environment.apiUrl;
}
- Vérification faite sur les fichiers compilés : le
main-….js de production ne contient que https://api.mon-site.tn, et le main.js de développement que http://localhost:8000.
- Ces fichiers sont livrés au navigateur : n'y mettez jamais de mot de passe, de clé secrète ou d'identifiants de base de données. Tout visiteur peut les lire.
-
Les budgets
- Les budgets de la configuration de production surveillent le poids de l'application : un avertissement au-delà de
maximumWarning, une erreur qui arrête la compilation au-delà de maximumError.
"budgets": [
{
"type": "initial",
"maximumWarning": "500kB",
"maximumError": "1MB"
},
{
"type": "anyComponentStyle",
"maximumWarning": "4kB",
"maximumError": "8kB"
}
]
initial limite le total des fichiers chargés à l'ouverture ; anyComponentStyle limite la feuille de style de chaque composant.
- Pour voir l'effet, abaissez
maximumError à 100kB et recompilez :
Application bundle generation failed. [2.600 seconds]
✘ [ERROR] bundle initial exceeded maximum budget. Budget 100.00 kB was not met by 115.64 kB with a total of 215.64 kB.

- Face à un dépassement, cherchez d'abord à alléger (charger des routes à la demande avec
loadComponent, retirer une bibliothèque inutile) avant de relever la limite.
-
Tester la version compilée sur sa machine
- Un double-clic sur
dist/premiers-pas-angular/browser/index.html affiche une page blanche. La console explique pourquoi : le navigateur refuse de charger un script type="module" depuis une adresse file://.
Access to script at 'file:///main-7W7XMOG5.js' from origin 'null' has been blocked by CORS policy:
Cross origin requests are only supported for protocol schemes: chrome, chrome-untrusted, data, http, https.

- Il faut passer par un petit serveur web. Le paquet
serve s'utilise sans installation, avec npx; l'option -s (single-page) renvoie index.html pour toutes les adresses inconnues, comme le fera le vrai serveur :
ng build
npx serve -s dist/premiers-pas-angular/browser -l 4300
INFO Accepting connections at http://localhost:4300
- Ouvrez
http://localhost:4300/cours/3: la page du cours « Signals » s'affiche directement, ce qui prouve que la version de production et le routeur fonctionnent.

-
Publier dans un sous-dossier : --base-href
- La balise
<base href="/"> de index.html indique à partir de quelle adresse le navigateur cherche les fichiers et le routeur construit ses liens. Si l'application doit vivre dans un sous-dossier (par exemple https://mon-site.tn/formation/), on le précise à la compilation :
ng build --base-href /formation/
<base href="/formation/">
- N'oubliez pas les deux barres obliques.
ng build --base-href formation est accepté sans erreur, mais produit <base href="formation">, qui casse les adresses dès que l'on quitte la page d'accueil.
- La leçon suivante montre l'installation complète dans un sous-dossier, avec la configuration du serveur.

-
Activité 1 : lire un rapport de compilation
- Lancer
ng build dans votre projet et recopier, pour chaque fichier initial, son nom, sa taille brute et sa taille transférée.
- Ajouter une phrase dans le template d'un composant, recompiler, et comparer le nom du fichier
main-….js avant et après.
- Vérifier : le nom change, celui de
styles-….css ne change pas si aucun style n'a été modifié.
- Pourquoi ce changement de nom est-il une bonne chose pour les visiteurs déjà venus sur le site ?
-
Activité 2 : production contre développement
- Compiler successivement avec
ng build puis ng build --configuration development, et remplir un tableau : nom des fichiers, taille de main, présence de fichiers .map.
- Ouvrir les deux fichiers
main dans l'éditeur et comparer leur lisibilité.
- Vérifier : la version de développement est plusieurs fois plus lourde et contient des fichiers
.map.
- Laquelle publier, et pourquoi ne faut-il jamais publier l'autre ?
-
Activité 3 : une API par environnement
- Générer les fichiers d'environnement et y déclarer
apiUrl: http://localhost:8000 en développement, https://api.mon-site.tn en production.
- Afficher cette adresse en bas de la page d'accueil, puis comparer l'affichage sous
ng serve et sous npx serve -s après ng build.
- Vérifier :
ng serve affiche l'adresse locale, la version compilée celle de production.
- Un camarade propose d'y ranger aussi le mot de passe de la base de données : que lui répondez-vous ?
-
Activité 4 : déclencher et corriger un dépassement de budget
- Abaisser le budget
initial à 100kB (erreur) et observer le message.
- Rétablir la valeur d'origine, puis abaisser
anyComponentStyle à 1kB et ajouter une grosse feuille de style dans un composant.
- Vérifier : la compilation échoue avec un message qui nomme le budget dépassé.
- Pourquoi l'équipe d'Angular a-t-elle choisi de bloquer la compilation plutôt que d'afficher un simple avertissement ?
-
Activité 5 : préparer une publication dans un sous-dossier
- Compiler avec
--base-href /formation/ et ouvrir dist/premiers-pas-angular/browser/index.html dans l'éditeur.
- Recommencer avec
--base-href formation, sans les barres obliques.
- Vérifier : la balise
<base> vaut /formation/ puis formation.
- Quelle valeur faut-il garder, et que se passera-t-il avec l'autre ?
-
Erreurs fréquentes
| Message ou symptôme |
Cause |
Solution |
Page blanche après un double-clic sur index.html, erreur blocked by CORS policy |
Fichiers ouverts en file:// |
Passer par un serveur : npx serve -s dist/…/browser |
bundle initial exceeded maximum budget |
Application trop lourde pour le budget |
Alléger (routes à la demande, bibliothèques inutiles), sinon ajuster le budget |
L'application publiée appelle localhost |
Adresse écrite en dur, ou import de environment.development.ts |
Importer environment.ts et compiler en production |
Fichiers .map et code lisible sur le serveur |
Compilation avec --configuration development |
Recompiler avec ng build |
Un fichier rangé dans dist/ a disparu |
Chaque compilation vide le dossier de sortie |
Ranger les fichiers à publier dans public/ |
| Le serveur affiche la liste des fichiers ou une page 403 |
Dossier dist/premiers-pas-angular publié au lieu de browser/ |
Publier le contenu de browser/ |
Liens cassés dans un sous-dossier, <base href="formation"> |
Barres obliques oubliées dans --base-href |
--base-href /formation/ |
-
À retenir
ng build compile en production par défaut et écrit le résultat dans dist/<projet>/browser/: c'est le contenu de ce dossier que l'on publie.
- Le résultat est fait de fichiers statiques : un simple serveur web suffit, sans Node.js.
- Les noms avec empreinte (
main-7W7XMOG5.js) changent à chaque modification : ces fichiers peuvent rester longtemps en cache, mais pas index.html.
ng generate environments crée deux fichiers ; on importe toujours environment.ts, et on n'y met aucun secret.
- Les budgets arrêtent la compilation si l'application devient trop lourde.
- Pour tester la version compilée :
npx serve -s dist/<projet>/browser, jamais un double-clic.
--base-href /dossier/ prépare une publication dans un sous-dossier.
Le dossier dist/ est le seul livrable : ce qui n'y est pas n'arrivera jamais chez l'utilisateur, et ce qui y est sera lisible par tous.