Verbessern Sie die SPA-Leistung, indem Sie Ihre Angular-Bibliotheken in mehrere Teile aufteilen

Hallo habr Ich präsentiere Ihnen die Übersetzung des Artikels „Verbessern Sie die SPA-Leistung, indem Sie Ihre Angular-Bibliotheken in mehrere Blöcke aufteilen“ von Kevin Kreuzer .


Angular ist ein großartiger Rahmen. Wir alle lieben ihn <3.


Eines der Dinge, die Angular gleichzeitig erfolgreich und schön machen, ist die breite Community und der Wert, den es trägt. Es gibt viele Meetings, Blogs, Konferenzen und natürlich Angular-Bibliotheken.


Dank der Angular-CLI können Bibliotheken heute einfach erstellt werden. Sie eignen sich hervorragend für die gemeinsame Nutzung von Code zwischen mehreren Anwendungen.


Da sie an vielen Orten eingesetzt werden können, ist die Leistung ein kritischer Aspekt. Eine Bibliothek mit schlechter Leistung kann mehrere Anwendungen verlangsamen!


Frontend hat verschiedene Arten von Leistung. Laufzeit - Leistung und Anfangslast. In diesem Artikel konzentrieren wir uns auf das anfängliche Laden.


Durch das Bereitstellen und Unterstützen verschiedener Bibliotheken und Benutzeroberflächen-Frameworks für ein großes Unternehmen stieß ich auf einige nicht so offensichtliche Fallstricke und Möglichkeiten, diese zu beheben. Ich denke, es lohnt sich, einige von ihnen zu teilen.


"Dies ist eine so einfache Bibliothek. Sie kann die Leistung nicht beeinträchtigen, oder?"


Beginnen wir mit einer einfachen Bibliothek, die wir mit der Angular-CLI erstellen. Wenn Sie noch nie eine Angular-Bibliothek erstellt haben, ist es möglicherweise hilfreich, den folgenden Artikel zu lesen:


Bild


Sobald wir die CLI zum Konfigurieren eines Großteils des Projektarbeitsbereichs verwenden, können wir Code hinzufügen.


Die Bibliothek heißt grüß dich und hat nur den Zweck, dich mit deinem Namen zu begrüßen oder dir die Ortszeit mitzuteilen. Es enthält zwei Module mit jeder Komponente. Ein Modell begrüßt, das andere spricht Zeit.


Bild


Nur ein reguläres Winkel- und Komponentenmodul, das eine Namenseigenschaft über den Eingabebindungen aufnimmt und diese anzeigt.


Bild


HowdyTimeComponent ist für die Zeitanzeige mithilfe einer Drittanbieter- Momentbibliothek verantwortlich.


Großartig! Unsere Grussbibliothek steht zur Veröffentlichung bereit! Es ist so eine einfache Bibliothek; Sie wird nicht in der Lage sein, die Leistung zu beeinträchtigen, oder?


Grüß dich Bibliothek Verbrauch


Jetzt haben wir eine grüß dich Bibliothek! Es wäre eine Schande, dies nicht auszunutzen. Um die Howdy- Bibliothek nutzen zu können, erstellen wir ein neues SPA mit der Angular-CLI.


ng new greeting-app 

Da wir an Performance interessiert sind, installieren wir auch die dev-Abhängigkeit namens webpack-bundle-analyzer .


 npm i -D webpack-bundle-analyzer 

Mit dem Webpack-Bundle-Analyzer können Sie die Größe Ihrer Webpack-Ausgabedateien mithilfe einer interaktiven, skalierbaren Baumstruktur anzeigen.


Um unser Paket zu analysieren, fügen Sie unserem package.json das folgende Analyseskript hinzu .


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

Wenn wir diesen Befehl ausführen, erstellt Angular die Produktion und gibt auch die Datei stats-es2015.json aus , die dann von webpack-bundle-anlyzer ausgewählt und gerendert wird.


Bild


Da wir noch keinen Code geschrieben haben, besteht unser Hauptpaket hauptsächlich aus Angular. Wir können auch sehen, dass zone.js in unserem Polyfill- Paket enthalten ist.


Im Allgemeinen beträgt die Größe unserer Anwendung jetzt 207 KB .


Aber wir haben unsere Howdy-Bibliothek noch nicht aufgenommen! Lassen Sie uns weitermachen und es tun.


 npm i howdy 

Wir haben die Howdy- Bibliothek installiert, weil wir einen Gruß mit einem Namen hosten möchten. Die Demonstration der Zeit interessiert uns nicht. Aus diesem Grund verwenden wir nur das HowdyNameModule- Modul und schließen HowdyTimeModule nicht ein .


Bild


Hierbei ist zu beachten, dass wir nur HowdyNameModule importieren . Lassen Sie uns das Analyse-Skript erneut ausführen.


Bild


Wow! Ziemlich cool! Wir haben von 207 KB auf 511,15 KB umgestellt. Die Größe hat sich mehr als verdoppelt. Was für ein ...!


