Comment configurer Webpack 4 avec Angular 7: un guide complet

Logos angulaires et webpack

La CLI angulaire facilite la création d’une application qui fonctionne déjà, tout de suite. C'est un excellent outil, mais n'avez-vous jamais pensé: "Comment ça marche? Comment puis-je créer une application sans la CLI?"

Ces questions me sont venues à l’esprit lorsque Angular 7 a été publié. J'ai commencé à chercher des réponses sur le Web et ce que j'ai trouvé n'était pas à jour pour mes besoins. En effet, Angular et webpack étant en constante évolution, il en va de même pour les dépendances et les configurations.

Dans cet article, vous allez apprendre:

  • Comment configurer une application de base Angular 7, à partir de zéro
  • Comment configurer webpack pour le mode de développement (compilation Just-in-Time)
  • Comment configurer WebPack pour le mode de production (compilation Ahead-of-Time)

Angular 7: configurer une application de base

Créez un nouveau fichier package.json et ajoutez les lignes suivantes pour installer Angular et ses dépendances.

"dépendances":
  "@ angular / animations": "~ 7.0",
  "@ angular / common": "~ 7.0",
  "@ angular / compiler": "~ 7.0",
  "@ angular / compiler-cli": "~ 7.0",
  "@ angular / core": "~ 7.0",
  "@ angular / forms": "~ 7.0",
  "@ angular / http": "~ 7.0",
  "@ angular / platform-browser": "~ 7.0",
  "@ angular / platform-browser-dynamic": "~ 7.0",
  "@ angular / platform-server": "~ 7.0",
  "@ angular / router": "~ 7.0",
  "@ angular / upgrade": "~ 7.0",
  "core-js": "~ 2.5",
  "rxjs": "~ 6.3",
  "zone.js": "~ 0.8"
}

J'ai longtemps lutté pour trouver la meilleure structure de dossiers qui convient à tous les projets Angular, en particulier lorsque la taille de l'application grandissait. Cet article m'a beaucoup appris sur le sujet.

Créez un nouveau dossier src et les dossiers / fichiers suivants. Toute notre logique métier d'application angulaire sera dans ce dossier.

src
| __ app
    | __ modules
        | __ menu
            | __ composants
                | __ menu
                    | __ menu.component.html
                    | __ menu.component.scss
                    | __ menu.component.ts
            | __ menu.module.ts
            | __ menu-routing.module.ts
| __ partagé
         | __ composants
             | __ home
                 | __ home.component.html
                 | __ home.component.scss
                 | __ home.component.ts
| __ app.component.html
        | __ app.component.scss
        | __ app.component.ts
        | __ app.module.ts
        | __ app-routing.module.ts
| __ index.html
| __ main.ts

Chaque application a au moins un module angulaire, le module racine que vous amorcez pour lancer l'application. Par convention, il s’appelle généralement AppModule. Je crée un autre module, le MenuModule, pour vous montrer comment utiliser le chargement paresseux dans votre projet, en particulier pour la production.

Quelques points importants:

  • index.html

Add indique à notre routeur angulaire comment composer les URL de navigation. Cette ligne signifie que votre application démarrera à partir du dossier racine: localement, il considérera localhost: 3000 / et sur le serveur, il considérera le dossier racine.

  • app-routage.module.ts

Il existe trois étapes principales pour configurer un module de fonctionnalité chargé paresseux:

  1. Créer le module de fonctionnalité
  2. Créer le module de routage du module de fonctionnalités
  3. Configurer les itinéraires

