12 Sep 2016

Utiliser Webpack avec AngularJS – Partie 3 : Hot Module Replacement

Etape 3 : HMR, Components & LazyLoad

Nous somme ici dans le troisième et dernier article de cette suite  (cf Partie 1 & Partie 2). Si vous n’avez pas suivi les étapes précédentes, je vous conseille de partir d’un clone des sources de la partie précédente.

Hot Module Replacement (HMR)

Le HMR (pour ‘Hot Module Replacement’, aussi appelé ‘hot module swapping’) est, à mon sens, l’outil ultime des développeurs.

En effet, contrairement aux rumeurs, il n’est pas réservé à ReactJS, n’est pas si difficile d’accès et, surtout, ce n’est pas la même chose que le live reload ! Je vais eclaircir ce dernier point : le live reload rafraîchit la page lorsque le code est mis à jour, le HMR remplace le code en place et met à jour le site sans refresh.

Assez de blabla, passons à la pratique. Commençons sa mise en place.

Première possibilité : CLI

Cette façon de faire est la plus courante et la plus facile à mettre en place. Elle consiste à utiliser directement le webpack-dev-server en ligne de commande avec ces deux paramètres supplémentaires :

Ces paramètres ajoutent les bons plugins et configurent webpack pour activer le HMR (Plus de détails sur la doc officielle)

Ce qui donnerait, pour notre task ‘devserver’ :

Pour tester, vous n’avez qu’à lancer la task devserver et changer la valeur des variables utilisées dans notre controller. Une fois le fichier modifié et enregistré, la mise à jour des bundles se lance et vous verrez votre pagge se mettre à jour toute seule.

Deuxième possibilité : API

Dans certains cas (présence d’une task gulp/grunt, webpack lancé par script ou app sous express), l’utilisation du CLI n’est pas approprié. Nous devrons donc passer par l’API.

Pour se faire, c’est plutôt simple. Nous allons créer une application NodeJS qui mettra à disposition notre site web tout en gérant notre Webpack et HMR. Créons un fichier server.js à coté de nos fichiers de configuration :

Dans ce fichier, nous récupérons Webpack et son dev-server puis, nous les lançons. Le résultat obtenu est identique au CLI (dans notre cas). Attention, dans notre exemple, j’ai volontairement modifié la configuration de webpack dans le fichier server.js uniquement dans un but pédagogique. En effet, vous ne pouvez pas utiliser le CLI si la référence au ‘webpack/hot/dev-server’ et au HotModuleReplacementPlugin existent dans votre webpack.config.js.

Components & Routes

Maintenant que le HMR est fin prêt, il nous faut revoir un peu l’organisation de notre code.

Components

Pour se faire, passons en mode composants et ajoutons un système de gestion de routes adapté.

Revoyons un peu notre application AngularJS, à commencer par notre page d’index :

Vous aurez remarqué une nouvelle balise “app”. Celle-ci correspond à un nouveau composant angularJS. Travaillons son template avant de le déclarer (app.pug) :

Ajoutons maintenant le composant en tant que tel dans l’index.js :

Lancez la commande devserver. Vous verrez que ça tourne 😉

Profitons-en pour transformer notre HelloWorldController en composant : Commençons par le déclarer via HelloWorld.js

Nous avons retiré la déclaration .controller(…) pour le remplacer par un component. Puisque nous avons ajouté un ‘require’ sur un nouveau fichier pug, créons-le :

Le contenu est simple mais nous permettra de voir si ça fonctionne : Lancez le devserver, allez sur l’URL http://localhost:9100/, changez la valeur de ‘nonScopedData’ dans le code puis admirez. La page change d’elle-même sans se recharger (rien de tel pour briller en société !)

Qu’en est-il des résultats de tests unitaire? Evidemment, nos deux tests sont en erreur puisque le controller n’existe plus. Pour corriger, il suffit juste de revoir les injections dans le beforeEach :

Nous attaquons ainsi directement le controller du component, ce qui permet de garder tous nos tests intacts.

ngComponentRouter

Pour jouer avec les routes, nous avons l’embarras du choix : ngRoute, ui-route ou ngComponentRouter. Il y a déjà beaucoup de tutoriels sur ngRoute ou ui-route. Utilisons quelque chose de moins commun : ngComponentRouter. De plus, son utilisation nous donnera un aperçu de ce qui existera sur Angular2.

Commençons par l’installer :

Ensuite, un peu de préparation s’impose sur l’index.js. Importons notre nouveau module

Activons le mode html5 et définissons notre composant web principal pour la gestion des routes

Ajoutons nos routes :

Il ne nous reste plus qu’à dynamiser notre composant ‘app’ via son template en remplaçant la balise hello-world par ng-outlet :

“ng-outlet” correspond aux composants routés (un peu comme un ng-view).

Lazy loading

Il ne nous reste qu’à charger dynamiquement nos modules selon le besoin. Pour se faire, nous allons utiliser le module ocLazyLoad d’Olivier COMBE. Ce module permet d’injecter “à la volée” les scripts en fonction des besoins lors de la navigation.

Commençons par revoir légèrement notre configuration webpack en ajoutant un bundle pour HelloWorld

et vérifier, dans le HtmlWebpackPlugin, que nous ne chargeons QUE le bundle principal :

Maintenant que le module helloWorld est dans un autre bundle, il faut retirer l’import puis sa référence dans le module principal (index.js)

Le souci, c’est que cette action a totalement supprimé helloWorld. Il nous faut donc charger se composant depuis le $routeConfig. Mais ce n’est pas si facile car il nous faut un nouveau module à charger (ocLazyLoad) et un service angular à référencer.

Commençons par installer ocLazyLoad :

Créons un Controller pour notre composant ‘app’ dans un fichier AppController.js:

Ici, le controller servira à remplacer le $routeConfig et pour lui permettre d’utiliser l’ocLazyLoad.

Revenons sur l’index.js pour y ajouter la référence à notre nouveau controller.

et remplacer le $routeConfig du component ‘app’ par son nouveau controller. Revenons sur l’index.js pour y ajouter la référence ocLazyLoad

Et voilà, il vous reste plus qu’à tester le résultat et y ajouter quelques fonctionnalités de votre cru !

Sources et conclusion

Voilà, c’était la dernière partie de ce tutoriel. Sachez, néanmoins, qu’il ne s’agit là que d’une partie des fonctionnalités de Webpack.
Il existe aussi, par exemple, des outils d’analyse des bundles :

Je suis, personnellement, convaincu par cet outil exceptionnel et j’espère, qu’après lecture de ces articles, il en est de même pour vous.

A noter aussi qu’une v2 de webpack est en cours. Elle apportera, la gestion de l’ES2015 en natif, le mode promise, des loaders plus complets et bien d’autres choses…
Pour en savoir plus, je vous conseille leur documentation qui n’est pas parfaite mais qui s’améliore de jour en jour.

Enfin, pour ceux qui le souhaite, vous pourrez trouver l’intégralité des sources sur ce lien github : https://github.com/Bogala/webpack-starter.

Share
  • Un article très intéressant ! J’ai l’impression de faire de l’AngularJS préhistorique en comparaison ^^ J’ai vraiment hâte d’avoir l’occasion de tester Webpack.

  • Pierre Fiorelli

    Je réponds un peu tard, mais pour info ngComponentRouter est déprécié depuis quelques mois. Dans la doc il est conseillé d’utiliser ui-router à la place (qui permet au final de faire exactement la même chose)