CommonsChunkPlugin problem with code splitting and multiple entry points

I’m submitting a bug report

Webpack version:
1.13.1

Please tell us about your environment:
Linux

Current behavior:
Trying to get code split between multiple entry points, with each entry point split into own code and vendor bundle, then commons extracted for both own code and vendor bundles.

Entry points look like:

        entry: {
            login: './src/Login/index.jsx',
            app: './src/index.jsx',
            vendor: Object.keys(packageDotJson.dependencies).filter(function (element) {
                return element !== 'font-awesome' && element !== 'jspdf';
            }),
            loginvendor: packageDotJson.loginDependencies
        },

The following works as expected:

            new webpack.optimize.CommonsChunkPlugin({
                name: "vendor",
                chunks: ["app"],
                minChunks: Infinity
            }),
            new webpack.optimize.CommonsChunkPlugin({
                name: "loginvendor",
                chunks: ["login"],
                minChunks: Infinity
            }),
            new webpack.optimize.CommonsChunkPlugin({
                name: "vendor.commons",
                chunks: ["vendor", "loginvendor"],
                minChunks: 2
            }),

Vendor bundles are extracted from each entry point bundle, then a common vendor bundle is extracted from the two vendor bundles.

Grepping the build results for definitions of commonly used packages like babal-polyfill and React, they are correctly found only in vendor.commons file.

Adding:

            new webpack.optimize.CommonsChunkPlugin({
                name: "commons",
                chunks: ["app", "login"],
                minChunks: 2
            }),

and testing for the same packages, we have:

> grep -R "var React = {" ./dist -l
./dist/vendor.commons.080acb7415d897182eca.js
./dist/commons.080acb7415d897182eca.js

It seems the final invoking of the plugin is selecting the original app and login chunks, as they were before vendor modules were removed into vendor and loginvendor chunks.

Expected/desired behavior:
Expecting

            new webpack.optimize.CommonsChunkPlugin({
                name: "commons",
                chunks: ["app", "login"],
                minChunks: 2
            }),

to select the app and login chunks with vendor modules removed and extract the common modules from them into commons chunk. Vendor modules shouldn’t appear both in commons and vendor.commons chunks.

  • What is the motivation / use case for changing the behavior?

It seems logical to expect that instances of the plugin will be ran sequentially and that every run will have access to chunks modified by the previous run.

This specific use case if for production build. We need vendor code in separate bundles to avoid generating sourcemaps for it. Multiple entry points are needed to avoid serving a lot of unnecessary code to the user. Common modules are extracted to avoid duplication.

  • Browser: [ Chrome 52.0.2743.116 (64-bit) ]
  • Language: [ ES6/7 ]

Author: Fantashit

1 thought on “CommonsChunkPlugin problem with code splitting and multiple entry points

  1. @MilosRasic I’ve had more success doing

    function _isVendor(module) {
      if (typeof userRequest !== 'string') {
        return false;
      }
      return  userRequest.indexOf('/node_modules/') >= 0  
    } 
    
    ...
    
    new webpack.optimize.CommonsChunkPlugin({
      name: "vendor",
      chunks: ["app", "login"],
      minChunks: function(module, count){
        return _isVendor(module);
      }
    })
    

    this removes the need to have that other vendor entry point you had earlier.

    if you still want to get the vendors out of each entry you can

    new webpack.optimize.CommonsChunkPlugin({
      name: "appvendor",
      chunks: ["app"],
      minChunks: function(module, count){
        return _isVendor(module);
      }
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: "loginvendor",
      chunks: ["login"],
      minChunks: function(module, count){
        return _isVendor(module);
      }
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: "vendor.commons",
      chunks: ["login", "app", "appvendor", "loginvendor"],
      minChunks: function(module, count){
        return count >= 2 && _isVendor(module);
      }
    }),
    

    And now all the entry points have their own vendor and and a shared vendor chunk.

Comments are closed.