對於webpack的hash,經常使用於cdn緩存。我理解的是文件不變的狀況下,最後打包出來的hash串也不會變。最近被問到了這是三個hash的區別,就查了一下,發現還頗有講究。css
先看一下三個hash的解釋:react
原代碼:webpack
// file1.js
console.log('file1')
// file2.js
console.log('file2')
// file3.js
console.log('file3')
// index.js
require('./file2')
console.log('index')
// file1.js
require('./file1')
console.log('detail')
// webpack.config.js
const path = require('path')
const webpack = require('webpack')
module.exports = {
// mode: 'development',
// mode: 'production',
entry: {
index: './src/index.js',
detail: './src/detail.js',
},
output: {
filename: '[name].[hash].js',
path: path.resolve(__dirname, 'dist')
},
}
複製代碼
第一次變動:git
// file2.js
require('./file22')
複製代碼
第二次變動:github
// index.js
require('./file2')
require('./file3')
console.log('index')
複製代碼
下面我會以我理解的順序比較一下三個hashweb
每次構建的生成惟一的一個hash,且全部的文件hash串是同樣的。 源代碼構建: 緩存
第一次變動: app
是否是看到非預期的地方了?我只改了file2.js,index.js的hash串變了,可是爲何detail.js爲何也變了?這還怎麼有緩存的做用!不行,升級!ide
每個文件最後的hash根據它引入的chunk決定ui
源代碼構建:
第一次變動:
第二次變動:
緣由是 module identifier,由於 index 新引入的模塊改變了之後全部模塊的 id 值,因此 detail 文件中引入的模塊 id 值發生了改變,因而 detail 的 chunkhash 也隨着發生改變。
不用怕,webpack已經提供方案了,解決方案是將默認的數字 id 命名規則換成路徑的方式。webpack 4 中當 mode 爲 development 會默認啓動,可是production環境仍是默認的id方式,webpack也提供了相應的plugin來解決這個問題
plugins: [
new webpack.HashedModuleIdsPlugin(),
],
複製代碼
加上這個plugin後,再走一遍上述代碼的變動,你會發現第一次、第二次的變動後,detail的hash串仍然沒有變化,符合預期。
在webpack中,有css的狀況下,每一個entry file會打包出來一個js文件和css文件,在使用chunkhash的狀況下,js和css的文件的hash會是同樣的,這個時候暴露出來的一個問題:你修一個react的bug,可是並無改樣式,最後更新後,js和css的文件的hash都變了。這個仍是不太好,css文件的hash串不變最好,再繼續升級!
contenthash是根據抽取到的內容來生成hash。
生產環境是否是會使用一個MiniCssExtractPlugin
來進行css的壓縮,這個時候咱們在這個plugin裏面指定hash爲contenthash
,你會發現修改js文件後,js文件的hash串變了,css的hash串沒變!完美。
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: '[name].[contenthash:8].css',
chunkFilename: '[name].[contenthash:8].chunk.css'
})
複製代碼
將webpack中的所有hash都設置成contenthash的狀況下,僅僅只修改css文件,不改js文件的狀況下,css文件的hash串會變,js文件的不會變,這樣能達到最小更新。
我查了兩個流行的腳手架:create-react-app和umi,發現它們的entry file的配置都是contenthash
output: {
filename: '[name].[contenthash].js',
chunkFilename: 'cfn_[name].[contenthash].js',
},
複製代碼
umi使用了HashedModuleIdsPlugin
來進行穩定的hash構建,可是cra沒有,我看有人已經提issue了:github.com/facebook/cr…,做者說optimization.moduleIds: "hashed"
這個也能知足需求,查了webpack5中optimization.moduleIds是能夠的
因此目前最佳實踐是contenthash
+HashedModuleIdsPlugin/optimization.moduleIds: "hashed"
參考資料: