Dynamic Imports With Webpack 2
Tags: javascript, bundling, building
Published: 2017-01-27 14:20:06

---
title: Dynamic Imports With Webpack 2
published: true
description: Load javascript on demand with the help of Webpack 2
cover_image: 
tags: javascript, bundling, building
---

If you're reading this post, you probably faced a problem many single page applications have, _too much JavaScript!_ You minified and bundled all your code with a tool of your choice, but somehow still end up with _too much being loaded at your first page_.

Many SPAs are used by people on mobile connections, which often aren't that fast. And you probably read that users will abandon a site if it loads too long. But how to solve this, without sacrificing features?

One way is dynamic, or on-demand loading of JavaScript.

The idea is, you just load the code that is needed for the current URL the user opened. Often your login page is much smaller as the rest of your pages. Or you have a simple landing page that just shows some nicely styled text with a few small images, things that can be downloaded and rendered very fast. 

Then, when the user knows what he's getting you let them download the rest, or maybe download it asynchronously while they read something that is already rendered.

Anyway, _performance is UX_, better UX means happier users. _The fastest bit is the bit not sent_, so lets dive into one solution for this problem: __Webpack 2__

Webpack 2 offers a way to automatically to bundle all your code into one file, like every bundler does. It also offers a way to bundle it in multiple files, that are needed at the same time, _almost_ out of the box.

So how does this work? Really simple!

You just have to use the (dynamic) `import` function in your code instead the _regular_ ES2015 `imports` that get evaluated statically.

Instead of writing:

    import home from './pages/home' 
    import about from './pages/about' 

    const page = document.location.hash.substr(1)

    if (page === 'home') home.render()
    if (page === 'about ') about .render()

Which will put the two page files into one bundle.

You would write:

    const page = document.location.hash.substr(1)

    import('./pages/' + page)
    .then(page => page.render())

Which will generate a bundle for all the possible files with that dynamic _pattern_. In this example 2, for `home.js` and `about.js`
 
That's _almost_ it!

What's missing?

The paths on the client need to be right. Webpack will generate bundles for every file that is dynamically imported and load _those_ bundle files at runtime, instead of the ones in your source directory. 

For example, your entry JS file is `src/index.js` but your output (bundle) file is `dist/application.js`. You would import the latter with:

    <script src="dist/application.js"></script>

if your HTML file in one directory above `dist/`. The other bundle files will be prefixed with numbers. For example: `0.application.js`. These will be loaded in the browser dynamically.

Webpack will throw an error in the browser, that it `cannot load chunk 0` or something. This is because, it tries to load the other files relative to the your HTML file and not relative to the first JavaScript file you loaded via the script tag.

To migrate this, you have to add a `publicPath` to your Webpack config:

    const path = require('path')

    module.exports = {

      entry:  './src/index.js',

      output: {
        filename: 'application.js',
        path: path.resolve(__dirname, 'dist'),
        publicPath: 'dist/',
      },

    }

Now, when you load the built `application.js` in your HTML, all the other generated bundle files will be loaded with `dist/` in their path. Like `dist/0.appliaction.js` instead of `0.application.js`

I also created a [repository](https://github.com/kay-is/webpack-on-demand-loading) with a simple complete example.

_Edit: System.import() is deprecated._