Skip to content

Minimize Load Time by Code Splitting with Webpack

In re-theming my site, one of my goals was to minimize load time. I hadn’t used Webpack to split bundles in Javascript yet, so I thought this was a perfect time to do it.

My awesome webpack code. (Explained below)

In creating the dragon curve animation, I had spent some time programmatically generating the points to get a dragon curve at different iterations. After I had that working and could export my coordinates for this curve, my next step was morphing the dragon curve. And while all that stuff deserves a series of posts in themselves, I found that Webpack bundling and dynamic imports were a perfect solution for conditionally loading scripts.

Why? Because the animation on my homepage uses a json file that was about 200k (not compressed/gzipped), and we don’t need to load that on mobile.

TL;DR: If you have purely decorative, larger size code you can ignore loading it on mobile using dynamic imports. This drastically decreases your load time.

The problem

I had this sweet animation. The problem is that the JSON data that I had for all the animation coordinates were in a file that was around 200kb.

I was doing Google Lightouse audits to get a baseline performance, and my score was around 50 / 100 ?. Not good.

There were many things that I tweaked to make sure my site loaded quickly. But this dang JSON was one of the primary offenders.

After splitting my bundle and gzipping my assets (look it up, it’s super powerful), my lighthouse score shot up to 95.

Kid giving a thumbs up

The Webpack Solution™️

I decided that the dragon curve was not necessary on mobile. What this actually means is that Javascript will be checking the view port size and see if it is less than 768. If it’s less, then don’t import my fancy animation.

// Thanks youmightnotneedjquery.com
var domReady = function(callback) {
    document.readyState === "interactive" || document.readyState === "complete" ? callback() : document.addEventListener("DOMContentLoaded", callback);
};

// Select dat animation
const dragon = document.querySelector('#dragon');

function checkViewPortWidth() {
    // Check if the window size is right
    // AND
    // if the dragon element is even there
    if (window.innerWidth > 768 && dragon) {
        // See below for more about this ↓
        import('./components/AnimateDragon/AnimateDragon')
            .then( ({ default: AnimateDragon }) => new AnimateDragon(dragon));
    }
}

// We want to run the animation kick off whenever
// the viewport is changed.
// Who knows?  Maybe someone opened my page in a
// small window?
window.addEventListener('resize', checkViewPortWidth);

// Actually kick off animation on page load
domReady(checkViewPortWidth);

About the import()

When you use the import like I have here (and by the way I’m running this all through babel with babel-preset-env,) it functions much like fetch does. It returns a promise. So, if you need to then do anything with your stuff, you need to either use await or a .then to handle the “response.”

For example:

import('./path/to/module')
    .then( (res) => {
        /* do what you need with the file
            in this case, "res" is the module */
    });

// OR, if in an async function

async function() {
    // ...
    
    const myModule = await import('./path/to/module');
    // Do stuff with my Module

    // ...
}

In my case, I’m doing some fancy destructuring and calling of my animation class because I set up my animation to be a class. ?

import('./components/AnimateDragon/AnimateDragon')
    // I take the 'default' property on the module
    // and destructure it, AND rename it to AnimateDragon
    .then( ({ default: AnimateDragon }) => new AnimateDragon(dragon));
    // class AnimateDragon expects a node element, so I instantiate
    // it with the dragon DOM node

Other ways to minimize load time

This is one specific way to speed up your site. There are many things you can do that will speed page load. You can try:

  • A CDN like cloudflare
  • WordPress has some caching plugins out there that you can try like Super Cache
  • Definitely gzip your stuff (you do this in your apache/nginx config)

Finally… the most powerful optimization you can try… if it’s really big and unwieldy, ask yourself Do I need this?

Hope that helps!

That’s all I have for now. I’d love to hear about cool ways that you’ve implemented bundling and splitting. Let me know what you think in the comments or hit me up on twitter!

Leave a Reply

Your email address will not be published. Required fields are marked *