webpack中文件打包 hash、chunkhash、contenthash 的区别

318 阅读2分钟

webpack对输出文件名可以有三种hash值:

  1. hash
  2. chunkhash
  3. contenthash

为什么需要hash?

浏览器会缓存我们的文件。

优点是浏览器读取缓存的文件,能带来更佳的用户体验(不需要额外流量,速度更快);

缺点是有时候我们修改了文件内容,但是浏览器依然读取缓存的文件(也就是旧文件),导致用户看到的文件不是最新的。

这也是为什么以前有时需要在js文件后面拼接上一个版本号

eg: https://xxx.cdn.cn/index.js?version=1.1

hash hash是项目级别的,使用hash的缺点是假如我只改了其中一个文件,但是所有文件的文件名里面的hash都是一样的。

这样会导致本来应该被浏览器缓存的文件,强制要去服务器读取一遍,网络请求数变多了,页面加载有可能就变慢了,用户体验就差了。

module.exports = {
	output: {
	        filename: 'js/[name]_[hash:8].js',
	        path: path.resolve(__dirname, '../dist'),
	    },
	    
	plugins: [
	        new MiniCssExtractPlugin({
	            filename: 'css/[name]_[hash:8].css',
	        }),
	    ]
}

image.png

有没有可能做到只有改变了文件,hash值才变,而没有改变的文件,文件名里面的hash值就不变呢? chunkhash可以做到这一点

chunkhash chunkhash根据不同的入口文件(Entry)进行依赖文件解析、构建对应的chunk,生成对应的哈希值。

在生产环境里把一些公共库和程序入口文件区分开,单独打包构建,接着我们采用chunkhash的方式生成哈希值,那么只要我们不改动公共库的代码,就可以保证其哈希值不会受影响。

// entry 加多一个入口
module.exports = {
	entry: {
        app: path.resolve(__dirname, '../src/index.js'),
        test: path.resolve(__dirname, '../src/test/test.js'),
    },
	output: {
	        filename: 'js/[name]_[chunkhash:8].js',
	        path: path.resolve(__dirname, '../dist'),
	    },
	    
	plugins: [
	        new MiniCssExtractPlugin({
	            filename: 'css/[name]_[chunkhash:8].css',
	        }),
	    ]
}

第一次打包

image.png 随便修改了index.js中的一点东西

第二次打包

image.png 第二次打包后发现打包出来的test.js的hash值并没有变化,app.js的hash和第一次的hash不一样了,说明chunkhash做到了,只改变修改的文件的hash。

但是为什么css文件的hash和app文件的hash是一样的,但是css文件并没有被修改,是因为css文件是被import到了index.js中的,css文件和index.js建立了依赖关系,所有它们的chunkhash是一样的,这样还是存在缓存没有被充分利用的问题。

contenthash contenthash是针对文件内容级别的,只有你自己模块的内容变了,那么hash值才改变。

所以我们可以通过contenthash解决上面的问题。

第一次打包

image.png

修改index.js

第二次打包

image.png 两次的css文件的hash是一样的,app.js文件的hash发生了改变