Tree-Shaking性能优化

# 什么是 Tree-shaking
上图形象解释了 Tree-shaking 的本意。在 webpack 项目中,有一个入口文件,相当于一颗树的主干,入口文件有很多依赖的模块,相当于树枝。实际情况中,虽然依赖了某个模块,但其实只使用其中的某些功能。通过 tree-shaking,将没用的模块摇调,这样达到删除无用代码的目的。
现支持 tree shaking 的工具有 Rollup (opens new window)、Webpack (opens new window)、closure-compiler (opens new window).
DCE(dead code elimination): 编译器可判断出某些代码不影响输出,然后消除这些代码。 Tree-shaking 是 DCE 的一种新的实现,传统的 DCE 消灭不可能执行的代码,而 Tree-shaking 消除没有用到的代码。
# DCE
- 代码不会被执行,不可到达
- 代码执行的结果不会被用到
- 代码只会影响死变量(只写不读)
js 的 DCE 由 uglify 完成
中间为 rollup 打包的结果,右边是 webpack 打包的结果
rollup 将无用的代码 foo/unused 函数消除了,但仍保留不会执行到的代码,而 webpack 则完整保留了无用代码和不会执行的代码
分别用 rollup + uglify 和 webpack + uglify 将代码进行打包
中间为配置文件,右侧是结果,可看出结果中都去除了无法执行的代码
# tree-shaking 原理
# ES6 module 特点
- 只能作为模块顶层的语句出现
- import 的模块名只能是字符串常量
- import binding 是 immutable 的
ES6 模块依赖关系是确定的,和运行时的状态无关,可以进行可靠的静态分析,这是 tree-shaking 的基础。 所谓静态分析就是不执行代码,从字面量上对代码进行分析,ES6 之前的模块化,动态 require 一个模块,只有执行后才知道引用什么模块,不能通过静态分析做优化。
面向过程编程和面向对象编程,从这两个方面来实验
函数消除实验
utils 中 get 方法没有被使用到,我们期望 get 方法最终被消除 注意:uglify 目前不支持跨文件做 DCE,所以上面这种情况,uglify 是不能优化的
上图 rollup 打包结果,符合预期
上图 webpack 打包结果,也符合预期,但是没有 rollup 更优化
类消除实验
,Closure Compiler 使用起来也比较麻烦,所以虽然效果很赞,但比较难以应用到项目中,迁移成本较大。
# 总结
三大工具的 tree-shaking 对于无用代码,无用模块的消除,都是有限的,有条件的。closure compiler 是最好的,但与我们日常的基于 node 的开发流很难兼容。 tree-shaking 对 web 意义重大,是一个极致优化的理想世界,是前端进化的又一个终极理想。