Webpack bundles my files in the wrong order (CommonsChunkPlugin)

Ollie Cee picture Ollie Cee · Mar 23, 2017 · Viewed 24k times · Source

What I want is to bundle my JavaScript vendor files in a specific order via CommonsChunkPlugin from Webpack.

I'm using the CommonsChunkPlugin for Webpack. The usage from the official documentation is straight forward and easy. It works as intended but I believe the plugin is bundling my files in alphabetical order (could be wrong). There are no options for the plugin to specify the order they should be bundled.

Note: For those who are not familiar with Bootstrap 4, it currently requires a JavaScript library dependency called Tether. Tether must be loaded before Bootstrap.

webpack.config.js

module.exports = {
  entry: {
    app: './app.jsx',
    vendor: ['jquery', 'tether', 'bootstrap', 'wowjs'],
  },

  output: {
    path: __dirname + '/dist',
    filename: 'bundle.js',
  },

  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
        name: 'vendor',
        filename: 'vendor.bundle.js'
    }),

    new webpack.optimize.UglifyJsPlugin(),
  ],
};

Two things are happening here:

  1. vendor.bundle.js contains bootstrap, jquery, tether, wowjs
  2. bundle.js contains the rest of my application

Bundling order:
correct: jquery, tether, bootstrap, wowjs
incorrect: bootstrap, jquery, tether, wowjs

Notice in my webpack.config.js I ordered them exactly as they should but they are bundled in the incorrect order. It doesn't matter if I rearrange them randomly the result is the same.

After I use Webpack to build my application, the vendor.bundle.js shows me the incorrect order.

I know they're bundled incorrectly cause Chrome Dev. Tools tell me there are dependency issues. When I view the file through the tool and my IDE, it is bundled in the incorrect order.


My other approach also resulted in the same issue

I also tried import and require in my entry file (in this case, app.jsx) without the use of the CommonChunkPlugin and that also loads my JavaScript libraries in alphabetical order for some reason.

webpack.config.js

module.exports = {
  entry: './app.jsx',

  output: {
    path: __dirname + '/dist',
    filename: 'bundle.js',
  },

  plugins: [
    new webpack.optimize.UglifyJsPlugin(),
  ],
};

app.jsx (entry)

import './node_modules/jquery/dist/jquery.min';
import './node_modules/tether/dist/js/tether.min';
import './node_modules/bootstrap/dist/js/bootstrap.min';
import './node_modules/wowjs/dist/wow.min';

or

require('./node_modules/jquery/dist/jquery.min');
require('./node_modules/tether/dist/js/tether.min');
require('./node_modules/bootstrap/dist/js/bootstrap.min');
require('./node_modules/wowjs/dist/wow.min');

The result?
Bootstrap > jQuery > Tether > wowjs


How do I load my vendor files in the correct order?

Answer

Ollie Cee picture Ollie Cee · Mar 24, 2017

Success!

webpack.config.js

module.exports = {
  entry: {
    app: './app.jsx',
    vendor: [
        "script-loader!uglify-loader!jquery",
        "script-loader!uglify-loader!tether",
        "script-loader!uglify-loader!bootstrap",
        "script-loader!uglify-loader!wowjs",
    ]
  },

  output: {
    path: __dirname + '/dist',
    filename: 'bundle.js',
  },

  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
        name: 'vendor',
        filename: 'vendor.bundle.js'
    }),

    new webpack.optimize.UglifyJsPlugin(),
  ],
};

What magic is happening here?

  1. Webpack creates vendor.bundle.js by minifying & bundling my vendor files which now execute in the global context.
  2. Webpack creates bundle.js with all of its application code

entry file (app.jsx in this case)

import './script';

This script is just custom JavaScript that uses jQuery, Bootstrap, Tether and wowjs. It executes after vendor.bundle.js, allowing it to run successfully.

A mistake I made trying to execute my script.js was that I thought it had to be in the global context. So I imported it with script-loader like this: import './script-loader!script';. In the end, you don't need to because if you're importing through your entry file it will end up in the bundle file regardless.


Everything is all good.

Thanks @Ivan for the script-loader suggestion. I also noticed that the CommonsChunkPlugin was pulling the non-minified vendor versions so I chained uglify-loader into the process.

Although, I do believe some .min.js are created differently to get rid of extra bloat. Though that is for me to figure out. Thanks!