Ein Blick genügt, um den Täter zu finden. Moment ist riesig! Es enthält den Hauptimplementierungscode und alle regionalen Einstellungen.


Selbstverständlich kann moment durch andere Pakete wie date-fns oder moment-mini ersetzt werden . Aber die Frage ist anders. Warum ist er überhaupt dort? Denken Sie daran, dass wir nur HowdyNameModule importiert haben , nicht HodwyTimeModule . Ich dachte, wenn Tree Shaking auftritt , werden nur unbenutzte Module abgeschüttelt? Was ist los?


Baumschütteln entfernt möglicherweise nicht alles


Damit Tree Shaking stattfinden kann , werden mit dem Build Angular eine Reihe erweiterter Optimierungen gestartet. Dennoch ist der Moment im Kit vorhanden, HowdyTimeModule jedoch nicht.
Das Problem ist, wie der Moment verpackt ist. Werfen wir einen kurzen Blick auf die Datei moment.js in unserem Ordner node_modules .


Bild


Da moment an vielen Orten verwendet werden kann, z. B. in Node JS-Backends, Angular-Anwendungen oder normalem JavaScript, wird es in UMD gebündelt und nicht als ES- Modul.


Die verknüpften UMD- Bibliotheken sind in eine IFFE-Funktion eingeschlossen, was bedeutet, dass ModuleConcatenation nicht verwendet werden kann. Die Tools zur Assemblyoptimierung können nicht herausfinden , ob dieser Code verwendet wird oder ob er Nebenwirkungen hat.


Kurz gesagt, dieser Modultyp verhindert, dass Angular ein erweitertes Optimierungskit auf den Markt bringt.


Leider können wir nicht kontrollieren, wie der Moment abgeschlossen ist. Bedeutet das, dass wir uns mit der Größe des Pakets abfinden müssen?


Sekundäre Einstiegspunkte für den Sieg


Wir können nicht kontrollieren, wie ein Moment entsteht. Aber wir können unsere Bibliothek verwalten. In der Tat gibt es eine Möglichkeit, solche Szenarien zu verhindern. Sekundäre Einstiegspunkte!


Fast alle Angular-Bibliotheken werden derzeit mit ng-packagr gepackt . Mit ng-packagr können Sie ng-package.json in Kombination mit public-api verwenden , das schließlich zum Einstiegspunkt für Ihre Anwendung wird.


Wie der Name schon sagt, können Sie mit zusätzlichen Einstiegspunkten mehrere Einstiegspunkte für Ihre Anwendung angeben.


Das hört sich gut an! Wie aktiviere ich sekundäre Einstiegspunkte?


Sekundäre Einstiegspunkte werden mit ng-packagr dynamisch erkannt. ng-packagr sucht nach package.json- Dateien in Unterverzeichnissen des Hauptordners der package.json- Datei


Cool! Nutzen Sie die sekundären Einstiegspunkte in unserer Howdy- Bibliothek, indem Sie die folgenden Dateien hinzufügen.


Bild


Für jedes Modul haben wir index.ts , package.json und public_api.ts hinzugefügt .


  • index.ts gibt es nur, um auf public_api zu verweisen , was beim Import nützlich ist.
  • public_api exportiert alle Module und Komponenten aus unserem Modul.
  • package.json enthält spezifische ng-packagr-Konfigurationen . In unserem Fall reicht dies aus, um entryFile anzugeben.

Package.json kann auch andere Eigenschaften wie cssUrl usw. enthalten. Beachten Sie, dass der Bereich dieser Eigenschaften nur das aktuelle Unterelement ist.

Wenn wir die Assembly jetzt ausführen, erhalten wir drei Blöcke. howdy.js , howdy-src-lib-name.js und howdy-src-lib-time.js .


Howdy-src-lib-name.js enthält jetzt nur Code für HowdyNameModule , und howdy-src-lib-time.js enthält jetzt nur Code für HowdyTimeModule .


Aber schauen wir uns ein Stück von howdy.js an .


Bild


Das Teil howdy.js enthält weiterhin HowdyNameComponent und HowdyTimeComponent . Dies bedeutet, dass wir immer noch den Moment bekommen, auch wenn wir nur HowdyNameModule importieren.


Wenn wir mit diesem Ansatz HowdyTimeModule entfernen möchten, müssen wir Deep Import verwenden. Wir importieren also nicht aus howdy.js , sondern direkt aus howdy-src-lib-time.js
Was wird nicht empfohlen! Tiefenimporte sind gefährlich und sollten immer vermieden werden!

Wie können wir diese Probleme lösen? Wie können wir garantieren, dass das HowdyTimeModule auch dann entfernt wird, wenn wir Standardimporte verwenden? Nun, wir müssen einen Weg finden, um ein Stück von howdy.js zu erstellen.


Verwenden Sie "Wegweiser"


Die Idee ist, den Code aus dem Block howdy.js zu entfernen und ihn stattdessen als eine Art "Wegweiser" zuzulassen, der Sie auf andere Blöcke verweist.


Schauen wir uns also src / public_api.ts genauer an.


 /* * 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'; 

Diese Zeilen sind dafür verantwortlich, dass alle Angaben von Name und Uhrzeit im Block howdy.js enthalten sind. Wir müssen den Code aus howdydy.js entfernen und ihn auf andere Fragmente verweisen lassen, die die Implementierung enthalten. Lassen Sie uns den Inhalt ändern.


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

Anstatt die eigentliche Implementierung zu exportieren, geben wir den relativen Pfad zu den verschiedenen Teilen an. Mit dieser Änderung verweist howdy.js nur auf andere Pakete und enthält keinen "echten" Code.
Lassen Sie uns ng build ausführen und unseren dist- Ordner analysieren.


Bild


Howdy.js fungiert jetzt als "Wegweiser", der auf Fragmente verweist, die die Implementierung enthalten. Der Block howdy-src-lib-name.js enthält nur den Code aus dem Namensordner , und die Datei howdy-src-lib-time.js enthält nur den Code aus dem Zeitordner .


Ergänzen Sie das Paket mit Ersatz


Lassen Sie uns das Howdy- Paket in unserer Willkommensanwendung aktualisieren und das Analyseskript erneut ausführen.


Bild


Cool. Die Paketgröße beträgt jetzt 170,94 KB . Etwas höher als ursprünglich. Mal sehen, wie das Howdy- Modul im endgültigen Bundle aussieht.


Bild


Großartig! Diese Anpassung ermöglicht es uns, die Packungsgröße verbrauchender SPA klein zu halten. SPA bekommt nur was sie brauchen!


Sekundäre Einstiegspunkte sind sehr gut, wenn Sie sie in Verbindung mit faulem Laden verwenden. Wenn wir HowdyTimeModule in einem trägen Modul verwenden würden, würde der Moment in einem trägen Teil enden und nicht im Grunde.

Echte Erfahrung


Das obige Beispiel ist sehr einfach.


Nach der Einführung von sekundären Einstiegspunkten in das bestehende Unternehmensprojekt wird sich jedoch alles ändern. Sie müssen sich mit einer viel größeren Komplexität auseinandersetzen, während Fehlermeldungen von ng-packagr nicht immer nützlich sind.


Höchstwahrscheinlich müssen Sie einige Importpfade konfigurieren oder einige Pfade in Ihrer Datei tsconfig.json angeben. Außerdem stoßen Sie auf Module aus einem Block, die Module aus einem anderen Block verwenden.


Aber glauben Sie mir, sobald Sie diese Belastung bewältigt haben, lohnt es sich.


In einem umfangreichen Unternehmensumfeld haben wir festgestellt, dass die Paketgröße des neu erstellten SPA explodierte, nachdem wir einige der von uns bereitgestellten Bibliotheken einbezogen hatten.


Irgendwann waren es sogar 5 MB . Jeder SPA erhielt einen Moment , @swimlane / datatable und andere Dinge, die er nicht einmal benutzte. Wir haben begonnen, uns auf die Optimierung dieser Paketgröße zu konzentrieren.


Wir haben moment von date-fns entfernt und sekundäre Einstiegspunkte verwendet. Derzeit haben wir eine 662 KB große Haupteinheit für das neu erstellte SPA erhalten, die mehrere Bibliotheken umfasst. Das ist noch viel, aber wir sind noch nicht fertig. Die Optimierung ist noch nicht abgeschlossen - wir können die Paketgröße noch weiter reduzieren.


Es ist sehr cool zu sehen, wo wir sind und woher wir kommen.


Obwohl es im obigen Beispiel recht einfach ist, zusätzliche Einstiegspunkte zu verwenden, kann es schwierig sein, sie sich in einem wichtigeren Projekt vorzustellen.


Fazit


Angular leistet hervorragende Arbeit bei der Optimierung der Packungsgröße. Obwohl die Montageschritte zur Optimierung sehr komplex sind, können sie das Baumschütteln nicht erschüttern.


Module, die in anderen Formaten als ESModules verpackt sind, können nicht in einem Baum geschüttelt werden.


Daher müssen wir als Entwickler von Bibliotheken die Auswirkungen unserer Bibliothek auf die Paketgröße sorgfältig überwachen, wenn wir Bibliotheken von Drittanbietern einbeziehen.
Wir können die Verpackung von Bibliotheken von Drittanbietern nicht kontrollieren. Wir haben aber sehr gute Kontrolle über die Verpackung unserer Bibliothek.


Unterteile bieten uns eine hervorragende Möglichkeit, unsere Bibliothek in mehreren Teilen bereitzustellen. Diese Teile können während der Optimierung des Zusammenbaus der Winkel geschüttelt werden (baumschüttelbar). Mit diesem Ansatz werden auch falsch gepackte Bibliotheken von Drittanbietern nur dann in das endgültige Paket aufgenommen, wenn sie verwendet werden.

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


All Articles