前言
这是webpack实战系列第12篇。
上两篇中,描述了一些关于生产环境的配置:环境变量的使用、配置文件描述、source-map配置、资源压缩等,从这几个方面入手来对生产环境进行一定的配置。
本篇将从缓存
和资源bundle体积
开始,来对生产环境进行进一步的处理。
1. 缓存
“缓存是指重复利用浏览器已经获取过的资源。
合理的使用缓存是提升客户端性能的一个关键因素。具体的缓存策略(如指定缓存时间)由服务器来决定,浏览器会在资源过期前一直使用本地缓存进行响应。但同时也带来一个新的问题,比如我们想要对代码进行一个bug fix(故障修正程序),并且立即更新到用户的浏览器中,而不要让他们使用旧的缓存资源应该怎么处理呢?那此时最好的办法便是更改资源的URL,这样可迫使所有客户端资源都去下载最新的资源。
1.1 资源hash
一个常用的方法是在每次打包的过程中对资源的内容计算一次hash,并作为版本号存放在文件名中,如bundle@0sd5fd6fh8hf4g4d.js。其中,bundle是文件本身的名字,而@后则跟随文件内容hash值,每当代码发生变化时,hash也会发生相应变化。
我们通常使用chunkhash来作为文件版本号,因为它会为每一个chunk单独计算一个hash值。如:
代码语言:javascript复制// webpack.config.js
module.exports = {
entry: './src/index.js',
output: {
filename: '[name]@[chunkhash].js'
},
mode: 'production'
}
打包结果:
打包结果
1.2 输出动态HTML
既然资源名字使用hash动态,那么也就意味着在HTML文件中引入的路径也会随之改变,而如果选择手动处理,不光是维护成本大,而且复杂程度相当高:如果有几十个文件变动……因此最理想的情况是打包结束后自动将最新的资源名字同步过去。此时,我们使用html-webpack-plugin来做到这一点:
代码语言:javascript复制// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
index: './src/index.js',
},
output: {
filename: '[name]@[chunkhash].js'
},
mode: 'development',
plugins: [
new HtmlWebpackPlugin()
],
}
打包结果:
打包后,可以看到除了js文件之外还多出来了一个HTML文件:
打包结果
index.html 内容
代码语言:javascript复制<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Webpack App</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<script src="index@61b65a6278687c007c6c.js"></script>
</body>
</html>
从html内容可以看出,html-webpack-plugin会自动将我们打包出来的资源名放入index.html中,如上述的src="index@61b65a6278687c007c6c.js
(其中 @是@的编码 ),这样我们便不再需要手动的去更新资源url了。
HTML模板
虽然是我们通过html-webpack-plugin创建出来一个index.html文件,但是在大多数情况下,此种条件并不符合我们项目工程中的常规操作,因为我们需要在HTML中引入一些个性化的内容,这这是,我们可以传入一个已有的HTML模板,如:
代码语言:javascript复制<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>自定义配置模板</title>
</head>
<body>
<div id="app"></div>
<p>随便一些内容...</p>
</body>
</html>
webpack配置
代码语言:javascript复制const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
...
plugins: [
new HtmlWebpackPlugin({
template: './index.html'
})
]
}
然后再次打包,结果如下:
打包结果
2. 体积监控和分析
为保证良好的用户体验,我们可以对打包输出的bundle体积进行持续的监控,以防止不必要的冗余模块被添加进来。
介绍两个工具来协助我们对体积进行监控和分析。
2.1 Import Cost
在VS Code中,安装插件Import Cost
,这个插件可以帮助我们对引入的模块大小进行实时监测。每在我们代码中引入一个新的模块后,它会为我们计算该模块压缩后及gzip后将占用体积的大小。
体积监测
当我们检测到引入的某些模块包过大时,我们可以想办法处理它,比如寻找一些更小的包或模块作为替代方案,或者引入其子模块而不是全局引入。
2.2 webpack-bundle-analyzer
“作用:分析一个bundle的构成。
安装
代码语言:javascript复制yarn add webpack-bundle-analyzer
// or
npm install webpack-bundle-analyzer --save-dev
配置
代码语言:javascript复制// webpack.config.js
const WebpackBundleAnalyzer = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
entry: {
index: './src/index.js',
},
output: {
filename: '[name]@[chunkhash].js'
},
mode: 'development',
plugins: [
new WebpackBundleAnalyzer()
],
}
打包
执行打包命令,然后会从本地浏览器自动打开一个包体积监测的页面,如下:
包体积分析
从上图我们可以直观的看到生成的 index@hash.js 文件中包含的各个模块及其占体积占比,这样我们也能直观的看出需要从某个模块进行优化。
2.3 bundlesize 自动化监测
那刚才所描述的只是打包后查看,如果希望自动化的对资源体积进行监控呢?bundlesize 这个工具则可以协助我们做到。
同样,先安装:
代码语言:javascript复制yarn add bundlesize
// or
npm install bundlesize
然后在 package.json 中配置:
代码语言:javascript复制{
"name": "w1",
"version": "1.0.0",
"main": "index.js",
"bundlesize": [
{
"path": "./src/index.js",
"maxSize": "10 kB"
}
],
"scripts": {
"test:size": "bundlesize"
}
...
}
可以看到,我设置了 bundlesize 的路径及最大体积限制,然后在 scripts 中添加了一条脚本命令。然后在终端执行该脚本,如图:
体积限制监控
小结
对生产环境配置做个小结。
在开发环境中,我们注重打包速度,而生产环境中我们则关注资源输出体积大小及如何优化客户端缓存来缩短页面渲染时间,通过一系列配置可以优化,如:设置环境变量、代码压缩、资源体积检测监控等方法。我们也对缓存的控制有一定的了解,缓存的控制主要依赖于chunk内容生成hash作为版本号,并添加到资源文件名中,使得资源更新后客户端可以及时更新最新资源。
此外,source map主要用于线上问题的追溯,不过存在安全隐患,可以通过一些特殊的配置来兼顾追溯及安全问题。
描述完了生产环境配置,那么下一阶段来到打包优化问题。