React-Code in AEM: Arbeiten mit dynamischen Chunks

    Ihre AEM-basierte Website liefert nicht die Leistung, die Sie sich erhofft hatten? Eine mögliche Lösung: Implementieren Sie React! Lesen Sie hier, wie „dynamisches Code Chunking“ funktioniert.

    Abonnieren Sie unseren Blog

    Gleich als Facebook es 2015 auf den Markt brachte, erkannten Frontend-Entwickler, welches Potenzial React bietet. Hohe Leistungsfähigkeit, agile Benutzerschnittstellen – für Kenner zählt React definitiv zu den besten JavaScript-Frameworks.

    Grund genug, diese Bibliothek in verschiedene unserer Adobe Website-Projekte zu implementieren. React bietet die Möglichkeit, Websites oder mobile Apps mit hochinteraktiven Elementen auszustatten. Allein mit den Kernkomponenten des Adobe Experience Manager (AEM) gelingt das nämlich nicht so ohne Weiteres. Gemeint sind hier Elemente wie interaktive Infografiken, ein User-Portal mit Dashboards und Widgets oder eine Live-Simulation im Investment-Bereich.

    Die Herausforderung: JavaScript-Code mit React in AEM reduzieren


    React in Kombination mit AEM optimiert das Benutzererlebnis und bietet Vorteile bei der Projektentwicklung. Regelmäßig sehen sich Webentwickler dabei allerdings vor Herausforderungen gestellt.

    Unsere React-Komponenten gelangen gemeinhin über eine große Bootstrap-Datei auf die AEM-Website. Das funktioniert, wenn unser DOM (Document Object Model) HTML-Elemente eines bestimmten Datentyps (hier data-type=”react”) enthält, den wir in AEM festlegen können. Ist ein solches Element, oder auch mehrere, vorhanden, prüfen wir das „data-id“-Attribut und übersetzen (rendern) die relevanten Komponenten in besagte HTML-Elemente.

    Eine solche große Bootstrap-Datei bedeutet, dass jede verfügbare React-Komponente darin Eingang findet. Der kompilierte Code ist dann zwangsläufig sehr umfangreich. Wenn Sie aber zum Beispiel drei Webseiten mit jeweils eigener React-Komponente haben, ist es wenig sinnvoll, den Code dieser Seiten mit Bausteinen zu belasten, die an dieser Stelle gar nicht relevant sind.

    Idealerweise würde jede Seite einzeln geprüft und es würden jeweils nur diejenigen Code-Bestandteile angefragt, die auf der aktuellen Seite überhaupt gebraucht werden. Und damit sind wir beim Thema „dynamisches Code Chunking“ mit WebPack! Durch die Implementierung von WebPack ist es uns gelungen, den React-Code in AEM aufzusplitten. Und zwar so:


    Schritt 1: Code-Splitting über dynamische Importe in JavaScript

    Zunächst einmal muss man wissen, dass sich dynamische React-Chunks und reguläre JavaScript-Importe ausschließen. Der nachfolgende Screenshot zeigt, wie diese Importe aussehen:

    JavaScript-StandardimporteJavaScript-Standardimporte

    CODE

    import { Component1 } from './app/components/component1.component';
    import { Component2 } from './app/components/component2.component';
    import { Multiple, Components } from './app/components/multiplecomponents.component';
    import * as alias from 'we-need-everything-from-this-file.json';
    import { Service } from './app/services/service.service';

    Sind diese Importe Bestandteil unserer Bootstrap-Datei und kompilieren wir dann den Code, wird jede Komponente in die Zieldatei importiert. Daher steigen wir um: auf die Methode des dynamischen Imports(). Diese Methode basiert auf so genannten „asynchronous promises“. Der neue Code könnte dann zum Beispiel so aussehen:


     Dynamischer JavaScript-Import()
     Dynamischer JavaScript-Import()

    CODE

    import('./app/components/component1.component').then((Component1File) => {
    // Do stuff with your import!
    console.log(Component1File.Component1);
     });
    import ('./app/components/multiplecomponents.component').then((MultipleComponentsFile) => {
    console.log(MultipleComponentsFile.Multiple);
    console.log(MultipleComponentsFile.Components);
    });
    // and so on...

    WebPack generiert dann für jede importierte Komponente separate Code-Chunks, die im Hintergrund dynamisch abgefragt werden. Über die Kommentarfunktion von WebPack lassen sich die Chunks auch im Voraus benennen. Zum Beispiel so:

    Benennung von Code-Chunks in React über „Magic Comments“ in WebPackBenennung von Code-Chunks in React über „Magic Comments“ in WebPack

    CODE

    import(/* webpackChunkName: "core" */'./app/components/component1.component').then((Component1File) => { 
    // Do stuff with your import!
    console.log(Component1File.Component1);
    });

    Der vorstehende Programmcode fordert WebPack auf, einen Chunk namens ‚core’ zu erstellen. Jedes Mal, wenn Component1 ins Spiel kommt, wird der Chunk ‚core’ über das Netzwerk angefragt. Derselbe Chunk-Name kann auch an mehrere unterschiedliche Importe vergeben werden: Diese Importe gelangen dadurch alle in denselben Chunk.
    Das ist in Bezug auf JavaScript schon alles. Gar nicht so schwierig, oder? Jetzt muss noch WebPack konfiguriert werden.


    Schritt 2: Konfiguration von WebPack


    Bei AEM-Projekten kommt bei uns für das Frontend mehrheitlich Grunt zum Einsatz. Damit das Chunking funktioniert, muss in der Grunt-Datei die WebPack-Konfiguration entsprechend angepasst werden. Die Konfiguration für unseren Input bleibt unverändert:

    Input-Konfiguration in WebPackInput-Konfiguration in WebPack

    CODE

    entry: {
    'main': ['./src/app.bootstrap.tsx'],
    'subsite1': './src/assets/sass/subsite1.scss',
    'subsite2': './src/assets/sass/subsite2.scss',
    'subsite3': './src/assets/sass/subsite3.scss',
    'addon-author': './src/assets/sass/addon-author.scss',
    'labels': ['./src/assets/js/labels.ts'],
    },

    Ausgehend von diesen Dateien erzeugt WebPack dann Bundles. In app.bootstrap.tsx findet es unsere dynamischen Importe von oben. Es weiß dann, dass daraus jeweils einzelne Chunks zu erstellen sind. Jetzt legen wir die Output-Konfiguration fest, d. h. unser Build-Verzeichnis, die Namen der Bundles und Chunks und der Weg, über den unsere Chunks angefordert werden. Das geht wie folgt:


    Output-Konfiguration in WebPackOutput-Konfiguration in WebPack

    CODE

    output: {
    path: path.resolve(__dirname, 'build'),
    filename: 'js/[name].bundle.js',
    chunkFilename: path_to_our_aem_clientlibs/chunks/[name].[chunkhash].chunk.js',
    publicPath: "/",
    },


    Im Beispiel oben erkennt man, dass unser Code im Build-Verzeichnis vorliegt. Die Bundles befinden sich im JS-Verzeichnis und die Chunks in einem Verzeichnis, das genauso benannt ist wie unsere clientseitigen Bibliotheken in AEM (auch ClientLibs genannt). Warum? Wenn der Build-Vorgang abgeschlossen ist, sollen alle Dateien in die eigentliche AEM-Struktur kopiert werden. Auf diese Weise können wir sie inklusive Verzeichnis kopieren. WebPack holt sich die Chunks über den Root-Pfad.

    Achtung: Wir verwenden [chunkhash]. An die Chunk-Dateinamen wird dadurch automatisch ein Rautenzeichen angehängt. Der Grund hierfür liegt im Caching. Wenn der Code im Chunk geändert wird, ändert sich auch der Hashcode. Der Browser weiß dann, dass er den Chunk neu laden muss, und verwendet nicht den im Cache vorhandenen Chunk. Anderenfalls bliebe der Chunk-Name auch im Fall einer Änderung unverändert. Website-Besuchern würde dann eine alte Version des Chunks angezeigt.

    Das war es auch schon fast! Im letzten Schritt kopieren wir die Chunk-Dateien an die richtige Stelle in der AEM-Struktur. Dazu nutzen wir den „Copy“-Task aus Grunt. Die Konfiguration sieht dann so aus:



    WebPack-Konfiguration für den KopiervorgangWebPack-Konfiguration für den Kopiervorgang

    CODE
    {
    cwd: "./build/",
    dest: aem_design_etc_overrides + '/designs/project/clientlibs/chunks/',
    expand: true,
    flatten: true,
    src: "etc/designs/project/clientlibs/chunks/*.js"
    },

    Wir nehmen die Chunks aus dem Build-Verzeichnis (Sie erinnern sich: WebPack erhielt die Order, den Code dort zu generieren) und kopieren sie in das ClientLibs-Verzeichnis in AEM, in den angegebenen Chunks-Ordner.

     

    Das Ergebnis: eine im Durchschnitt um 19 % verbesserte Leistung der Website

    Das war alles. Mit diesen Änderungen ist es uns gelungen, den React-Code in einzelne Chunks aufzusplitten. AEM fordert diese nun dynamisch über das Netzwerk an. Klingt doch gut, oder? Aber welches konkrete Ergebnis dürfen Sie erwarten? Verbessert sich die Leistung Ihrer Website auch tatsächlich?

    Absolut! Wir haben einige „Vorher/Nachher“-Tests durchgeführt. Dabei haben wir einige Seiten hundert Male aufgerufen. Sehen Sie sich den Unterschied an!

    Vor der Erstellung der Code-Chunks in React:

    Seite

    Durchschnittliche Ladezeit (Millisekunden)

    Kürzeste Ladezeit (Millisekunden)

    Längste Ladezeit (Millisekunden)

    Index

    3948

    1165

    6996

    Übersicht Seite 1

    1521

    246

    5595

    Übersicht Seite 2

    37895

    20713

    55070

    Detail Seite 1

    13201

    158

    31618

    Detail Seite 2

    1573

    45

    6731

    Insgesamt

    11628

    45

    55070


    Nach der Erstellung der Code-Chunks in React:

    Seite

    Durchschnittliche Ladezeit (Millisekunden)

    Kürzeste Ladezeit (Millisekunden)

    Längste Ladezeit (Millisekunden)

    Inhalt

    3840

    1160

    6281

    Übersicht Seite 1

    810

    116

    5457

    Übersicht Seite 2

    35250

    20642

    53209

    Detail Seite 1

    12944

    110

    30390

    Detail Seite 2

    1052

    40

    5252

    Insgesamt

    9454 (-19 %)

    40 (-12 %)

    53209 (-3 %)

    Die Zahlen sprechen eine klare Sprache: Es ist uns gelungen, die Ladezeit der Seiten im Schnitt um 19 % zu verkürzen. Dabei muss man wissen, dass wir bei dieser speziellen Website überhaupt nur für die Code-Hauptblöcke Chunks erstellt haben. Es besteht also sogar noch weiteres Optimierungspotenzial.

    Nun sind Sie an der Reihe! Probieren Sie es aus: Sie werden sehen, wie sich die Performance Ihrer Website verbessert.

    Veröffentlicht auf 25/02/20    Zuletzt aktualisiert am 25/02/20

    #Adobe, #Webentwicklung, #software-entwicklung

    Über den Autor

    Bertijn Pauwels is DXM Junior Technical Consultant at Amplexor, based in Belgium. Having joined the Adobe team in 2018, Bertijn specializes in front-end development, including HTML/CSS and JavaScript, Angular and React frameworks.

    ABONNIEREN SIE UNSEREN BLOG

    Beteiligen Sie sich an dieser Diskussion