Améliorez les performances du SPA en divisant vos bibliothèques angulaires en plusieurs parties

Bonjour, Habr! Je vous présente la traduction de l'article «Améliorez les performances du SPA en divisant vos bibliothèques Angular en plusieurs morceaux» de Kevin Kreuzer .


Angular est un excellent cadre. Nous l'aimons tous <3.


L'une des choses qui rend Angular réussie et belle en même temps est la vaste communauté et la valeur qu'elle apporte. Il existe de nombreuses réunions, blogs, conférences et, bien sûr, des bibliothèques angulaires.


Grâce à la CLI angulaire, les bibliothèques sont faciles à créer aujourd'hui. Ils sont parfaits pour partager du code entre plusieurs applications.


Puisqu'ils peuvent être utilisés dans de nombreux endroits, les performances sont un aspect critique. Une bibliothèque aux performances médiocres peut ralentir plusieurs applications!


Le frontend a différents types de performances. runtime - performances et charge initiale. Dans cet article, nous nous concentrerons sur la charge initiale.


En fournissant et en prenant en charge diverses bibliothèques et structures d'interface utilisateur pour une grande entreprise, je suis tombé sur des pièges et des moyens pas si évidents de les corriger. Je pense que cela vaut la peine d'en partager certains.


"C'est une bibliothèque si simple. Elle ne peut pas affecter les performances, non?"


Commençons par une bibliothèque simple que nous allons créer à l'aide de la CLI angulaire. Si vous n'avez jamais créé de bibliothèque angulaire, il peut être utile pour vous de lire l'article suivant:


image


Dès que nous utilisons la CLI pour configurer une grande partie de l'espace de travail du projet, nous pouvons commencer à ajouter du code.


La bibliothèque s'appelle howdy et son seul but est de vous accueillir avec votre nom ou de vous indiquer l'heure locale. Il contient deux modules avec chaque composant. Un modèle se félicite, l'autre parle du temps.


image


Juste un module Angular and Component normal qui prend une propriété de nom au-dessus des liaisons d'entrée et l'affiche.


image


HowdyTimeComponent est responsable de l'affichage de l'heure à l'aide d'une bibliothèque de moments tierce.


Super! Notre bibliothèque howdy est prête à être publiée! C'est une bibliothèque tellement simple; elle ne pourra pas affecter les performances, non?


Howdy bibliothèque consommation


Maintenant, nous avons une bibliothèque howdy ! Il serait dommage de ne pas en profiter. Pour utiliser la bibliothèque howdy , nous créons un nouveau SPA avec la CLI angulaire.


ng new greeting-app 

Puisque nous sommes intéressés par les performances, installons également la dépendance de développement appelée webpack-bundle-analyzer .


 npm i -D webpack-bundle-analyzer 

Webpack-bundle-analyzer vous permet de visualiser la taille de vos fichiers de sortie Webpack en utilisant une arborescence interactive et évolutive.


La meilleure façon d'analyser notre package est d'ajouter le script d'analyse suivant à notre package.json .


 "analyze": "ng build --prod --stats-json && webpack-bundle-analyzer ./dist/greeting-app/stats-es2015.json" 

Si nous exécutons cette commande, Angular effectuera la génération de production et produira également stats-es2015.json , qui sera ensuite sélectionné et rendu par webpack-bundle-anlyzer .


image


Comme nous n'avons pas encore écrit de code, notre package principal est principalement composé d'Angular. Nous pouvons également voir que zone.js est inclus dans notre package polyfill .


En général, la taille de notre application est désormais de 207 Ko .


Mais nous n'avons pas encore inclus notre bibliothèque Howdy! Allons de l'avant et faisons-le.


 npm i howdy 

Nous avons installé la bibliothèque howdy parce que nous voulons héberger un message d' accueil avec un nom. Nous ne sommes pas intéressés par la démonstration du temps. Par conséquent, nous n'utiliserons que le module HowdyNameModule et n'inclurons pas HowdyTimeModule .


image


Il est important de noter ici que nous importons uniquement HowdyNameModule . Exécutons à nouveau le script d'analyse d'analyse.


image


Ouah! Assez cool! Nous sommes passés de 207 Ko à 511,15 Ko. La taille a plus que doublé. Quel ...!


Un coup d'œil suffit pour trouver le coupable. le moment est énorme! Il apporte son code d'implémentation principal et tous les paramètres régionaux.


