首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

深入浅出tree-shaking

  • 25-04-23 06:40
  • 4689
  • 5507
juejin.cn

什么是 Tree-shaking?

tree shaking 是一个术语,通常用于描述移除 JavaScript 上下文中的未引用代码 (dead-code) 。

它依赖于 ES2015 模块语法的 静态结构 特性,例如 import 和 export。这个术语和概念实际上是由 ES2015 模块打包工具 rollup 普及起来的。

因此tree-shaking仅针对 ES6 模块语法,因为 ES6 模块采用的是静态分析,从字面量对代码进行分析。

对于必须执行到才知道引用什么模块的 CommonJS 动态分析模块他就束手无策了,不过我们可以通过插件支持 CommonJS 转 ES6 然后实现 tree-shaking

原理:

  • 基于ES Module引入进行静态分析,故而编译的时候正确判断到底加载了那些模块
  • 静态分析程序流,判断那些模块和变量未被使用或者引用,进而删除对应代码

深入Tree-shaking

ECMAScript 6 module

ES6 module 特点:

  • 只能作为模块顶层的语句出现
  • import 的模块名只能是字符串常量
  • import binding 是 immutable的

ES6模块依赖关系是确定的,和运行时的状态无关,因此可以进行可靠的静态分析,判断哪些模块最终没有被引用,这就是tree-shaking的基础。

Dead code

Dead code,也叫死码,无用代码,它的范畴主要包含了以下:

  • 代码不会被执行,不可到达
  • 代码执行的结果不会被用到
  • 代码只会影响死变量(只写不读)

Dead code代码片段举例:

csharp
代码解读
复制代码
function foo() { return 'foo'; var bar = 'bar'; // 函数已经返回了,这里的赋值语句永远不会执行 }
scss
代码解读
复制代码
if(0) { // 这个条件判断语句块内部的代码永远不会执行 }
javascript
代码解读
复制代码
function add(a, b) { let c = 1; // 代码执行的结果不会被用到 return a + b; }
javascript
代码解读
复制代码
// foo.js function foo() { console.log('foo'); } export default foo; // bar.js function bar() { console.log('bar'); } export default bar; // index.js import foo from './foo.js'; import bar from './bar.js'; foo(); // 这里入口文件虽然引用了模块 bar,但是没有使用,模块 bar 也可以被看作死码

Dead code 我们知道了,那么什么是 Tree-Shaking 呢?

在传统的静态编程语言编译器中,编译器可以判断出某些代码根本不影响输出,我们可以借助编译器将 Dead Code 从 AST(抽象语法树)中删除。

但 JavaScript 是动态语言,编译器不能帮助我们完成死码消除,我们需要自己实现 Dead code elimination。

而我们说的 Tree-Shaking,就是 Dead code elimination 的一种实现,它借助于 ECMAScript 6 的模块机制原理,更多关注的是对无用模块的消除,消除那些引用了但并没有被使用的模块。

Webpack的Tree-shaking流程

借助 ES6 模块语法的静态结构,通过编译阶段的静态分析,找到没有引入的模块并打上标记,然后在压缩阶段利用像 uglify-js(现在是terser) 这样的压缩工具删除这些没有用到的代码。

1.Webpack 标记代码

webpack打包过程中,先对代码进行标记,主要是对 import & export 语句标记为 3 类:

  • 所有 import 标记为 /* harmony import */
  • 所有被使用过的 export 标记为/* harmony export ([type]) */,其中 [type] 和 webpack 内部有关,可能是 binding, immutable 等等
  • 没被使用过的 export 标记为/* unused harmony export [FuncName] */,其中 [FuncName] 为 export 的方法名称

2.压缩清除

使用uglify、terser等压缩工具,根据标记以及静态分析程序流,去压缩删除无用代码。

简单来说,就是压缩工具读取 webpack 打包结果,在压缩之前移除 bundle 中未使用的代码。

rollup的Tree-shaking流程

rollup本身内置就是支持tree-shaking的

  1. rollup()阶段,解析源码,生成 AST tree,对 AST tree 上的每个节点进行遍历,判断出是否import(标记避免重复打包),是的话标记,然后生成 chunks,最后导出。
  2. generate()/write()阶段,根据 rollup()阶段做的标记,进行代码收集,最后生成真正用到的代码。

tree-shaking瘦身对比

webpack4的结果:

添加一个dead code函数,这个export并未被引入使用:

启用tree-shaking前:

  • 打包后的代码,仍然存在这个dead code:

使用tree-shaking后:

  • 打包后的代码不存在这个dead code了:

全局查找,未被使用的export只有30个,算是比较少的,所以瘦身效果不算明显:

可以看出,瘦身效果还是有的。当然瘦身效果也是取决于你的代码如何组织,代码有过多的冗余瘦身效果自然会更明显。如果代码本身比较规范,没有冗余的代码,效果就自然不那么明显

注:本文转载自juejin.cn的chiuwingyan的文章"https://juejin.cn/post/7039661255107280927"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top