提及ugilfy,这是目前前端工程化里最重要的伙伴之一,经过对代码的压缩混淆,它给咱们带来了多种好处:前端
而前端工程化的象征——webpack
,从1.0时期起就内置了uglify插件,简单的配置便可使用该功能。webpack
webpack 1.0~3.0均内置的插件,它伴随前端工程的服役时间最长,同时期也没有太多的竞争者,Closure
一直被批评过于激进,使用者寥寥。git
可是,它有一个从诞生起就伴随的缺陷,仅支持ES5代码。随着浏览器的兼容性需求愈来愈低,不少非现代浏览器都已经逐步被市场淘汰,chrome近几年每一年都会升4个大版本。github
慢慢的,原生的简洁ES6代码已经能够在浏览器里运行了,这时候uglify-js
就显的有点笨重。对于ES5代码再压缩,可能也比不上直接输出ES6代码呀。web
此外,还有一个危险的信号:chrome
在前端界,你们都会去研究和讨论类库的实现,但对于工程上的工具项目,却知之甚少。对于开源项目,输入越多,它越健壮;相反的,关注的少,场景输入少,项目变得黑盒化的同时,也埋下了致命bug的种子。前端工程化
在时代推进下,迫切须要uglify-js
能够解析ES6代码,因而uglify-es
诞生。webpack 4.0随着自身内部的一次大革新,将uglify-es
内置,并于今年初面世。api
可是。。。我用了还不到半年就遇到一个致命bug。浏览器
诡异的是,由于没有深究uglify源码,构建出的简单示例并不会出现该问题。网络
示例代码以下:
// Parent.jsx
import Child from './Child'
class Parent extends React.PureComponent {
onChange = () => {
// 触发rerender
}
render() {
return <div><Child onChange={this.onChange} /></div> } } // Child.jsx class Child extends React.PureComponent { componentWillMount() { fetch('/api').then(this.props.onChange) } render() { return <div /> } } 复制代码
最终压缩后的代码形如:
// Parent.js的render函数
return React.createElement(
'div',
null,
React.createElement(class Child extends PureComponent {})
)
复制代码
能够看到,Child因为只被一处引入,因此再也不是独立模块,甚至被处理成了内联。
在js语法里这样处理,彷佛没什么问题,可是当处理的是包含生命周期的组件时,就触发了严重的问题,该Child组件会被不断的销毁和建立,引发死循环。
因为部分“玄学”缘由,我没找到稳定复现该bug的写法。。。
解决方式是在uglify配置中关闭reduce_vars和reduce_funcs:
uglifyOptions: {
compress: {
reduce_vars: false,
reduce_funcs: false,
},
}
复制代码
这仅仅是我碰到的问题,搜一下uglify-es
的bug,会发现,这项目确实有点哔——(消音),它已经从并肩做战的战友成功升级成4v6了。。。
随着uglify-es
再也不维护(我用着的时候都不知道= =!),webpack也悄悄的更改了内置uglify依赖:
uglify-es is no longer maintained
其实还有不少项目也进行了调整:
Switch minifier from uglify-es to terser
看样子terser是从uglify-es
fork出来的项目,目前看来,该项目维护者很是活跃,在不少uglify-es
的bug issue下都会看到他宣传terser没有bug的身影~
但愿该项目能够从新赢回开发者们的信任,让前端工程更完善,效率更高!