`
jinhailion
  • 浏览: 46204 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

tree-shaking

 
阅读更多
es6的引入是静态的,即编译时就能分析出引入了什么,不需要运行时才能分析。所以import要求写在顶部,是为了静态语法分析。因为require是动态的,所以如果有if条件,它可能就不引入了,但es6的import是没有这些的,所以它的依赖关系在执行前就确定了,require不能确定,万一有个if就不能require了。

最好先了解以下es6但模块语句,看阮的es6教程
1. commonjs中模块输出都是对象
2. es6的模块实际输出的是一段代码,所以可以tree-shaking
3. export const a = 1; export const b = 2; 最后相当于 export {a:1, b;2}
所以引入时不能import a from 'x' 只能 import {a} from 'x'
export default的变量和函数默认变量名为default,引入它时不使用{}解构,同时可以不需要知道变量名,任意命名(说的不是as,而是随便引入一个不存在的名称变量,那么引入的就是default的,而引入其他变量就需要通过对象解构方式指定正确的变量名)。如果要同时引入一个模块中default的和其他不default的内容,用 import xx, {xx, xx} from 'xx' 的方式

https://juejin.im/post/5a4dc842518825698e7279a9
《Tree-Shaking性能优化实践 - 原理篇》
这篇文章提到了什么是dce代码,即不需要tree-shaking,uglifyjs本身就会去除的代码,包括执行不到的代码,定义但未使用的局部变量等。

ast是抽象语法数,babel编译es6或jsx或vue什么的都要基于它,先把代码进行词法分析拆成单词,然后做语法分析,生成抽象语法数,然后再生成想要转变成的形态。

treeshaking是基于es6的import做静态的语法分析,然后去除不需要的代码。在webpack的使用中,还有不少问题,可以看一下掘金的几篇
https://juejin.im/post/5a5652d8f265da3e497ff3de
《你的Tree-Shaking并没什么卵用》

以下的这篇文章,内容比较简单,它里面提到了,webpack的treeshaking还要结合uglifyjs
《webpack 如何优雅的使用tree-shaking》
https://blog.csdn.net/haodawang/article/details/77199980
这篇文章里treeshaking后去掉了无效的export,但原函数还在,再经过uglify去掉了没有使用到的function

使用 uglifyjs-webpack-plugin,做压缩。vue-ssr项目里没有用,build的代码都没有压缩
用draw项目做了实验,去除uglify的使用,如果在入口里定义两个函数,只使用其中一个,最后两个函数都会被打进去,使用了uglifyjs就不会。然后又实验了解构引入某个模块文件里的部分函数的例子,不用uglifyjs效果一样,用了看一下。即使入口中import {name, age} from './dahuang.js'但在入口中假如没有使用age,那么压缩后也不会被打入dahuang里age但声明。

所以webpack必须结合uglifyjs否则无效,至少我在webpack3上时下来是这样的。
这个draw项目也通过webpack.optimize.ModuleConcatenationPlugin 启用了scope hoist



https://zhuanlan.zhihu.com/p/37148975 <React 16 加载性能优化指南>
这篇是以前看的性能优化指南,里面也讲到了tree-shaking时,设置babel的module为false的原因,即关闭babel将es6中import转为commonjs引入的方式,webpack2以后已经可以直接识别import了。和webpack4.0无副作用tree-shaking掉引入但未使用的代码的方式

vscode就能发现引入但没有使用的模块,应该也是类似的检查静态代码的方式

---2020平安离职后的补充---
1. 从给出的文章中知道,uglifyjs本身就有dce的功能,但不能跨文件,所以不能干掉引入的模块里没有用到的代码。
2. tree-shaking必须依赖静态引入,因为是在编译前,静态语法分析。require不行,因为它可能在if条件等里面,依赖关系不确定,只有运行时才能确定依赖关系。
(本质上webpack干的都是静态的分析,比如ast, 因为都在代码运行前干)
tree-shaking结果知识加了注释,同时必须使用uglifyjs才能干掉代码。
3. tree-shaking只能干掉未使用的解构的模块。
(其他未使用的default的模块,例子里class不可以干掉,其他不清楚没有实验过。)
要注意的是,tree-shaking是基于webpack2.0及以上的import功能的支持,2.0前不支持import,需要babel编译的。因此要关闭babel-preset-env的module配置项,关闭将import转为require的编译,因为不再需要了,webpack认识import了。否则tree-shaking会无效,因为你转为了require就不是静态的依赖了。
4. 还是那篇性能文章中提到的。
如果你自己开开发的npm包,设置sideEffect为false。那么即使它有export出的default的模块,在webpack项目中如果import了这个default模块,但未使用到,是会被tree-shaking干掉的,因为明确告知了没有副作用。因为webpack会担心如果有副作用的模块,你引入了这个default出的内容虽然没有用到,但这个模块代码里可能有其他但副作用定义,和输出的东西无关。比如立即执行了什么,或是有css,或是覆盖了Array函数等。
所以个人认为正常情况下default的模块,引入后不使用也会被打入结果。除非它是一个npm包且声明了自己没有副作用。
(sideEffects的讲解,我的pc win电脑上有)





分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics