如果每次构建输出的文件名称是一样的,会给在客户端做长缓存带来很大的麻烦。因此,我们需要在输出的文件名中添加一些 hash 值,使得每次构建输出的文件名称是不一样的。

从 Webpack 5 开始,Webpack 开始使用固定的方式来决定输出的文件名,我们可以通过 optimization.moduleIdsoptimization.chunkIds 这两个字段进行控制。

占位符(placeholder)

Webpack 提供了一些占位符:

  • [id] 返回 chunk id
  • [path] 返回文件路径
  • [name] 返回文件名
  • [ext] 返回文件扩展名
  • [fullhash] 返回本次构建的 hash,如果本次构建过程中有任何一部分发生变化,这个 hash 也会变化
  • [chunkhash] 返回每一个 entry chunk 的 hash。Webpack 配置定义的每一个 entry 都有一个自己的 hash,当 entry 中任何一部分发生变化,这个 hash 也会发生变化。[chunkhash][fullhash] 粒度更细一点。
  • [contenthash] 返回模块内容的 hash。从 Webpack 5 开始,这个 hash 值被默认使用在生产模式构建中。

假设有如下配置:

const config = {
  output: {
    path: PATHS.build,
    filename: '[name].[contenthash].js',
  },
};
1
2
3
4
5
6

Webpack 构建输出的文件名为:

main.d587bbd6e38337f5accd.js
vendor.dc746a5db4ed650296e1.js
1
2

此时,如果文件内容发生变化,则 [contenthash] 也会相应的变化,此时,浏览器缓存就会失效,浏览器就会重新发起一个请求来加载变化了的文件。即,如果仅仅只要 main.js 发生了变化,那么浏览器只会重新请求加载 main.js

我们还可以将 hash 值加载请求参数中,比如 main.js?d587bbd6e38337f5accd, 这样的话,输出文件名不变,通过查询参数的变化来使缓存失效。

使用占位符

webpack.config.js

const productionConfig = merge([
  {
    output: {
      chunkFilename: "[name].[contenthash].js",
      filename: "[name].[contenthash].js",
      assetModuleFilename: "[name].[contenthash][ext][query]",
    },
  },
  ...
]);
1
2
3
4
5
6
7
8
9
10

同时,我们还要给 css 也加上 hash。

webpack.parts.js

exports.extractCSS = ({ options = {}, loaders = [] } = {}) => {
  return {
    ...
    plugins: [
      new MiniCssExtractPlugin({
    //    filename: "[name].css",
        filename: "[name].[contenthash].css",
      }),
    ],
  };
};
1
2
3
4
5
6
7
8
9
10
11

执行 npm run build,可以看到输出如下:

⬡ webpack: Build Finished
⬡ webpack: assets by path *.js 129 KiB
    asset 935.a25ff4285adcf5d835fd.js 126 KiB [emitted] [immutable] [minimized] (id hint: vendors) 2 related assets
    asset main.fdae79f138a0e0cd6a30.js 3.38 KiB [emitted] [immutable] [minimized] (name: main) 1 related asset
    asset 958.1752e720e564a63a9d5f.js 204 bytes [emitted] [immutable] [minimized] 1 related asset
  asset main.dd02bdb46b234aa6a450.css 1.37 KiB [emitted] [immutable] [minimized] (name: main)
  asset index.html 322 bytes [emitted]
  Entrypoint main 131 KiB (182 KiB) = 935.a25ff4285adcf5d835fd.js 126 KiB main.dd02bdb46b234aa6a450.css 1.37 KiB main.fdae79f138a0e0cd6a30.js 3.38 KiB 2 auxiliary assets
  runtime modules 7.92 KiB 10 modules
  orphan modules 465 bytes [orphan] 2 modules
  code generated modules 133 KiB (javascript) 4.18 MiB (css/mini-extract) [code generated]
    modules by path ./node_modules/ 133 KiB
      modules by path ./node_modules/react/ 6.48 KiB 2 modules
      modules by path ./node_modules/react-dom/ 119 KiB 2 modules
      modules by path ./node_modules/scheduler/ 4.91 KiB
        ./node_modules/scheduler/index.js 198 bytes [built] [code generated]
        ./node_modules/scheduler/cjs/scheduler.production.min.js 4.72 KiB [built] [code generated]
      ./node_modules/object-assign/index.js 2.06 KiB [built] [code generated]
    modules by path ./src/ 633 bytes (javascript) 4.18 MiB (css/mini-extract)
      ./src/index.js + 2 modules 600 bytes [built] [code generated]
      css ./node_modules/css-loader/dist/cjs.js!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[0].use[2]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[0].use[3]!./src/main.css 4.18 MiB [code generated]
      ./src/lazy.js 33 bytes [built] [code generated]
  webpack 5.11.1 compiled successfully in 18695 ms
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

现在尝试编辑 main.css,可以发现构建输出的文件名发生了变化。

总结

Webpack 提供的占位符可以帮助我们给输出文件名添加额外信息。

在这些占位符中,最有价值的是 [name], [contenthash][ext][contenthash] 基于文件内容生成 hash 值。

如果要导出 css 文件,即用了 MiniCssExtractPlugin,那么也需要在 css 文件名中使用 [contenthash]

关注微信公众号,获取最新推送~