Webpack 5 shared chunk file name

Viewed 848

(Apologies if this has been asked and answered previously - I tried to search for a solution but was not able to find anything).

I'm upgrading an app from webpack 4 → 5.

The app has two entrypoints: "app" and "admin".

The goal is to reproduce the same outputs that webpack 4 did, specifically:

/dist/admin.js      // admin chunk
/dist/admin~app.js  // shared chunk for app + admin
/dist/app.js        // app chunk
/dist/runtime.js    // webpack runtime chunk (from runtimeChunk: "single")
/dist/vendor.js     // vendor chunk (node_modules)

The webpack 4 the config was:

entry: {
  app: "app",
  admin: "admin"
},
output: {
  filename: "[name].js"
},
optimization: {
  moduleIds: "hashed",
  splitChunks: {
    chunks: "all",
    cacheGroups: {
      vendor: {
        name: "vendor",
        test: /[\\/]node_modules[\\/]/
      }
    }
  },
  runtimeChunk: "single"
}

This produces the expected output.

In webpack 5, we can now remove output.filename and optimization.moduleIds since those are the defaults, but everything else largely remains the same:

entry: {
  app: "app",
  admin: "admin"
},
optimization: {
  splitChunks: {
    chunks: "all",
    cacheGroups: {
      vendor: {
        name: "vendor",
        test: /[\\/]node_modules[\\/]/
      }
    }
  },
  runtimeChunk: "single"
}

However, this produces the following output:

/dist/121.js        // shared chunk for app + admin
/dist/admin.js      // admin chunk
/dist/app.js        // app chunk
/dist/runtime.js    // runtime chunk
/dist/vendor.js     // vendor chunk

Note that the shared chunk that was previously named admin~app.js now has (what appears to be) a hashed module id as the name (121.js).

I am guessing that the difference is perhaps related to this change in the docs:

  • In webpack 4, the [name] placeholder is described as "The module name"
  • In webpack 5, the [name] placeholder is described as "The name of the chunk, if set, otherwise the ID of the chunk"

I know it's pedantic and it shouldn't really matter whether the file is called admin~app or 121 but is there a way that I can have the shared chunk named as it was in webpack 4?

1 Answers

I use a version of the code in this example in the docs: https://webpack.js.org/plugins/split-chunks-plugin/#splitchunksname

This might work for you but I actually don't split out the node modules and just have a single cache group that includes vendor and non-vendor chunks but I use the same special name function. I have no idea how or why it works but it seems to do what I mostly want.

{
    //...
    optimization: {
        // Factor the webpack runtime out into a single dependency rather than
        // baking it into each entry point.
        // Include it before the other deps for each entry point.
        runtimeChunk: 'single',
        splitChunks: {
            cacheGroups: {
                vendor: {
                    test: /[\\/]node_modules[\\/]/,
                    name: function (module, chunks, cacheGroupKey) {
                        const moduleFileName = module
                            .identifier()
                            .split('/')
                            .reduceRight((item) => item);
                        // This is taken from the documentation but there
                        // seems to be no great explaination but it seems
                        // to be what we need, joining the entry point names
                        // together by ~.  We can then determine which chunk/file
                        // needs to be loaded by each entry point.
                        const allChunksNames = chunks.map((item) => item.name).join('~');
                        return `${cacheGroupKey}-${allChunksNames}-${moduleFileName}`;
                    },
                    chunks: 'all',
                    priority: -10,
                    reuseExistingChunk: true
                },
                commons: {
                    priority: -20,
                    reuseExistingChunk: true,
                    name: function (module, chunks, cacheGroupKey) {
                        const moduleFileName = module
                            .identifier()
                            .split('/')
                            .reduceRight((item) => item);
                        // This is taken from the documentation but there
                        // seems to be no great explaination but it seems
                        // to be what we need, joining the entry point names
                        // together by ~.  We can then determine which chunk/file
                        // needs to be loaded by each entry point.
                        const allChunksNames = chunks.map((item) => item.name).join('~');
                        return `${cacheGroupKey}-${allChunksNames}-${moduleFileName}`;
                    },
                    // Automatically split all code as needed into separate files.
                    chunks: 'all'
                },
            }
        }
    }
}

My config looks more like this:

{
    //...
    optimization: {
        // Factor the webpack runtime out into a single dependency rather than
        // baking it into each entry point.
        // Include it before the other deps for each entry point.
        runtimeChunk: 'single',
        splitChunks: {
                commons: {
                    name: function (module, chunks, cacheGroupKey) {
                        const moduleFileName = module
                            .identifier()
                            .split('/')
                            .reduceRight((item) => item);
                        // This is taken from the documentation but there
                        // seems to be no great explaination but it seems
                        // to be what we need, joining the entry point names
                        // together by ~.  We can then determine which chunk/file
                        // needs to be loaded by each entry point.
                        const allChunksNames = chunks.map((item) => item.name).join('~');
                        return `${cacheGroupKey}-${allChunksNames}-${moduleFileName}`;
                    },
                    // Automatically split all code as needed into separate files.
                    chunks: 'all'
                },
            }
        }
    }
}
Related