Tree Shaking

一、解决的问题

Tree-shaking 去除无用代码,从而减小文件体积。

二、什么是Tree Shaking

Tree-shaking (摇树) 是一个术语,通常指通过打包工具"摇"我们的代码,将未引用代码 (Dead Code) "摇" 掉。在 Webpack 项目中,有一个入口文件,相当于一棵树的主干,入口文件有很多依赖的模块,相当于树枝,虽然依赖了某些模块,但其实只使用其中的某些方法,通过 Tree Shaking ,将没有使用的方法摇掉,这样来达到删除无用代码的目的。

三、原理

程序会从入口文件出发扫描所有的模块依赖,以及模块的子依赖 ,然后将它们链接 起来形 一个 "抽象语法树 " (AST)。随后,运行所有代码 ,查看哪些代码是用到过的做好标记 。最后,再 "抽象语法树"中没有用到的代码"摇落" 。经历这样一个过程后,就去除了没有用到的代码。

前提是模块必须采用 ES6 Module 语法,因为 Tree Shaking 依赖 ES6 的静态语法:import 和 export。不同于 ES6 Module,CommonJS 支持动态加载模块 ,在加载前是无法确定模块是否有被调用 ,所以并不支持 Tree Shaking 。如果项目中使用了 babel 的话, @babel/preset-env 默认将模块转换成 CommonJs 语法,因此需要设置 module:false

CommonJS 与 ES6 Module 模块的依赖的区别在于,CommonJS 是动态的 ,ES6 Module 是静态的

CommonJS 导入时,require 的路径参数是支持表达式的,路径在代码执行时是可以动态改变的,所以如果在代码编译阶段就建立各个模块的依赖关系,那么一定是不准确的,只有在代码运行了以后,才可以真正确认模块的依赖关系,因此说CommonJS 是动态的。

ES6 模块不是对象,它的对外接口只是一种静态定义,在代码编译,静态解析阶段就会生成,这样我们就可以使用各种工具对JS模块进行依赖分析,优化代码。

四、sideEffects

webpack v4 开始新增了一个 sideEffects 特性,通过给 package.json 加入 sideEffects: false 声明该包模块是否包含副作用,从而可以为 Tree Shaking 提供更大的优化空间。 举例说明

arduino 复制代码
js
复制代码
// a.js
// 无副作用,仅仅是单纯的 export
function a () {
  console.log('a')
}
export default {
  a
}
javascript 复制代码
js
复制代码
// b.js
function b () {
  console.log('b')
}

// 执行了特殊行为
Array.prototype.fun = () => {}

export default {
  b
}

如果 a 在 import 后未使用,Tree Shaking 完全可以将其优化掉;但是 b 在 import 后未使用,但因为存在他还执行了为数组原型添加了方法,副作用还是会被保留下来 。这时就需要使用 sideEffects: false ,可以强制标识该包模块不存在副作用,那么不管它是否真的有副作用,只要它没有被引用到,整个 模块/包 都会被完整的移除。

如果你的项目中存在一些副作用代码 b 需要被保留下来,比如 polyfill、css、scss、less 等,可以按下面方法一样配置;保证必要的代码不被 Tree Shaking

json 复制代码
json
复制代码
// package.json
{
  "name": "your-project",
  "sideEffects": ["./src/b.js", "*.css"]
}

四、配置条件

  • 使用 ES6 Module 语法(即 importexport)。
  • 确保没有 @babel/preset-env等工具将 ES6Module 语法转换为 CommonJS 模块。
  • optimization: { minimize: true, usedExports: true }
  • 使用支持 Tree Shaking 的包。

五、引用

# 带你了解 Tree Shaking

相关推荐
袁煦丞40 分钟前
【局域网秒传神器】LocalSend:cpolar内网穿透实验室第418个成功挑战
前端·程序员·远程工作
江城开朗的豌豆41 分钟前
Vuex数据突然消失?六招教你轻松找回来!
前端·javascript·vue.js
好奇心笔记1 小时前
ai写代码随机拉大的,所以我准备给AI出一个设计规范
前端·javascript
江城开朗的豌豆1 小时前
Vue状态管理进阶:数据到底是怎么"跑"的?
前端·javascript·vue.js
用户21411832636021 小时前
dify案例分享-Dify v1.6.0 重磅升级:双向 MCP 协议引爆 AI 生态互联革命
前端
程序员海军1 小时前
AI领域又新增协议: AG-UI
前端·openai·agent
我想说一句1 小时前
React待办事项开发记:Hook魔法与组件间的悄悄话
前端·javascript·前端框架
真夜1 小时前
CommonJS与ESM
前端·javascript
LaoZhangAI1 小时前
GPT-image-1 API如何传多图:开发者完全指南
前端·后端
G等你下课1 小时前
从点击到执行:如何优雅地控制高频事件触发频率
前端·javascript·面试