Dynamic Module Loading in JavaScript

This is one of the niggling problems that have been in the back of my mind ever since I became involved with JavaScript. As I had a bit more time today, I decided to have another go at this.

After the first rather confusing google results I have stumbled upon a Git repo by Corey House (among other things he is the author of a few trainings on PluralSight): https://github.com/coryhouse/dynamic-import-example

I have forked this repo: https://github.com/jarecsni/dynamic-import-example, and tried to build it. Unfortunately the react-script approach wasn’t working in my local copy, and I was anyway interested in integrating this with Webpack + Babel explicitly, so I have changed things slightly around the build.

Using import() directly

Corey demonstrates two techniques, the first is using import() directly. The import() function is a proposal in stage 3 of the T39 process. To use this today, you will need the Babel plugin babel-plugin-syntax-dynamic-import which allows Babel to transpile import() calls.

Once you have installed this plugin, you can have code like this:

import(/* webpackChunkName: ‘vendor’ */ ‘moment’)
.then(moment => moment().format(‘LLLL’))
.then(str => console.log(str))
.catch(err => console.log(‘Failed to load moment’, err));

Have you noticed the ‘magic’ comment? It is used to tell Webpack which bundle it should use for the referenced module (the moment module will be stored in the vendor bundle in this case).

Personally I think this is not the best approach, as it leaves some Webpack specific code inside your source. I would rather have a simple map in the Webpack configuration, where you could tell Webpack where to bundle which module. Webpack could put those modules without explicit configuration to a default bundle.

In the example project, Tab2.js loads the moment library using this technique (in the React component’s componentDidMount callback). The browser only loads the vendor.bundle.js when the user selects Tab2 in the main page.

Using react-loadable

react-loadable is a higher order component to wrap around any React component, and make it dynamically loaded:

let Tab3 = Loadable({
loader: () => fakeDelay(2000).then(() => import(‘./Tab3’)),
loading: Loading
});

You can then include Tab3 in your render() and when the load does finish, the wrapper will make sure your component will be rerendered. This is rather useful, and not just for asynchronously loading a component, but also to do conditional stuff, like render images only when they are scrolled into view (the loader function can register itself as a callback on some event, etc.)

Conclusion and Looking ahead

I think these techniques are really valuable for deferred module loading, and automatic code splitting, worth studying them.

During writing this article I realised what I was really after is not dynamic module loading by the way :) I wanted to find a way to automatically load modules (without having to statically import them). I tried a few things but it seemed at some point that it’s not doable with JavaScript.

Finally I did find out how to this, and I think ‘auto-loading’ is important enough to dedicate a whole new article to it (I want to explore an interesting design patter this technique will make possible).

So, stay tuned :)

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.