Bien sûr, moment peut être remplacé par d'autres packages, tels que date-fns ou moment-mini . Mais la question est différente; Pourquoi est-il même là? N'oubliez pas que nous avons uniquement importé HowdyNameModule , pas HodwyTimeModule . Je pensais que lorsque l' arbre tremblait , seuls les modules inutilisés se coupaient? Que se passe-t-il?


Le tremblement des arbres peut ne pas tout supprimer


Pour que le tremblement d'arbre se produise, la construction angulaire lance un tas d'optimisations avancées. Mais encore, le moment est présent dans le kit, bien que HowdyTimeModule ne soit pas.
Le problème est de savoir comment le moment est conditionné. Jetons un coup d'œil au fichier moment.js dans notre dossier node_modules .


image


Étant donné que moment peut être utilisé à de nombreux endroits, comme les backends Node JS, les applications angulaires ou JavaScript ordinaire, il est fourni en UMD et non en tant que module ES .


Les bibliothèques UMD liées sont enveloppées dans une fonction IFFE, ce qui signifie que ModuleConcatenation ne peut pas être utilisé. Les outils d'optimisation d'assemblage ne peuvent pas déterminer si ce code sera utilisé ou s'il a des effets secondaires.


En un mot, ce type de module empêche Angular de lancer un kit d'optimisation plus avancé.


Malheureusement, nous ne pouvons pas contrôler la façon dont le moment est terminé. Est-ce à dire que nous devons supporter la taille même du colis?


Points d'entrée secondaires pour la victoire


Nous ne pouvons pas contrôler la façon dont le moment est créé. Mais nous pouvons gérer notre bibliothèque. En effet, il existe un moyen d'empêcher de tels scénarios. Points d'entrée secondaires!


Presque toutes les bibliothèques Angular sont actuellement empaquetées en utilisant ng-packagr . ng-packagr vous permet d'utiliser ng-package.json en combinaison avec public-api , qui deviendra éventuellement le point d'entrée de votre application.


Comme son nom l'indique, des points d'entrée supplémentaires vous permettent de spécifier plusieurs points d'entrée pour votre application.


Ça sonne bien! Comment activer les points d'entrée secondaires?


Les points d'entrée secondaires sont détectés dynamiquement à l'aide de ng-packagr . ng-packagr recherche les fichiers package.json dans les sous-répertoires du dossier principal du fichier package.json


Cool! Profitons des points d'entrée secondaires de notre bibliothèque howdy en ajoutant les fichiers suivants.


image


Pour chaque module, nous avons ajouté index.ts , package.json et public_api.ts .


  • index.ts est là, uniquement pour pointer vers public_api , ce qui est utile lors de l'importation.
  • public_api exporte tous les modules et composants de notre module.
  • package.json contient des configurations ng-packagr spécifiques. Dans notre cas, cela suffit pour spécifier entryFile .

Package.json peut également contenir d'autres propriétés, telles que cssUrl , etc. Notez que la portée de ces propriétés n'est que le sous-élément actuel.

Si nous exécutons l'assemblage maintenant, nous obtenons trois blocs. howdy.js , howdy-src-lib-name.js et howdy-src-lib-time.js .


Howdy-src-lib-name.js contient désormais uniquement du code lié à HowdyNameModule , et howdy-src-lib-time.js contient désormais uniquement du code spécifique à HowdyTimeModule .


Mais regardons un morceau de howdy.js .


image


La pièce howdy.js contient toujours HowdyNameComponent et HowdyTimeComponent . Cela signifie que nous obtenons toujours le moment, même si nous importons uniquement HowdyNameModule .


Si nous voulons nous débarrasser de HowdyTimeModule avec cette approche, nous devons utiliser l'importation en profondeur. Nous importons donc non pas de howdy.js , mais directement de howdy-src-lib-time.js
Ce qui n'est pas recommandé! Les importations profondes sont dangereuses et doivent toujours être évitées!

Comment pouvons-nous résoudre ces problèmes? Comment pouvons-nous garantir que le HowdyTimeModule sera également supprimé même si nous utilisons des importations standard? Eh bien, nous devons mettre en place un moyen de créer un morceau de howdy.js .


Utilisez «panneau»


L'idée est de supprimer le code du bloc howdy.js et de lui permettre à la place d'agir comme une sorte de «pointeur» de «panneau indicateur» qui vous pointe vers d'autres blocs.


Examinons donc de plus près src / public_api.ts .


 /* * Public API Surface of howdy */ export * from './lib/name/howdy-name.component'; export * from './lib/name/howdy-name.module'; export * from './lib/time/howdy-time.component'; export * from './lib/time/howdy-time.module'; 

