webpack稳定moduleid和chunkid以实现静态资源强缓存
- hash的种类:
hash
是跟整个项目的构建相关,只要项目里有文件更改,整个项目构建的hash值都会更改,并且全部文件都共用相同的hash值chunkhash
它根据不同的入口文件(Entry)进行依赖文件解析、构建对应的chunk,生成对应的哈希值, 比如一个js文件中引入css,但是会生成一个js文件,一个css文件,但是因为入口是一个,导致他们的hash(chunkhash)值也相同,所以当只有js修改时,关联输出的css、img等文件的hash值也会改变,但是入口js所引用的css、img的发生改变,整个chunkhash是不会发生变化contenthash
主要是处理关联性,比如一个js文件中引入css,但是会生成一个js文件,一个css文件,但是因为入口是一个,导致他们的hash(chunkhash)值也相同,所以当只有js修改时,关联输出的css、img等文件的hash值也会改变,这种情况下就需要contenthash了
根据以上hash的特性,我们知道我可以使用contenthash来完成静态文件的强缓存,但是当把其中入口js中所引用的css、img等文件删除掉后,会发现打包后,所有的hash都发生变化了,至于是为什么,那是因为moduleId发生了变化,moduleId即对于胶水代码中的那个文件map的key,所以要保证静态文件的稳定moduleId, 最终的打包代码中通过__webpack_require__(moduleId)去加载对应的chunk, moduleId是一个数字
保持稳定的moduleId
- 改变moduleId的生成规则
- 何时去改变moduleId
- 由于文件的路径是唯一的,所以这里采用文件的路径做为moduleID
- 在整个webpack打包的过程中涉及到moduleId的钩子有三个:
- before-module-ids
- optimize-module-ids
- after-optimize-module-ids
我们在before-module-ids这个钩子里修改moduleId, 见插件代码:
class moduleIDsByFilePath {
constructor(options) {}
apply(compiler) {
compiler.plugin('compilation', compilation => {
compilation.plugin("before-module-ids", (modules) => {
modules.forEach((module) => {
// 通过module.libIdent获取模块的路径
if(module.id === null && module.libIdent) {
module.id = module.libIdent({
context: this.options.context || compiler.options.context
})
}
})
})
})
}
}
module.exports = moduleIDsByFilePat
不过上述的插件已经被webpack官方抽成一个插件了,NamedModulesPlugin
, 我们只需要在插件中使用new webpack.NamedModulesPlugin()
即可,不过官方说 NamedModulesPlugin
适合在开发环境,而在生产环境下请使用 HashedModuleIdsPlugin
保持稳定的chunkId
在我们的entry chunk数量没有发生变化的时候,改变一个entry chunk的内容导致runtime内容发生变化的只有chunk id,这个时候问题就又来了。根据上面稳定module id的操作一样,数值型的chunk id不稳定性太大,我们要换,方式和上面一样。chunkId也是有相关的钩子
- before-chunk-ids
- optimize-chunk-ids
- after-optimize-chunk-ids
下面见修改chunkId的插件:
class chunkIDsByFilePath {
constructor(options) {}
apply(compiler) {
compiler.plugin('compilation', compilation => {
compilation.plugin('before-chunk-ids', chunks => {
chunks.forEach(chunk => {
chunk.id = chunk.name
})
})
})
}
}
同样的webpack官方也是提供了插件,NamedChunksPlugin
综上所述,通过contentHash保证保证静态文件的hash稳定,而通过保证moduleId的稳定进一步保证在module发生变化的时候,contentHash能够不发生变化, 最后通过保持chunkId稳定,保持runtime.js不会发生变化,进而保证静态文件能够被浏览器强缓存,减少网络请求
对于webpack5缓存优化
当
moduleIds和chunkIds
设置为natural
时,每个module.id 和 chunk.id
会默认地基于解析顺序(resolve order)进行增量。也就是说,当解析顺序发生变化,ID 也会随之改变
- webpack5对于生产模式下,
moduleIds和chunkIds
会默认设置为deterministic