{chemin: ‘menu’, loadChildren: ’./ modules / menu / menu.module # MenuModule}} demande à Angular de charger paresseux notre module de fonctions MenuModule au moment où l’utilisateur visite l’itinéraire / menu.

Configuration TypeScript

Ajoutez les lignes suivantes à votre fichier package.json:

"devDependencies": {
  "@ types / core-js": "~ 2.5",
  "@ types / node": "~ 10.12",
  "typescript": "~ 3.1"
}

Créez dans votre dossier de projet racine un fichier tsconfig.json:

{
  "compilerOptions": {
    "cible": "es5",
    "module": "commonjs",
    "moduleResolution": "noeud",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": vrai,
    "noImplicitAny": true,
    "suppressImplicitAnyIndexErrors": true,
    "lib": ["es6", "dom"],
    "typeRoots": ["node_modules / @ types"]
  },
  "exclude": ["node_modules"]
}

Ceci est un fichier de configuration TypeScript de base. Il est essentiel d’installer la définition des types node et core-js. Sans cela, TypeScript ne pourra pas compiler notre application Angular en JavaScript.

Configuration Webpack pour le mode développement (compilation Just-in-Time)

Tout d’abord, que signifie compilation? Cela ne signifie pas la compilation de fichiers TypeScript en JavaScript, cela n’est pas lié à Angular. Angular lui-même a besoin de compiler vos modèles HTML en JavaScript, ce qui peut se produire à deux moments différents:

  • Une fois votre application téléchargée dans le navigateur (JiT)
Compilation JiT
  • Juste après le développement, au moment de la construction, avant que votre application ne soit téléchargée dans le navigateur (AoT)

Qu'est ce que le Webpack?

Selon Wikipedia:

Webpack est un bundle de modules JavaScript open source. Son objectif principal est de regrouper des fichiers JavaScript pour les utiliser dans un navigateur. Il est également capable de transformer, regrouper ou empaqueter à peu près n'importe quelle ressource ou ressource. Webpack prend des modules avec des dépendances et génère des actifs statiques représentant ces modules. Il s’agit principalement d’un ensemble de modules pour JavaScript, mais il peut transformer des actifs frontaux tels que HTML, CSS, voire des images si les plug-ins correspondants sont inclus.

Pour dire à webpack comment regrouper notre application, nous devons configurer ce que nous appelons les concepts de base:

Entrée - Un point d'entrée indique le module que le pack Web doit utiliser pour commencer à créer son graphe de dépendance interne. Webpack déterminera les autres modules et bibliothèques dont dépend le point d'entrée (directement et indirectement).

Output - La propriété output indique à Webpack où émettre les ensembles créés et comment nommer ces fichiers. La valeur par défaut est ./dist/main.js pour le fichier de sortie principal et dans le dossier ./dist pour tout autre fichier généré.

Chargeurs - De manière générale, les chargeurs ont deux propriétés dans la configuration de votre pack Web:

  • La propriété test identifie le ou les fichiers à transformer.
  • La propriété use indique quel chargeur doit être utilisé pour effectuer la transformation.

Plugins - Les chargeurs sont utilisés pour transformer certains types de modules, mais ils peuvent également être exploités pour effectuer un plus grand nombre de tâches, telles que l'optimisation des ensembles, la gestion des actifs et l'injection de variables d'environnement.

Tous ces éléments doivent être configurés dans le fichier de configuration webpack webpack.config.js.

Configuration du webpack

Dans le dossier src, nous devons créer 2 fichiers supplémentaires:

  • vendor.ts qui importe uniquement les modules tiers de l'application.
  • polyfills.ts, nous avons besoin de polyfills pour exécuter une application Angular dans la plupart des navigateurs, comme expliqué dans le guide Support du navigateur. Ce fichier bundle se chargera en premier. C’est donc un bon endroit pour configurer l’environnement du navigateur pour la production ou le développement.

Créez un nouveau dossier de configuration et les fichiers suivants à l'intérieur:

  • webpack.config.common.js: configuration que nous utiliserons pour le développement et la production.

Entrée - Pour cette application (et pour la plupart d'entre eux en réalité), nous avons 3 points d'entrée différents: vendor.ts polyfills.ts et main.ts.

entrée: {
    fournisseur: './src/vendor.ts',
    polyfills: './src/polyfills.ts',
    main: './src/main.ts'
}

Loaders - Nous chargeons les fichiers .html avec html-loader, ce qui est assez standard. Le chargement de fichiers .scss est un peu délicat pour une application Angular et j'ai eu du mal à comprendre comment le faire.

Tout d’abord, nous devons charger des fichiers sass à l’aide de deux chargeurs sass-loader et css-loader. Si vous voulez faciliter le débogage, en particulier en mode développement, il est vraiment important d’ajouter sourceMap: true comme options. Dans une application angulaire, nous ajoutons des styles à un composant en transmettant un chemin de fichier au tableau styleUrls, comme suit styleUrls: ["./path/styles.scss"], mais nous avons besoin de style comme chaîne. pour nous et jette la sortie sur une chaîne.

{
    test: /\.html$/,
    loader: 'html-loader'
},
{
    test: /\.(scss|sass)$/,
    utilisation: [
        'to-string-loader',
        {
            loader: 'css-loader',
            Les options: {
                sourceMap: true
            }
        },
        {
            loader: 'sass-loader',
            Les options: {
                sourceMap: true
            }
        }
    ],
    comprennent: helpers.root ('src', 'app')
}

Plugins - CleanWebpackPlugin supprimera / nettoiera vos dossiers de construction avant de les reconstruire. Le plugin HtmlWebpackPlugin générera un fichier HTML5 qui inclut tous vos ensembles de packs Web dans le corps à l’aide de balises de script. Cela nécessite uniquement un chemin vers le modèle.

nouveau CleanWebpackPlugin (
    helpers.root ('dist'),
    {
        root: helpers.root (),
        verbose: true
    }
),
new HtmlWebpackPlugin ({
    modèle: 'src / index.html'
})
  • webpack.config.dev.js est la configuration de notre webpack que nous n'utiliserons que pour le mode de développement.
mode: "développement"

Dans Webpack 4, le mode choisi indique à Webpack d'utiliser ses optimisations intégrées en conséquence.

devtool: 'module-eval-source-map pas cher'

Cette option contrôle si et comment les cartes source sont générées. En utilisant cheap-module-eval-source-map, les cartes source des chargeurs sont traitées pour de meilleurs résultats. Cependant, les cartes source du chargeur sont simplifiées en un seul mappage par ligne.

sortie: {
    chemin: helpers.root ('dist'),
    publicPath: '/',
    nom de fichier: '[nom] .bundle.js',
    chunkFilename: '[id] .chunk.js'
}

La clé de sortie contient un ensemble d'options indiquant à Webpack comment et où il doit générer vos ensembles, vos actifs et tout ce que vous regroupez ou chargez avec Webpack. Ici, nous demandons à webpack de sortir nos ensembles dans le dossier dist.

optimisation: {
    noEmitOnErrors: true
}

Ignore la phase d’émission chaque fois qu’il ya des erreurs lors de la compilation. Cela garantit qu'aucun actif erroné n'est émis. La clé d'optimisation comporte de nombreuses autres options définies par défaut en fonction du mode de configuration de votre pack Web (développement / production). Vous pouvez en lire plus à ce sujet ici.

{
    test: /\.ts$/,
    chargeurs: [
        'babel-loader',
        {
            loader: 'awesome-typescript-loader',
            Les options: {
                configFileName: helpers.root ('tsconfig.json')
            }
        },
        'angular2-template-loader',
        'angular-router-loader'
    ],
    exclure: [/ node_modules /]
}

angular-router-loader est un chargeur Webpack qui permet le chargement de modules basé sur des chaînes avec le routeur angulaire.

angular2-template-loader est un chargeur de chaîne qui englobe tous les styles et le code HTML des composants angulaires.

awesome-typescript-loader est actuellement le chargeur de packs Web PackScript le plus rapide. Il utilise la résolution de dépendance pour créer un graphe de dépendance de modules. Cela accélère relativement le processus de construction.

babel-loader permet de transpiler des fichiers JavaScript.

devServer: {
    historyApiFallback: true,
    stats: 'minimal'
}

Lors de l'utilisation de l'API Historique de HTML5, la page index.html devra probablement être servie à la place de 404 réponses. Pour cela, nous devons activer historyApiFallback.

L'option stats vous permet de contrôler avec précision les informations sur les ensembles qui sont affichées. Cela peut constituer un bon compromis si vous souhaitez des informations sur les offres groupées, mais pas toutes.

Ajout de scripts

Ajoutez les lignes suivantes à votre fichier package.json:

"scripts": {
  "build: dev": "webpack-dev-server --inline --hot --progress --port 8080"
}

--hot active le remplacement du module Webpack (HMR). Il échange, ajoute ou supprime des modules lorsqu'une application est en cours d'exécution, sans rechargement complet. Cela peut considérablement accélérer le développement de plusieurs manières:

  • Conserver l'état de l'application qui est perdu lors d'un rechargement complet.
  • Gagnez un temps précieux de développement en ne mettant à jour que ce qui a changé.
  • Les modifications apportées à CSS / JS dans le code source entraînent une mise à jour instantanée du navigateur, qui est presque comparable à un changement de style directement dans les outils de développement du navigateur.

Maintenant vous êtes tous installés! Vous pouvez exécuter npm run build: dev, ouvrez votre navigateur et accédez à localhost: 8080.

Configuration Webpack pour le mode de production (compilation Ahead-of-Time)

Avantages de la compilation AoT

  • Avec AoT, le navigateur télécharge une version pré-compilée de l'application. Le navigateur charge le code exécutable afin de pouvoir rendre l'application immédiatement, sans attendre la compilation de l'application.
  • Le compilateur insère des modèles HTML externes et des feuilles de style CSS externes dans l'application JavaScript, éliminant ainsi les demandes AJAX distinctes pour ces fichiers source.
  • Il n’est pas nécessaire de télécharger le compilateur Angular si l’application est déjà compilée. Le compilateur correspond à peu près à la moitié de Angular lui-même; son omission réduit donc considérablement la charge utile de l'application.
  • Le compilateur AoT détecte et signale les erreurs de liaison des modèles lors de l'étape de construction avant que les utilisateurs ne puissent les voir.
  • AoT compile les modèles et les composants HTML dans des fichiers JavaScript bien avant qu'ils ne soient servis au client. En l'absence de modèles à lire et d'évaluation HTML ou JavaScript risquée côté client, les possibilités d'attaques par injection sont moins nombreuses.

Configuration du webpack

Dans votre dossier de configuration, créez un nouveau fichier webpack.config.prod.js

mode: 'production'

Nous procédons généralement à la compilation AoT en mode production et, comme je l’ai écrit précédemment, dans Webpack 4, le mode choisi indique à Webpack d’utiliser ses optimisations intégrées en conséquence.

sortie: {
    chemin: helpers.root ('dist'),
    publicPath: '/',
    nom de fichier: '[hash] .js',
    chunkFilename: '[id]. [hash] .chunk.js'
}

Nous disons également à webpack de sortir nos ensembles dans le dossier dist. Nous incluons un hachage dans les noms de fichiers pour exploiter efficacement le cache de niveau client. Ainsi, webpack sait si un fichier a été modifié ou non. Webpack fournit des espaces réservés à cet effet. Ces chaînes sont utilisées pour attacher des informations spécifiques aux sorties. Les plus précieux sont:

  • [id] renvoie l'identifiant du bloc.
  • [chemin] renvoie le chemin du fichier.
  • [nom] renvoie le nom du fichier.
  • [ext] renvoie l'extension. [ext] fonctionne pour la plupart des champs disponibles.
  • [hash] renvoie le hachage de construction. Si une partie de la construction change, cela change également.
  • [chunkhash] renvoie un hachage spécifique à un morceau. Chaque entrée définie dans la configuration reçoit un hachage propre. Si une partie de l'entrée change, le hachage changera également. [chunkhash] est plus granulaire que [hash] par définition.
  • [contenthash] renvoie un hachage généré en fonction du contenu.

Il est préférable d’utiliser surtout le haschich et le chunkhash uniquement pour la production, car le hachage n’est pas essentiel pendant le développement.

optimisation: {
    noEmitOnErrors: true,
    splitChunks: {
        morceaux: 'tous'
    },
    runtimeChunk: 'single',
    minimiseur: [
        new UglifyJsPlugin ({
            cache: true,
            parallèle: vrai
        }),
         nouveau OptimizeCSSAssetsPlugin ({
             cssProcessor: cssnano,
             cssProcessorOptions: {
                 discardComments: {
                     removeAll: true
                 }
             },
             canPrint: false
         })
    ]
}
  • Comme en mode de développement, nous voulons ignorer la phase d’émission chaque fois qu’il ya des erreurs lors de la compilation. Cela garantit qu'aucun actif erroné n'est émis.
  • morceaux: «tous» indique quels morceaux seront sélectionnés pour l'optimisation. Fournir tout peut être particulièrement puissant, car cela signifie que des morceaux peuvent être partagés même entre morceaux asynchrones et non asynchrones.
  • Les modules importés sont initialisés séparément pour chaque bloc d'exécution. Comme le suggère Webpack, lorsque vous travaillez sur un projet comportant plusieurs points d'entrée, vous ne souhaitez disposer que d'une seule instance d'exécution. Pour cela, vous devez le régler sur "single".
  • UglifyJsPlugin utilise uglify-js pour réduire vos fichiers JavaScript. Nous avons défini la valeur true pour les propriétés cache et parallel afin d'activer la mise en cache de fichiers et d'utiliser le fonctionnement parallèle multi-processus pour améliorer la vitesse de génération. Il y a plus d'options disponibles et je vous invite à en apprendre davantage sur ce plugin.
  • OptimizeCSSAssetsPlugin recherchera les actifs CSS lors de la création du webpack et l’optimisera et le minimisera. Le processeur CSS utilisé pour l'optimisation est cssnano. Tous les commentaires seront supprimés de notre CSS simplifié et aucun message ne sera imprimé sur la console.
module: {
    règles: [
        {
            test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$$/,
            loader: '@ ngtools / webpack'
        }
    ]
}
plugins: [
    new ngw.AngularCompilerPlugin ({
        tsConfigPath: helpers.root ('tsconfig.aot.json'),
        entryModule: helpers.root ('src', 'app', 'modules', 'app', 'app.module # AppModule')
    })
]

@ ngtools / webpack est le plug-in officiel permettant à AoT de compiler vos composants et modules angulaires. Le chargeur fonctionne avec le plugin webpack pour compiler votre TypeScript. Il est important d’inclure les deux et de ne pas inclure d’autre chargeur de compilateur TypeScript.

Ajout du fichier main.aot.ts

Dans le dossier src, ajoutez le fichier main.aot.ts:

importer {enableProdMode} depuis '@ angular / core';
importer {platformBrowser} à partir de '@ angular / platform-browser';
importer {AppModuleNgFactory} depuis './app/app.module.ngfactory';
enableProdMode ();
platformBrowser (). bootstrapModuleFactory (AppModuleNgFactory);

Votre entrée principale est un peu différente en mode production et en compilation AoT:

  • Importez enableProdMode pour désactiver le mode de développement d’Anngular, qui désactive les assertions et autres vérifications au sein de la structure.
  • Importez platformBrowser AND NOT platformBrowserDynamic car, dans la compilation AoT, votre application est livrée au navigateur déjà compilé, tandis que dans la compilation JiT, elle se produit au niveau du navigateur.
  • Au lieu d'importer AppModule, vous devez importer AppModuleFactory, qui est votre application compilée générée par notre compilateur Angular.

Ajout de scripts

Ajoutez les scripts suivants à votre fichier package.json:

"webpack-prod": "cross-env NODE_ENV = production webpack --mode production"
"build: prod": "npm exécuter build: nettoyer && ngc && npm exécuter webpack-prod && npm exécuter build: propre"
"build: clean": "del-cli 'src / ** / *. js"' src / ** / *. js.map '' src / ** / *. ngsummary.json '' src / ** / * .metadata.json '' src / ** / ** / *. ngfactory.ts '' src / ** / *. ngstyle.ts '' src / ** / * .shim.ts '"
"serve": "lite-server"
  • build: clean: le compilateur Angular génère de nombreux fichiers afin de compiler votre application. Pour rester propre dans notre projet, nous supprimons tous ces fichiers avant la compilation et après la génération des bundles.
  • build: prod: exécutez le compilateur angulaire avec la commande ngc puis exécutez webpack en mode production pour générer vos bundles.
  • serve: j'utilise lite-server pour servir notre application et voir à quoi elle ressemble. Bien sûr, vous n’en aurez pas besoin dans un projet réel car votre application sera diffusée via le cloud.

Maintenant, vous pouvez exécuter npm run build: prod pour compiler votre application Angular et construire vos bundles. Ensuite, exécutez npm run serve pour servir votre application au navigateur.

Hugh Jackman appréciant l'article

J'espère que vous avez apprécié cet article! Si vous avez des questions / suggestions, faites-le moi savoir dans les commentaires ci-dessous.

Les fichiers de projet sont sur mon GitHub: