记一次webpack优化 --- 从babelrc和UglifyPlugin下手
优化前
先来看优化前打包速度 大的第三方库大概有vue+axios+vueRouter+vuex+elementUI(datepicker, message两个插件)+jquery 打包总体积为2648k, 一共14个chunk(使用了异步路由)
在我本地打包一次需要31s
而在服务器打包时候则要70s以上, 这里就不贴图了.
优化后
优化后时间 打包总体积上升为2700k, 上升了50k
本地打包18s
服务器打包时间40s
提升很明显有没有
修改了哪些地方?
UglifePlugin
主要修改地方还是在UglifyPlugin配置中 由于我是用的并不是webpack自带的,而是独立的uglifyjs-webpack-plugin
其实官方使用的也是这个插件. 只不过官方使用的暂且不是最新版,而webpack4.0-beta已经使用此插件最新版本
用法很简单
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
plugins: [new UglifyJsPlugin()]
}
如果使用默认配置,那么打包速度并不会有提升.
而且uglifyplugin在打包过程中其实也会进行一些压缩优化,比如内敛静态变量等等.
那么我们可以从这里面入手,去除一切不必要的压缩优化.可以提升压缩速度.
同时.我们需要开启parallel和cache选项,对压缩进行缓存和多线程执行
具体配置规则请参考官方文档UglifyOptions
我的最终配置如下
new UglifyEsPlugin({
parallel: true,
cache: true,
sourceMap: true,
uglifyOptions: {
ecma: 8,
// 详细规则
// https://github.com/mishoo/UglifyJS2/tree/harmony#minify-options
compress: {
// 在UglifyJs删除没有用到的代码时不输出警告
warnings: false,
// 删除所有的 `console` 语句
drop_console: true,
// 将()=>{return x} 转成 ()=>x
// 关闭.eslint有做检查
arrows: false,
// 转换类似!!a ? b : c → a ? b : c
// 关闭.eslint做检查
booleans: false,
// 转换由计算得来的属性名 {["computed"]: 1} is converted to {computed: 1}.
// 关闭,eslint做检查
computed_props: false,
// 自动转换判断
// e.g. a = !b && !c && !d && !e → a=!(b||c||d||e) etc.
// 关闭,请自行做规范
comparisons: false,
// 去掉死代码
// 关闭.eslint做检查
dead_code: false,
// 关闭debugger
// eslint做检查
drop_debugger: false,
// 自动进行静态算术计算
// 开启
evaluate: true,
// 函数声明提升
// 默认就是关闭,不需要开启
hoist_funs: false,
// For example: var o={p:1, q:2}; f(o.p, o.q); is converted to f(1, 2);
// 不需要咯
hoist_props: false,
// 变量提升
// 不需要咯
hoist_vars: false,
// optimizations for if/return and if/continue
// 不需要, eslint做检查
if_return: false,
/**
* 无法用言语表达,自行理解
* inline (default: true) -- inline calls to function with simple/return statement:
false -- same as 0
0 -- disabled inlining
1 -- inline simple functions
2 -- inline functions with arguments
3 -- inline functions with arguments and variables
true -- same as 3
*/
inline: false,
// join consecutive var statements
// 就是将变量声明合并到一个var中
// 关闭, eslin做检查
join_vars: false,
// 自动去除无用的function参数
// 关闭. eslint做检查
keep_fargs: false,
// Pass true to prevent Infinity from being compressed into 1/0
// 禁止将infinity转成1/0
keep_infinity: true,
// optimizations for do, while and for loops when we can statically determine the condition.
// 优化循环
// 此处关闭,应该由开发者自行优化
loops: false,
// negate "Immediately-Called Function Expressions" where the return value is discarded, to avoid the parens that the code generator would insert.
// 自行体会
negate_iife: true,
// rewrite property access using the dot notation, for example foo["bar"] → foo.bar
// 关闭.eslint检查
properties: false,
// 将只用到一次的function,通过inline方式插入
// 关闭.开发者自行把控
reduce_funcs: false,
// 将静态变量直接lnline紧代码里
// 可以开启
reduce_vars: true,
// 使用逗号运算符连接连续的简单语句
// 自行把控
sequences: false,
/**
* Pass false to disable potentially dropping functions marked as "pure".
* A function call is marked as "pure" if a comment annotation \/*@__PURE__*\/ or \/*#__PURE__*\/ immediately precedes the call.
* For example: \/*@__PURE__*\/foo();
* 就是关闭标注纯函数的注释了
*/
side_effects: false,
// 去掉重复和无法到达的switch分支
// eslint做检查, 以及开发者把控
switches: false,
// Transforms typeof foo == "undefined" into foo === void 0
typeofs: false,
}
}
其实很多优化点都是可以通过eslint来检查,而不需要在压缩过程检查
再配合自身的开发习惯以及规范,可以去掉很多压缩检查, 压缩效率就能提升
但是带来的负面影响就是压缩体积会有上升/
因为对于第三方库来说,并不会安装项目配置的eslint来跑.自然就达不到要求.
再少了uglifyplugin的压缩优化,体积就会上升.
以我的例子来看,总体积上升了50k. 尚可以接受.
而打包时间足足提升了30s.
但可能也有人说上线打包不必在乎打包时间.
其实这些都看具体业务需求,以及自身的开发规范来配置.
重要的还是在打包速度和打包体积两者中找出一个最合适的平衡点
babelrc
其实babel并不会影响到打包速度.我也只是顺便提下
我的配置如下
{
"plugins": [
[
"component",
[{
"libraryName": "element-ui",
"styleLibraryName": "theme-default"
}]]
],
"comments": false,
"env": {
"development": {
"plugins": ["transform-object-rest-spread", "syntax-dynamic-import"]
},
"production": {
"presets": [["es2015", {"modules": false}], "stage-2"],
"plugins": ["transform-runtime"]
},
"test": {
"presets": ["env", "stage-2"],
"plugins": ["transform-runtime", "istanbul"]
}
}
}
我把babel配置区分成了三个阶段,开发,生产和测试.
在开发过程不使用preset,直接跑原生代码.
在生产环境则使用es2015的preset
也许这样能提高开发环境的编译速度? 暂时不清楚,因为没感觉.一向很快.
这也看个人喜好了.
ps
eslint的作用真的很大很大.
但是在开发阶段使用eslint真的很烦很烦.
所以,我目前的做法就是在开发阶段关闭eslint检查.因为我的vscode有带插件提示
即便检查到有错误,也可以正常编译.
但是在commit的时候添加了一层pre-commit来对修改的文件执行eslint.
这样就确保上传到git的代码是经过eslint检查的
这样既能确保开发不被干扰,也能确保代码能按照规范.