javascriptwebpackwebpack-2commonschunkplugin

webpack2 CommonsChunkPlugin with manifest file, only generates the last file in the "names[]" array if minChunks is a function


webpack version

2.2.1

I'm trying to add an additional manifest file in order to bypass webpacks runtime code injection issue and enable caching:

https://webpack.js.org/guides/code-splitting-libraries/#manifest-file

however, when passing a function into minChunks, in this case - in order to automatically get all the files that are in node_modules inside the vendor.js chunk - will result an unexpected outcome: only the last file in the array (manifest, in the example below) is generated.

webpack.config.js

entry: {
        bundle: "./src/index.tsx",
    },
    output: {
        filename: "[name].js?[chunkhash]",
        path: `${projectRoot}/dist`
    },
    plugins: [new webpack.optimize.CommonsChunkPlugin({
        names: ['vendor', 'manifest'],
        minChunks: function (module) {
            return module.context && module.context.indexOf('node_modules') !== -1;
        }
    })]

expected output

3 files: bundle.js, vendor.js and manifest.js

actual output

2 files: bundle.js, manifest.js


Solution

  • I observed that with the config above, the webpack v2.2.1, would create just the last one (i.e. manifest in your case) as it first thinks vendor as parent for the 'bundle' bundle and process ... next it thinks manifest as parent of 'bundle' bundle and process which would overwrite the previous processing. Finally while generating bundle, it create two bundle, the 'bundle' bundle and its parent - manifest bundle. I am not sure why it behaves like this with v2.2.1.

    You would want to write your config like this

     plugins: [new webpack.optimize.CommonsChunkPlugin({
            name: 'vendor',
            chunks: ["bundle"], //optional
            minChunks: function (module) {
                return module.context && module.context.indexOf('node_modules') !== -1;
            }
        }), 
         new webpack.optimize.CommonsChunkPlugin({
          name: "manifest",
          chunks: ["vendor"],
          minChunks: Infinity
        })]
    

    The trick here is that with the first plugin instance, you will be extracting the modules coming from node_modules to the vendor bundle. Since this is the parent common bundle, webpack will add its runtime code into vendor bundle (if the second instance of plugin is not added). Then with the application of second instance of the plugin, using minChunks as Infinity, you will not be extracting any module, but you will make the manifest bundle as parent bundle for vendor, hence, webpack will add its runtime code into the manifest bundle.

    You need to make sure that manifest script should get executed first, then vendor script and finally bundle script. In other words, load them sequentially to avoid unexpected errors.