pocket-manual icon indicating copy to clipboard operation
pocket-manual copied to clipboard

Webpack 中 hash、chunkhash 和 contenthash 的区别

Open FishPlusOrange opened this issue 7 years ago • 0 comments

使用 Webpack 添加 hash 是实现前端静态资源在浏览器长缓存方案之一。以下介绍一下 Webpack 中 hash、chunkhash 以及 contenthash 的区别:

hash

hash 可以理解是整个项目的 hash 值,其根据每次编译 compilation 的内容计算得到,每次编译之后都会生成新的 hash,即修改任何文件都会导致所有文件的 hash 发生改变:

output: {
  filename: '[name].[hash].js',
  path: path.join(__dirname, 'dist')
}

所以使用 hash 无法实现前端静态资源在浏览器上长缓存,这时候应该使用 chunkhash

chunkhash

chunkhash 根据不同的入口文件(entry)进行依赖文件解析,构建对应的 chunk,生成相应的 hash:

output: {
  filename: '[name].[chunkhash].js',
  path: path.join(__dirname, 'dist')
}

所以每次编译之后,每个 chunk 的 hash 都是不同的。对于每个 chunk 来说,如果该 chunk 代码不变,那么 hash 也将保持不变,从而实现该资源在浏览器上长缓存。

例如,由于公共库基本上不会随意改动,我们可以把公共库(vendor)和入口文件区分开,使用 chunkhash:

entry: {
  app: path.join(__dirname, 'src/index.js'),
  vendor: ['vue']
},
output: {
  filename: '[name].[chunkhash].js',
  path: path.join(__dirname, 'dist')
}

但是,使用 chunkhash 存在一个问题:当在一个 JS 文件中引入了 CSS 文件,编译后它们的 hash 是相同的。而且,只要 JS 文件内容发生改变,与其关联的 CSS 文件 hash 也会改变。

针对这种情况,可以把 CSS 从 JS 中抽离出来并使用 contenthash

contenthash

使用 mini-css-extract-pluginextract-text-webpack-plugin 把 CSS 文件抽离出来:

// mini-css-extract-plugin
const miniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          miniCssExtractPlugin.loader,
          'css-loader'
        ]
      }
    ]
  },
  plugins: [
    new miniExtractPlugin({
      filename: '[name].[contenthash].css'
    })
  ]
}

FishPlusOrange avatar Jul 15 '18 12:07 FishPlusOrange