Code split your libraries and polyfills

dreitzner

Domenik Reitzner

Posted on June 26, 2020

Code split your libraries and polyfills

This is part two of seven.

Hack your legacy browsers

One of the things I like to do is to load polyfills only when they are needed. The way I do that is using the nomodule attribute.

<script src="/scripts/polyfills.js" nomodule defer></script>
Enter fullscreen mode Exit fullscreen mode

This will not load your polyfills in modern browsers 🙂

Babel and duplication

We are using gulp-babel ^6.1.2 in our project. The way it is set up it adds it's little helper functions to each file (e.g. for all classes _createClass is added).
This results in a lot of code duplication.
They way I worked around it, was to check those functions in the bundle for duplication and remove them.

let lastMatch = false;
const checkMatch = (match) => {
    if (lastMatch === match) return '';
    lastMatch = match;
    return match;
};

gulp
    .src(src)
    .pipe(p.babel({
        presets: [[
            'env',
            {
                targets: {
                    browsers: pkg.browserslist
                }
            }
        ]],
        plugins: ['angularjs-annotate'],
        compact: true,
    }))

    // bundle it up.
    .pipe(YOUR BUNDLE FUNCTION)

    // remove babel dupicates
    .pipe(p.replace(options.removeDuplicates.yourStringToCheck, checkMatch))
    .pipe(...whatEverElse)

Enter fullscreen mode Exit fullscreen mode

After that there should be only one instance of the helper function left.

Extract libraries from your vendor bundle

Some of the libraries that we use are not used on every page. So it makes sense to split them into their own bundle.
The ones I extrapolated where:

  • google maps markerclusterer
  • swiper
  • smartbanner (only load on mobile)

As we are using a C# MVC backend and have all bundles postfixed with a hash, we also needed to tell the frontend how they are called. In our case we made them accessible through a window environment object.

The only part that was left to do, was to load the scripts in the respective component/service before initializing them.

Here is an example of our swiper generator which returns a promise with the swiper after loading the script (if the script has been loaded the promise will resolve immediately):

class SwiperGenerator {
    constructor(Env, ScriptLoader, Resize) {
        Object.assign(this, {
            _Env: Env,
            _ScriptLoader: ScriptLoader,
            _Resize: Resize,
        });
    }

    init(element, options) {
        return this._ScriptLoader.load(this._Env.loadWhenNeeded.swiper)
            .then(() => new Swiper(element, options));
    }

}

angular
    .module('YOURMODULE')
    .service('SwiperGenerator', SwiperGenerator);
Enter fullscreen mode Exit fullscreen mode

Coming up next

  • find code duplications
  • optimize services
  • other shenanigans
💖 💪 🙅 🚩
dreitzner
Domenik Reitzner

Posted on June 26, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related