Webpack configuration for better bundle monitoring

The RelativeCI bundle analyzer1 works with any webpack configuration, though some configuration options can make it easier to identify changes between builds and notice regressions quicker. Also, some recommended webpack configuration options improve long-term caching and application web performance for returning users.

Use a common pattern with content hashes for file names

Adding the content hash suffix to asset names helps browsers cache the responses and only request from the server when the content of the asset changes. This method improves the performance for returning users because they only need to download the changed assets.

When comparing asset names between different builds, bundle-stats1 removes the hash and compares the assets by the normalized path. The supported patterns are:

# hex hash
**/*.HASH.EXT
**/*-HASH.EXT
**/*_HASH.EXT
**/*~HASH.EXT
# base64url hash
**/*.HASH.EXT
**/*~HASH.EXT

To configure asset file names, you can set the following options for the production mode config:

webpack.config.js
module.exports = {
output: {
// Configure entry file names
filename: '[name].[contenthash].js',
// Configure chunk file names
chunkFilename: '[name].[chunkhash].js',
// Configure asset file names
assetModuleFilename: '[path][name].[contenthash][ext][query]'
},
plugins: [
// CSS file name pattern when using mini-css-extract-plugin
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css'
})
]
}

assets by path *.js 10.5 KiB
asset vendors.f1eef34c98603711f45e.js 8.71 KiB [emitted] [immutable] [minimized] (name: vendors) (id hint: vendors)
asset main.7c920d907e4c753d0935.js 1.79 KiB [emitted] [immutable] [minimized] (name: main)
asset images/logo.31b9235056a3dc35c4c5.png 6.4 KiB [emitted] [immutable] [from: images/logo.png] (auxiliary name: main)
asset index.html 364 bytes [emitted]
asset main.b231cc1c6e07b9d4ff06.css 122 bytes [emitted] [immutable] (name: main)
webpack.config.js
module.exports = {
output: {
// Configure entry file names
filename: '[name].[contenthash].js',
// Configure chunk file names
chunkFilename: '[name].[chunkhash].js'
},
module: {
rules: [
// file name pattern when using file-loader
{
test: /\.(png|jpe?g|gif)$/i,
loader: 'file-loader',
options: {
name: '[path][name].[contenthash].[ext]'
}
}
]
},
plugins: [
// CSS file name pattern when using mini-css-extract-plugin
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css'
})
]
}

Asset Size Chunks Chunk Names
images/logo.31b9235056a3dc35c4c5d9806ab46e4f.png 6.4 KiB [emitted] [immutable]
index.html 336 bytes [emitted]
main.63b96e941d400fc1b806.css 122 bytes 0 [emitted] [immutable] main
main.d7df904f48c9631839e8.js 1.75 KiB 0 [emitted] [immutable] main
vendors.0e025fde233b62c30823.js 8.72 KiB 1 [emitted] [immutable] vendors

You can adjust the hash length globally using the output.hashDigestLength option (default 20). The bundle-stats hash replacement supports a minimum of 5 characters.

Name asynchronous chunks

Asynchronous chunks defer code loading/execution, decrease the initial JS/CSS size, and improve the loading performance. By default, webpack uses the chunk ID for the chunk file name. When the chunk ID changes, the chunk name will be different, forcing the users to re-download the asset even if there are no code changes.

To output predictable asset names for chunks, use webpack annotation for async chunks:

const HomePageComponent = React.lazy(
() => import(/* webpackChunkName: 'home' */'./pages/home')
);
const DetailsPage = Loadable({
loader: () => import(/* webpackChunkName: 'details' */'./pages/details'),
loading: Loading
});

Use deterministic chunk IDS(webpack 4)

By default, webpack 4 generates chunk IDs based on their order of appearance ('natural' algorithm). The chunk IDs map can change across related chunks when the order changes or a chunk is added/removed. The change causes unnecessary cache invalidation and does not allow RelativeCI to compare the chunk modules between different builds.

To generate deterministic chunk IDs between different builds, you can use the optimization.chunkIds option:

webpack.config.js
module.exports = {
optimization: {
chunkIds: 'named'
}
}

By default, webpack 5 uses the chunkIds: 'deterministic' option. Read more



[1]: bundle-stats is an open-source standalone tool that analyzes webpack/rspack/vite/rollup bundle stats and generates an in-depth report with insights and metrics for assets, modules and packages. Read more about RelativeCI open-source projects