Doing split modules in webpack

I have several directories of JavaScript code, each representing a seperate module. I would like each directory to compile to a JS bundle. While the common code between them is in a `common.js` bundle. Then the bundle for each page can be loaded separately while the common bundle is always loaded.

I’ve struggled with the answer to this question for months. While I’ve realized it is possible, the examples I’ve found are bad, or do not work. And the documentation for webpack is as always arcane on the subject, making it very difficult to do it from scratch yourself.

However, I have finally managed to get it working through the Code Splitting plugin. Below is the configuration to use for webpack:

var webpackConfig = {
  // cheap source maps (only line numbers, not column numbers)
  devtool: 'eval',

  output: {
    filename: '[name].js',
  },

  entry: {
    // Here  you list the modules you would like outputted, with the corresponding directory
    'webpack-bundles/main': src + '/modules/main',
    'webpack-bundles/intro-guide': src + '/modules/intro-guide',
    'webpack-bundles/charts': src + '/modules/charts',
  },

  module: {
    loaders: [
      {
        test: /\.jsx?$/,
        loader: 'babel',
        exclude: ['/node_modules/', '/bower_components/'],
        query: {
          plugins: [],
          cacheDirectory: true,

          // Use stage 2 ES6
          presets: ['react', 'es2015', 'stage-2']
        }
      }
    ]
  },

  resolve: {
    extensions: ['', '.js', '.jsx'],
  },

  plugins: [
    // Split into multiple modules, required to make this example work
    new webpack.optimize.CommonsChunkPlugin("webpack-init.js")
  ],
};

Running webpack (through gulp in my case) after this should result in the following:

Terminal showing webpack code splitting outputting four files, screenshot.
Great success!

This results in webpack creating four different modules. The webpack-init.js must be included on every page, and includes the common code for the modules (libraries etc.) and also the webpack bootstrap code. The other modules contains the compiled code from that folder.

Then the question is; how to load the modules dynamically on demand? In my case the entire page is NOT a React component, only parts of the page are. And I mount separate React components in different places in the DOM.

To solve this, I have a function that wraps ReactDOM.render with a check if the module is loaded, in that case it just forwards the call, otherwise it injects the script tag for that module.

var loadedModules = {}

function mountComponent(module, component, props, domNode) {
    function mountIt() {
        ReactDOM.render(React.createElement(component, props), domNode)
    }

    if (!loadedModules.hasOwnProperty(module)) {
      // Not mounted already, add the script tag on document.ready
      document.addEventListener('DOMContentLoaded', function() {
        var s = document.createElement('script')
        s.type = 'text/javascript'
        s.src = document.location.origin + '/dist/webpack-bundles/' + module + '.js'
        document.body.appendChild(s)

        loadedModules[module] = true

        mountIt()
      }, false)
    }
    else {
        mountIt()
    }
}

// Use it
mountComponent('intro-page', 'IntroPageApp', {}, document.getElementById('intro-container'))

This solution works great for intermingling React and native HTML for a page. If your situation is different, and your entire page is a React app you will need to modify this approach, by using require.ensure([dependencies], callback) instead. I have not tried this yet, but it should not require any changes to the webpack configuration above to implement.