前言:随着项目的迭代,项目的代码量越来越大,客户端访问速度越来慢,此时webpack在优化打包体积和配合浏览器进行资源缓存上起到很大作用。
首先要认识hash:
众所周知webpack打包最终会通过output输出到指定目录下指定的文件名filename,如果filename写死成某个文件名,例如index.js,那么当此资源文件被客户端强缓存后,下次修改再次打包成index.js部署到server上,此时若server没有配置协商缓存,那么客户端会认为此资源没有被更新,从而会从本地强缓存取出index.js继续使用。这样就会遇到缓存问题。所以hash的作用就能发挥出来了。通过webpack的output可以配置如下生成唯一资源名称。
output: {
filename: '[name].[hash].js',
path: path.resolve(__dirname, 'dist')
}
webpack 内置了多种可使用的hash,按官网的解释分别如下:
- hash:the hash of the module identifier 和整个项目的构建相关,只要项目文件有修改,整个项目构建的hash值就会改变
- chunkHash:the hash of the chunk content 和webpack打包的chunk有关,不同的entry会生成不同的chunkhash值
- contentHash:the hash of extracted content 根据文件内容来定义hash,文件内容不变,则contenthash不变
注:hash的默认长度是20个字符,可以通过output.hashDigestLength全局配置,或使用[hash:8] 方式配置
1.hash
hash:配置好了hash可以发现每次修改代码后打包出来的资源文件名都不一样。但是如果不做任何修改,文件名可能会变,也可能不会变。官方的解释是:
这也是因为 webpack 在入口 chunk 中,包含了某些样板(boilerplate),特别是 runtime 和 manifest。(译注:样板(boilerplate)指 webpack 运行时的引导代码)
2.抽离boilerplate
输出可能会因为当前的webpack版本而稍有差异,新版本不一定有和旧版本相同的hash问题。为了解决这个不稳定的因素,webpack4提供了一个配置可以把boilerplate给单独提取出来。
optimization: {
runtimeChunk: {
name: 'manifest'
}
}
3.抽离第三方库
如果不做处理,webpack会将我们引用到的第三方库和我们的源代码打包在一起。比较推荐的做法是将第三方库提取出来,输出到vendor chunk文件中,因为它们很少像本地源代码频繁改动。可通过以上方法配合浏览器的强缓存机制,来消除请求,减少客户向server获取资源次数。webpack很牛批的为我们提供了splitChunks。
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
}
}
}
}
manifest.js: 被注入了webpackJsonp的定义及异步加载相关的定义(webpack调用CommonsChunkPlugin处理后模块管理的核心,因为是核心,所以要第一个进行加载,不然会报错).
vendor.js: 将所有从node_modules/里require(import)的依赖都打包到这里,所以这个就是所有node_modules/下的被require(import)的js文件
main.js:项目中自己的代码
4.模块标识符(module identifiers)
项目中新增一个模块进行引用,再次构建,期望只有main bundle的hash发生改变。
但是可以发现vendor的hash也变了,这是因为每个module.id会默认地基于解析顺序进行增量。当解析顺序发生变化,id也会随之变化。所以vendor的module.id发生了变化,从而也生成了新的hash。
webpack提供了一个插件HashedModuleIdsPlugin
plugins: [
// 不再使用id作为打包模块的索引,采用文件路径的hash值
new webpack.HashedModuleIdsPlugin()
]
5.chunkhash
虽然配置好了hash构建出来的所有模块hash都会变,但这是不利于缓存的。因为我可能只修改了一个chunk,另一个chunk没有修改
chunkhash可以做到只针对修改的chunk生成hash,解决了hash的会对所有资源重新生成hash的痛点。
output: {
filename: '[name].[chunkhash].js',
path: path.resolve(__dirname, 'dist')
},
6.css抽离
用了chunkhash,看似是没问题了,其实项目中我们是需要把css代码抽离出来的。通常是用MiniCssExtractPlugin把css给单独提取出来
new MiniCssExtractPlugin({
filename: `[name].[hash].css`
})
7.contenthash
css也是资源文件,也需要缓存。如果css使用hash生成的话,那么当某个模块引用了此css,但是css并没有修改。那重新打包出来的包中,css的hash也会随着重新生成。这很显然没有达到缓存的目的,我们是不希望没有改动的css资源名字被重新生成的。
new MiniCssExtractPlugin({
filename: `[name].[contenthash].css`
})
8.externals:外部扩展
虽然上面通过splitChunks.cacheGroups为我们分离出了第三方库到vendor bundle中,但是我们希望将这些三方包从cdn引入,而不是将他打包。从cdn引入既可以加速客户访问速度,又可以进一步减小vendor打包体积。(下面只举例排除lodash库)
externals: {
lodash: '_'
}
9.写入cdn
通过HtmlWebpackPlugin插件可以生成默认html页面,此时我们准备一个模板文件index.html,将externals掉的三方库通过cdn引入进去,(下面只举例lodash,其他三方库可自行再次引入)
<body>
<script type="text/javascript" src='https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js' crossorigin></script>
</body>
plugins: [
...,
new HtmlWebpackPlugin({
template: path.resolve(__dirname, './index.html')
})
]
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!