文/米酒
前段时间在某个项目进行需求开发的时候,该项目是基于 webpack3 进行打包构建的。在开发过程当中我发现打包很慢,开发体验不佳,因而作了简单的优化并梳理了优化方案css
进行优化的第一步须要知道咱们的构建到底慢在那里。经过 speed-measure-webpack-plugin
测量你的 webpack 构建期间各个阶段花费的时间:前端
// 分析打包时间
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin")
const smp = new SpeedMeasurePlugin()
// ...
module.exports = smp.wrap(prodWebpackConfig)
复制代码
咱们能够看到打包速度慢主要是由于对样式文件和对 js 文件的处理 loader 耗时较久node
当文件发生修改,进行从新编译时,此时的打包各阶段时间以下webpack
从新编译时耗时其实并不久,可是在浏览器上实际上却花费了更多的时间在看到了新的修改,这是为什么呢web
"analyse": "webpack --config ./webpack.config.js --profile --json>states.json"复制代码
咱们能够看到在使用 webpack 3.5.6 进行打包的过程当中涉及到了 705 个模块,生成了 2 个 chunks, 耗时约 51sjson
打包出的两个 chunks 文件分别为 app 和 vendor 文件,其中 app.js 文件体积高达 6M浏览器
在绝大多数的状况下,应用刚开始工做时,并非全部的模块都是必需的。若是这些模块所有被打包到一块儿,即使应用只须要一两个模块工做,也必须先把 bundle.js 总体加载进来,并且前端应用通常都是运行在浏览器端,这也就意味着应用的响应速度会受到影响,也会浪费大量的流量和带宽。缓存
开发环境下的 bunlde 依赖表也能看出 node_modules 中大部份内容是随着 app.js 一块儿打包,这些就是引发咱们打包速度缓慢的元凶bash
这意味着,每次代码修改,浏览器都会从新加载这个 6M 大的文件,因此为啥改了一点点内容,浏览器也须要好久才有反应,元凶在这app
Entrypoints are code that are loaded on page load. To get best possible user experience, you should keep the total size of entrypoints to less than 200kb and load the rest dynamically by using code splitting.
咱们将 json 文件上传到 Bundle optimize Helper 获得的优化建议是去进行代码分割,入口文件的代码体积不要超过 200K
高达 6M 的入口文件显然是很是影响体验的,所以优化的第一步就是从代码分割开始。代码分割经过把项目中的资源模块按照咱们设计的规则打包到不一样的 bundle 中,从而下降应用的启动成本,提升响应速度。
new webpack.optimize.CommonsChunkPlugin({
name: 'common',
minChunks: function(module) {
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, './node_modules')
) === 0
)
}
})
复制代码
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
chunks: ['vendor', 'common', 'app']
}),
复制代码
能够看到此时 app.js 中以来的一些三方库被单独抽取出来了,体积从 6M 降至 3.49 M
当咱们的业务代码发生修改时,会从新进行打包,而依赖的三方库并不会从新打包,此时从新打包的业务代码 app.js 体积也为 3.49M
咱们能够看到没有变动的依赖包会走 304 协商缓存,而有变动的 app.js 的会从新请求而且由于体积比以前小,加载性能获得了优化
在前面的速度分析中咱们已经知道了打包速度主要耗费在 loader 的处理上
很显然在开发过程当中进行 webpack 缓存是极其有必要的,咱们在处理样式文件和 js 文件的 loader 以前添加 cache-loader 将结果缓存到磁盘中,能够显著提高二次构建速度
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: ['cache-loader', ...loaders],
include: path.resolve('src'),
},
{
test: /\.scss$/,
use: ['cache-loader', ...loaders],
include: path.resolve('src'),
},
],
},
};
复制代码
加入缓存后咱们能够看到打包速度有了显著的提高
进行优化后咱们能够看到:优化后入口包体积缩小 42%,打包速度从 51s 提高至 11s
wepack 的打包优化没有固定的模式,须要咱们针对项目去进行分块、拆包、压缩等,常见的优化思路主要分为四部分
在当前的生产构建时会使用 UglifyJsPlugin 来进行代码压缩,但这个插件是单线程的,压缩时会将代码先解析为 AST 抽象语法树,而后根据规则去分析和处理 AST, 最后再将处理后的 AST 还原为 JS 代码,这种涉及大量运算的操做都是很是耗时的。在 Webpack4 中内置了 TerserPlugin 来处理 JS 代码的压缩,咱们能够开启多进程压缩模式,能够进一步优化咱们的打包速度
咱们对 chunks 进行代码分割,但目前 app.js 在未压缩的状况下体积为 3.49M,依然比较大,Webpack4 中 splitChunks 中提供了更为丰富的配置规则,咱们能够将代码中公共的部分抽取出来,以及异步加载的模块进行抽取,这样也能够进一步优化代码体积
考虑到项目的稳定性,咱们将延后进行 webpack 的升级改造。
以上是本次基于 webpack 优化项目开发体验的小结。了解 webpack 的打包原理,使用 webpack 新特性,必定能够给咱们带来更佳的开发体验。