简单介绍 farm 中的 tree-shaking

前言

鉴于大家可能对 rust 不是很了解,就尽量不贴代码了,用图和文字来描述整个过程。

由于我的 rust 水平也是一坨大便,如果有讲的不对的地方,谢谢大哥们指正。

正文

前置条件

首先做 tree-shaking 前,我们的模块关系肯定是梳理完毕的,比如 a 模块中引用了模块 b,那么 b 就是 a 的 dependence,基于这个条件,我可以把整个 modules 看出一个图,里面也包括了循环依赖啊,一个模块被多次引用啊这些玩意。

Shake步骤

大致分为以下5个步骤。

1. 排序 sort modules

为什么要 sort modules?

  1. 找到所有模块的引入顺序,保证在该模块做 tree shaking 的时候,以它作为 dependence 的模块都已经 tree shaking 完毕。

就像这个图,比如 B 模块中 import 了 D 模块中的 name,C 模块中 import 了 D 模块中的 age ,那么在 D 模块做 shake 的时候,我们必须保证 B 和 C 已经 shake 过了,不然我们不知道谁使用了 D 模块中的内容。

  1. 找到模块关系中的循环依赖的环,因为循环依赖的模块是不做 shake 处理的。

怎么做

  1. 首先对模块图进行深度优先遍历(先输出子元素,再输出父元素),记录下访问过的模块的 id,重复的模块不再重新访问,如果在访问的时候发现循环依赖,则把这几个模块加入到记录循环模块的数组中。
  1. 将 sort 后的 modules 数组反转
    原因

    图中反转后的顺序就变成了 [a, d, h, i, j, c, g, b, f, e] ;

    观察 f 在上图中,反转前,其实是 b 先引用的 f ,反转后,由于 c 后面没有 f,但是 shake c 的时候,我们就能知道 c 引用了 f 中的内容,所以轮到 f 模块的时候,我们已经能知道 c 和 b 中都引用了哪些内容,就可以进行 shake 了。

  2. 将循环依赖链路中的 module 都标记为 side-effects: true ,后续不进行 shake。

2. 中间操作

  1. 把所有的入口文件(index.tsx)标记为 side-effects,不做 shake
  2. 把非 js|jsx 模块,和外部引入的模块(external)排除,不做 shake。

3. 为每个需要 tree shake 的 module 生成一个 treeModule

根据 module 已有的一些信息,生成一个专门用于 tree shake 的结构体

yaml 复制代码
{
  module_id: 模块id,
  side_effects: 模块是否有副作用,
  module_system: esm 或者 cjs,
  stmt_graph:
  	记录模块de ast 中 语句(statement) 和 变量(ident) 的关系,cjs 为空,因为不做 shake,
  used_exports:
    模块中被使用的导出,side_effects 为 true 的,记为全部导出被使用(不做 shake),不然初始值
    为空数组(后续遍历时记录被使用的 exports 然后添加进来)
}

4. 遍历 treeModule,开始进行 shake

  1. 如果 module 不是 esm ,那么把 module 中所有引入的 module 的 used_exports 也记为 ALL,不做 shake

  2. 如果 module 是 esm,但是 side_effects 为 true,则根据引入模块的语句,按需把引用的内容作为 used_exports 的标记。

    比如:
    import b from 'b'; 就把 b 模块标记为 used_exports::ALL;
    import { b } from 'b'; 就把 b 的 tree shake 结构体中的 used_exports 数组中加入 b。

  3. 如果 module 是 esm 且 side_effects 为 false,就开始正常的 shake 操作。

    1. 先根据前面当前模块 used_exports 中的标记和 ast 树的语句分析,找出被使用过的语句,然后通过对语句中的变量分析,反推出使用了那些引入的依赖,得到 used_import 和 used_export
    2. 然后和上文的步骤一样,根据引入的依赖标记引入模块中的 used_eports。
  4. 把一部引入的模块都标记 side_effects 为 true

5. 删除所有导出都没有被使用的模块

如何删除无用的语句

简单介绍介绍 shake 步骤中第四步中,是如何删除 useless 的语句的。

  1. 首先在生成 treeModule 的时候,把文件中的每个语句都分别进行初始化,生成一个对应的 stmt_id 和对应的语句信息,包括语句的 export、import 信息,语句中使用了哪些变量,定义了哪些变量,是否是自执行(比如 for,while)。

  2. 通过收集到的 usedExports 可以知道哪些 export 的内容被使用了,通过语句中收集的变量,可以知道那些语句是被使用了的,然后依次反推,哪些变量被使用,又可以得知哪些语句被使用了,最后就能得到 used_statement,然后删除没有被使用到的语句。

  3. 最后统计下变量中使用的 import 语句中的内容,标记引入模块中的 usedExport,继续遍历下一个 Module。

盗图:

由于我的画图水平也是一坨大便,就偷一下 pshu 老师的图来帮助理解一下,如果通过 export 找到被使用过的语句。

相关推荐
爱吃的强哥3 分钟前
vue3 使用 vite 管理多个项目,实现各子项目独立运行,独立打包
前端·javascript·vue.js
谈不譚网安12 分钟前
CSRF请求伪造
前端·网络安全·csrf
TT模板17 分钟前
苹果cmsV10主题 MXonePro二开优化修复开源版
前端·html5
拖孩18 分钟前
【Nova UI】十一、组件库中 Icon 组件的测试、使用与全局注册全攻略
前端·javascript·vue.js·ui·sass
去伪存真24 分钟前
不用动脑,手把手跟着我做,就能掌握Gitlab+Jenkins提交代码自动构部署
前端·jenkins
天天扭码1 小时前
深入解析 JavaScript 中的每一类函数:从语法到对比,全面掌握适用场景
前端·javascript·面试
小希爸爸1 小时前
4、中医基础入门和养生
前端·后端
kooboo china.1 小时前
Tailwind CSS 实战:基于 Kooboo 构建企业官网页面(一)
前端·css·编辑器
uhakadotcom1 小时前
Fluid:云原生数据加速与管理的简单入门与实战
前端
鬼面瓷2 小时前
CAPL编程_03
前端·数据库·笔记