1、什么是Tree-Shaking
1.1 摇树优化(Tree Shaking)是Webpack中一种用于优化JavaScript代码的技术。它的目标是通过静态分析,从代码中剔除未被使用的模块,从而减少最终打包文件的大小。
1.2 Tree-shaking 它的名字来源于通过摇晃(shake)JavaScript代码的抽象语法树(AST),是一种用于优化JavaScript代码的技术,主要用于移除未被使用的代码,使得最终生成的代码包含应用程序中实际使用的部分。这主要用于减小应用程序的体积,提高加载性能。
2、适用范围&实现原理
1.1 适用范围:
Tree Shaking 只支持 ESM (ES6 Module)的引入方式,不支持 Common JS 的引入方式。
摇树优化要求代码使用ES6模块化的语法。确保你的代码基于ES6模块化进行编写,而不是使用CommonJS或AMD等其他模块化方案。
ESM:export + import
Common JS:module.exports + require
// 导入所有内容(不会触发 tree-shaking)
import lodash from 'lodash'
// 导入命名导出 (会触发 tree-shaking)
import { debounce } from 'lodash'
注意📢:如果想要做到 tree shaking,那么在引入模块时就应该避免全部引入。应该采用按需引入,才可以触发 tree shaking 机制。
2.2 实现原理
以webpack为例,webpack 会从入口文件开始,对你 import 的代码进行静态分析,如果发现某个模块没有被任何地方使用,就会将该模块标记为 unused harmony exports,并且在生成产物时不再 export 该模块。最后,再将生成产物交给 uglify 或 terser 这样的压缩工具进行处理,此时未被 export 的代码就会被当成死代码删除。 需要注意的是,tree shaking 并不会直接删除代码,只是分析模块依赖关系并去掉未引用代码的 export,真正进行死代码消除的是 uglify 或 terser 这样的压缩工具。
相关配置
// webpack.config.js
module.exports = {
optimization: {
usedExports: true, // 开启 tree shaking
concatenateModules: false, // 关闭模块合并
minimize: false // 关闭代码压缩
}
}
3、webpack中的Tree-Shaking
Webpack 5对Tree Shaking进行了改进,可以更有效地删除未使用的代码,从而使打包后的文件更小,加载更快
在 Webpack 中,启动 Tree Shaking 功能必须同时满足三个条件:
- 使用 ESM 规范编写模块代码
- 配置 optimization.usedExports 为 true,启动标记功能
- 启动代码优化功能,可以通过如下方式实现:
- 配置 mode = production:在Webpack的配置中,将mode设置为production模式。这会自动启用一系列的优化功能,包括摇树优化
- 配置 optimization.minimize = true
- 提供 optimization.minimizer 数组
// webpack.config.js
module.exports = {
entry: "./src/index",
mode: "production",
devtool: false,
optimization: {
usedExports: true // 启用tree-shaking
}
}
4、vite中的Tree-Shaking
生产模式下vite会默认开启所有优化通过tree-shaking摇掉未使用代码
Vite中未使用资源仍被打包问题:简单参考
5、为什么Tree-shaking失效
5.1 sideEffects副作用
在Webpack中,sideEffects是一个用于优化打包输出的配置选项。它用于指示哪些模块具有副作用,或者说哪些模块是否会对整个应用程序的行为产生影响,以便Webpack可以进行更有效的处理。
设置sideEffects的目的是告诉Webpack哪些模块没有副作用,以便它可以在打包过程中优化代码。Webpack可以根据这些信息,例如删除未使用的导入、通过摇树优化(tree-shaking)消除未使用的代码等。
详细说明:https://zhuanlan.zhihu.com/p/260724544
5.2 babel-loader使Tree-shaking失效
使用Babel Loader确实有可能导致Tree-shaking失效,这是因为Babel Loader默认情况下会将所有ES6模块转换为CommonJS模块,而CommonJS模块的导入和导出方式是动态的,无法在编译时进行静态分析。
为了解决这个问题,你需要在Babel配置中进行相应的调整,以保持ES6模块的静态导入和导出,从而使Tree-shaking能够正常工作。
首先,确保你安装了@babel/preset-env插件,并在Babel配置文件(通常是.babelrc或babel.config.js)中进行如下配置:
{
"presets": [
["@babel/preset-env", {
"modules": false
}]
]
}
在上述配置中,将modules选项设置为false,以保持ES6模块的形式。这样Babel在转换代码时就不会将ES6模块转换为CommonJS模块。
通过pure标记一些只在开发环境中,但生产环境不需要的代码
var test = /*#__PURE__*/function () {
return 996;
}();
在Babel 6之后的版本可以用/#PURE/注释,这样在做副作用检查的时候,就可以认为该方法没有副作用,标记为"纯函数",方便删除。这样的好处在于一些特别的测试数据不会出现在线上环境中~
5.3 export default 会导致 Tree Shaking 失败
import {add} from './add';
import {sub} from './sub';
export default {add, sub}
具体说明:https://zhuanlan.zhihu.com/p/123268547
参考文档:https://zhuanlan.zhihu.com/p/549543919