Tree-Shaking
是什么
用于消除项目中没有被使用到的模块(引用了却没有被使用)
DEMO
demo1
- rollup.config.js
import babel from 'rollup-plugin-babel'
export default {
input: 'src/main.js',
treeshake: true,
output: {
file: 'rollup.bundle.js',
format: 'cjs'
},
plugins: [
babel()
]
};
- 主入口
import arg from './arg'
import { add } from './func'
import Clazz from './clazz'
export default function() {
console.log(add(1, 2))
}
- arg.js
export default 'hello world!';
- clazz.js
export default class Clazz {
constructor() {
this.name = 'Clazz'
}
getName() {
return this.name
}
}
- func.js
export function add(a, b) {
return a + b
}
export function sub(a, b) {
return a - b
}
打包后的代码
'use strict';
function add(a, b) {
return a + b
}
function main() {
console.log(add(1, 2));
}
module.exports = main;
可以发现,我们打包后的代码中,消除掉了没有用到的arg
模块、clazz
模块、以及func
模块中的sub
函数。这可以证明,函数、类、变量都是可以被Tree-shaking掉的
。
demo2
我们在func.js
中添加一行:
export function add(a, b) {
console.log(sub(a - b))
return a + b
}
export function sub(a, b) {
return a - b
}
此时add
方法会调用同包内的另一个方法。
再进行打包操作,打包结果:
'use strict';
function add(a, b) {
console.log(sub(a - b));
return a + b
}
function sub(a, b) {
return a - b
}
function main() {
console.log(add(1, 2));
}
module.exports = main;
问题
在这篇文章中Tree-Shaking性能优化实践 - 原理篇 - 掘金,作者提到,类不能被消除。
这是因为作者使用了Babel对代码进行了预编译。Babel会添加含有副作用的函数,导致Tree-shaking失效。
原理
ES6模块的特点
- 只能在顶层引用
- 模块名是字符串常量
- 依赖关系是确定的
ES6之前的模块
- 可以在代码中动态引用
- 可能和运行状态有关,也有可能和运行状态无关,依赖关系不确定
- 模块名可能是变量
模块名确定、依赖关系确定,代码文件可以进行“静态分析”,这给Tree-Shaking奠定了基础。
静态分析就是不执行代码,从字面量上对代码进行分析。ES6之前的模块化,我们可以动态require一个模块,只有执行后才知道引用什么模块,这就不能通过静态分析去优化。(from: Tree-Shaking性能优化实践 - 原理篇 - 掘金)
思考
调研Tree-shaking的使用与原理可以带来两点思考
1. 代码优化
在实际写工具类代码的时候,不要使用一个对象并将方法挂载在这个对象上,然后export default
这个对象的写法。最好采用export function
依次输出函数方法。这样在打包工具进行分析时可以更好的进行Tree-Shaking
。
书写函数的时候要减少函数的副作用,尽量少在函数体内使用函数体外的变量,立即执行函数内少用函数体外的变量。
在制作模块的时候尽量将代码进行拆分,尽量不要在模块内直接写会带来副作用的操作。
2. 打包优化
经过以上的调研,我们发现使用babel
会给代码带来一定的副作用,因此我们可以尝试先将代码进行打包,之后再将打包好后的代码使用babel
转译一下。
推荐使用rollup
工具进行打包。然而目前rollup
的生态系统还不是那么完善,而且rollup
工具还存在一定的功能限制,所以更多的还是使用webpack
工具进行打包。
另外,也可以了解一下webpack
中的sideEffects
属性Webpack 中的 sideEffects 到底该怎么用? · Issue #41 · kuitos/kuitos.github.io · GitHub