Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Webpack bundles my files in the wrong order (CommonsChunkPlugin)

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?

like image 547
Ollie Cee Avatar asked Mar 23 '17 22:03

Ollie Cee


3 Answers

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!

like image 118
Ollie Cee Avatar answered Nov 15 '22 09:11

Ollie Cee


You can try https://webpack.js.org/guides/shimming/#script-loader - it looks like it will execute scripts in order and in global context.

like image 23
Ivan Avatar answered Nov 15 '22 09:11

Ivan


Worked with htmlWebpackPlugin from official tutorials and switched the order form entry key. ( vendor then app )

In webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: {
      vendor: [
          'angular'
      ],
      app: [
          './src/index.js',
          './src/users/users.controller.js',
          './src/users/users.directive.js',
      ]
  },
   plugins: [
       new CleanWebpackPlugin(['dist']),
       new HtmlWebpackPlugin({
           template: './src/index-dev.html'
       }),
       new webpack.NamedModulesPlugin()
  ...
}

Now in the generated index.html file I have the correct order

<script src='vendor.bundle.js'></script>
<script src='app.bundle.js'></scrip
like image 2
que1326 Avatar answered Nov 15 '22 09:11

que1326