How to create dynamic chunks of React code in AEM

    Need to improve your AEM website performance? Implementing React can be the solution, here’s how to do it through dynamic code chunking.

    Subscribe to our blog

    React has won over front-end developers ever since its release by Facebook in 2015. When it comes to creating high performance, agile user interfaces, it's been even voted as one of the best JavaScript frameworks around.

    This is why we started implementing React in some of our Adobe website projects. It enables the design of highly interactive elements on your website or mobile app that are not so easy to accomplish with the Adobe Experience Manager (AEM) core components alone. Think about an interactive infographic, a user portal with dashboards and widgets, or live investment simulations, for example.

    The problem: reducing JavaScript code with React in AEM


    While using React with AEM brings several advantages to the user experience and project development, there’s a common hiccup along the way many web developers face.

    The way we load our React components into the AEM website is by having one large bootstrap file. This checks if there are HTML elements available in our Document Object Model (DOM) with a certain data-type (in this case, data-type=”react”), which we can set in AEM. If one or more elements are available, we check the data-id attribute and render the relevant components into these HTML elements.

    Having such a large bootstrap file means we have to include every available React component in this file, causing the resulting compiled code to be very large. For example, if you have three webpages, each with its own React component, it doesn’t make sense that we overload the code of these pages with components that won’t be really used there.

    The ideal scenario would be to check every single page, and only request the code for those components that are needed on the current page. That’s where dynamic code chunking with WebPack comes in! Here’s how we managed to implement WebPack to split React code in AEM.


    Step 1: Code splitting with dynamic imports in JavaScript

    The first step in creating dynamic chunks of React code is to get rid of the regular JavaScript imports, which look like the screenshot below:

    Standard JavaScript importsStandard JavaScript imports

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

     

    When we put these imports in our bootstrap file and compile the code, every component is imported in the resulting file. From now on, we’ll be using the dynamic import() method, that uses asynchronous promises. The updated code should look like this:


    Dynamic JavaScript import() method Dynamic JavaScript import() method

    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 will then generate separate code chunks for each imported component, and these chunks will get requested dynamically behind the scenes. You can also use WebPack’s magic comments, which enables you to name your chunks in advance. Here’s an example:

    WebPack’s magic comments to name React code chunksWebPack’s magic comments to name React code chunks

    CODE

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

    The code above instructs WebPack to create a chunk named ‘core’, and every time Component1 gets included, the ‘core’ chunk will be requested over the network. We can also pass the same chunk name to multiple different imports, which will place these imports in the same chunk.
    That’s it for the JavaScript part, pretty straightforward right? The one thing that’s left now is configuring our WebPack.

     

    Step 2: WebPack configuration

    In most of our AEM projects, we use Grunt for our front-end. In order to make the chunking work, we have to adjust our WebPack configuration in our Grunt file. The configuration for our entry files stays the same as before:


    WebPack input configuration
    WebPack input configuration

    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'],
    },

     

    WebPack will create bundles starting from these files. In app.bootstrap.tsx, it will encounter our dynamic imports from above, and it will know to create separate chunks for each. We will now have to define the output configuration, meaning our directory to build to, the names of the bundles and chunks, and the path on which our chunks are fetched. This is done in the following way:

    react code blog to replace
    WebPack output configuration

    CODE

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

    In the example above, you can see we build our code in the build directory, we put the bundles in the js directory, and the chunks in a directory with the same name as our AEM Client Libraries (or ClientLibs). Why? At the end of our build process, we have to copy all the files to the actual AEM structure, and this way, we can copy them with the directory included. The path on which WebPack has to fetch our chunks is the root.

    Please note that we use [chunkhash], which will automatically append a hash to our chunk file name. This is done for caching reasons. When the code in the chunk changes, the hashcode will change as well. This way, the browser will know that it has to fetch the chunk again, and not use the one that was in the cache. If we wouldn't do this, the chunk would keep the same name, even if it had changed, and visitors would get an old version of the chunk.

    Okay, we’re almost done! The only step left  is copying the chunk files to the correct place in the AEM structure. We do this by using the “copy” task from Grunt, and the configuration looks like this:


    WebPack copy configurationWebPack copy configuration

    CODE

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

    We get the chunks from the build directory (remember, we just told WebPack to build the code there), and we copy them to the ClientLibs directory in AEM, in the specified chunks folder.

    The results: an average website performance improvement of 19%

    That’s it - with these changes, we actually managed to split our React code into separate chunks, and AEM will request them dynamically over the network. Sounds pretty cool right? But what are the actual results? Did it actually improve our website’s performance?

    The answer is yes! we did some “before and after” tests, where we surfed some pages 100 times, and look at the difference!

    Before creating the React code chunks:

    Page

    Average load time (milliseconds)

    Minimum load time (milliseconds)

    Maximum load time (milliseconds)

    Index

    3948

    1165

    6996

    Overview page 1

    1521

    246

    5595

    Overview page 2

    37895

    20713

    55070

    Detail page 1

    13201

    158

    31618

    Detail page 2

    1573

    45

    6731

    Total

    11628

    45

    55070


    After creating the React code chunks:

    Page

    Average load time (milliseconds)

    Minimum load time (milliseconds)

    Maximum load time (milliseconds)

    Index

    3840

    1160

    6281

    Overview page 1

    810

    116

    5457

    Overview page 2

    35250

    20642

    53209

    Detail page 1

    12944

    110

    30390

    Detail page 2

    1052

    40

    5252

    Total

    9454 (-19%)

    40 (-12%)

    53209 (-3%)


    We can clearly see that by this change, we managed to achieve a 19% reduction, on average, on page load times.. Take into account that for this website in particular, we actually only created code chunks for the most common blocks of code, so there’s still potential for further improvement.

    So, what are you waiting for? Make sure you give this a try and see for yourself how it can improve your website performance!

    Published on    Last updated on 25/02/2020

    #Adobe, #Web Development, #Software Development

    About the author

    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.

    SUBSCRIBE TO OUR BLOG