Ces lignes sont chargées d'inclure tout, du nom et de l' heure dans le bloc howdy.js . Nous devons supprimer le code de howdydy.js et le laisser pointer vers d'autres fragments qui contiennent l'implémentation. Modifions son contenu.


 / * Public API Surface of howdy */ export * from 'howdy/src/lib/name'; export * from 'howdy/src/lib/time'; 

Au lieu d'exporter l'implémentation réelle, nous indiquons le chemin relatif vers les différentes parties. Avec cette modification, howdy.js pointe uniquement vers d'autres packages et ne contient aucun code "réel".
Lançons ng build et analysons notre dossier dist .


image


Howdy.js agit désormais comme un «pointeur» «indicateur» qui pointe vers des fragments contenant l'implémentation. Le bloc howdy-src-lib-name.js contient uniquement le code du dossier de noms et le fichier howdy-src-lib-time.js contient uniquement le code du dossier de temps .


Complétez le package avec des substituts


Mettons à jour le package howdy dans notre application de bienvenue et réexécutons le script d'analyse.


image


Cool. La taille du package est désormais de 170,94 Ko . Légèrement supérieur à l'origine. Voyons à quoi ressemble le module Howdy dans le bundle final.


image


Super! Cet ajustement nous permet de garder la taille de l'emballage consommant du SPA petit. SPA obtient seulement ce dont ils ont besoin!


Les points d'entrée secondaires sont très bons lorsque vous les utilisez conjointement avec le chargement paresseux. Si nous utilisions HowdyTimeModule dans un module chargé paresseusement, le moment se retrouverait dans une pièce chargée paresseusement, et pas fondamentalement.

Expérience réelle


L'exemple ci-dessus est très simple.


Cependant, après l'introduction de points d'entrée secondaires dans le projet d'entreprise existant, tout sera différent. Vous devez faire face à une complexité beaucoup plus grande, tandis que les messages d'erreur de ng-packagr ne sont pas toujours utiles.


Très probablement, vous devrez configurer certains chemins d'importation ou spécifier certains chemins dans votre fichier tsconfig.json . Et vous rencontrerez également des modules d'un bloc qui utilisent des modules d'un autre bloc.


Mais croyez-moi, une fois que vous gérez ce fardeau, cela en vaut la peine.


Dans un environnement d'entreprise étendu, nous avons découvert que la taille du package du SPA nouvellement créé a explosé après avoir inclus certaines des bibliothèques que nous avons fournies.


À un moment donné, il est même passé à 5 Mo. Chaque SPA a reçu un moment , @swimlane / datatable et d'autres choses qu'il n'a même pas utilisées. Nous avons commencé à nous concentrer sur l'optimisation de cette taille de package.


Nous avons supprimé moment de date-fns et avons commencé à utiliser des points d'entrée secondaires. Actuellement, nous avons reçu une unité principale de 662 Ko pour le SPA nouvellement créé, qui comprend plusieurs bibliothèques. C'est encore beaucoup, mais nous n'avons pas encore fini. L'optimisation n'est pas encore terminée - nous pouvons encore réduire la taille des paquets.


C'est très cool de voir où nous en sommes et d'où nous venons.


Cependant, malgré le fait que dans l'exemple ci-dessus, il est assez facile d'utiliser des points d'entrée supplémentaires, il peut être assez difficile de les imaginer dans un projet plus important.


Conclusion


Angular fait un excellent travail lorsqu'il s'agit d'optimiser la taille d'un paquet. Bien que les étapes d'assemblage pour l'optimisation soient très complexes, elles ne peuvent pas secouer l'arborescence.


Les modules conditionnés dans des formats autres que ESModules ne peuvent pas être secoués dans l'arborescence.


Par conséquent, en tant que créateurs de bibliothèques, nous devons surveiller attentivement l'impact de notre bibliothèque sur la taille des packages lorsque nous incluons des bibliothèques tierces.
Nous ne pouvons pas contrôler l'empaquetage des bibliothèques tierces. Mais nous avons un très bon contrôle sur l'emballage de notre bibliothèque.


Les sous-parties nous offrent un excellent moyen de livrer notre bibliothèque en plusieurs parties. Ces pièces peuvent être secouées (arbre secouables) lors de l'optimisation de l'assemblage des angulaires. Avec cette approche, même les bibliothèques tierces mal empaquetées ne sont incluses dans le package final que si elles sont utilisées.

Source: https://habr.com/ru/post/fr482646/


All Articles