在 production 模式下, Tree Shaking是默认开启的。
tree shaking 是一个术语,通常用于描述移除 JavaScript 上下文中的未引用代码(dead-code);
关联 - 函数副作用(函数式编程) 一个函数会、或者可能会对函数外部变量产生影响的行为
- 这个术语和概念实际上是由 ES2015 模块打包工具 rollup 普及起来的。
使用场景
Tree-shaking帮助我们删除掉没用到的代码。Tree-shaking这样的功能对于构建大型应用是非常好的,因为日常开发经常需要引用各种库。但大多数时候,仅仅使用了这些库的某些地方,并非需要全部,此时Tree-shaking如果能帮助我们删除掉没有使用的代码,将会大大缩减打包后的代码量。
Tree-shaking的原理
百度外卖前端:Tree-Shaking性能优化实践 - 原理篇
总结:1.ES6的模块引入是静态分析的,故而可以在编译时正确判断到底加载了什么代码;2.分析程序流,判断哪些变量未被使用、引用、进而删除此代码。
原理非常完美,那为什么我们的代码又删不掉呢? - 主要是副作用惹的锅。
副作用
了解过函数式编程的同学对副作用这词肯定不陌生。它大致可以理解成:一个函数会、或者可能会对函数外部变量产生影响的行为。
举例说明
function go (url) {
window.location.href = url
}
这个函数修改了全局变量location,甚至还让浏览器发生了跳转,这就是一个有副作用的函数。
现在我们了解了副作用了,但是细想来,我写的组件库也没有什么副作用啊,我每一个组件都是一个类,简化一下,如下所示:
// componetns.js
export class Person {
constructor ({ name, age, sex }) {
this.className = 'Person'
this.name = name
this.age = age
this.sex = sex
}
getName () {
return this.name
}
}
export class Apple {
constructor ({ model }) {
this.className = 'Apple'
this.model = model
}
getModel () {
return this.model
}
}
// main.js
import { Apple } from './components'
const appleModel = new Apple({
model: 'IphoneX'
}).getModel()
console.log(appleModel)
用rollup在线repl尝试了下tree-shaking,也确实删掉了Person,传送门
可是为什么当我通过webpack打包组件库,再被他人引入时,却没办法消除未使用代码呢?
因为我忽略了两件事情:babel编译 + webpack打包
成也babel,败也babel
Babel不用我多解释了,它能把ES6/ES7的代码转化成指定浏览器能支持的代码。正是由于它,我们前端开发者才能有今天这样美好的开发环境,能够不用考虑浏览器兼容性地、畅快淋漓地使用最新的JavaScript语言特性。
然而也是由于它的编译,一些我们原本看似没有副作用的代码,便转化为了(可能)有副作用的。