一、Tree Shaking的原理
基于es6(esm)模块,只能在使用exprt、export default、import进行导入导出的文件上生效。删除无用代码主要有两步骤。
-
先标记
-
再剔除----使用的是terser
其中无用代码dead code,示例:
-
1、写了未使用
// 其它地方没有用到
function foo1() {
console.log(1);
}
-
2、引用了未执行,会被剔除
// a.js文件
export function test1(x) {
console.log(x);
}
export function test2(x) {
console.log(x);
}
// b.js文件
// 这里引入,但是test2未执行,是无用代码会被剔除
import { test1, test2 } from './a.js';
test1(1)
-
3、代码执行结果不会被用到
// a.js文件
export function test1(x) {
console.log(x);
}
export function test2(x) {
return 2222222 //这里返回结果
}
// b.js文件
import { test1, test2 } from './a.js';
test1()
test2() //也会被剔除,因为test2的返回结果没有被使用!
如果把test2改一下不返回结果,改为console.log的话,是会保留的因为它没有返回值,这一点需要注意。
注意:如果是全量引入,例如如下,不支持tree shaking。
import lodash from 'lodash'
lodash.clone()
这也是为什么在使用比如element UI或者ant UI组件库时候需要通过import {Button} from 'antd'这种写法的原由。
理解为:要支持tree shaking的方法,前提是需要通过export导出,以及引用对应的模块名称的才可以
// util.js
export default {
test1(target) {
return 1;
},
test2(target) {
return 2;
}
};
// 引入并使用
import util from '../util';
util.test1()
上面这个虽然只使用了,test1,但是test2方法也会被打包,因为它属于模块内的方法,esm静态分析模块间的引用。
二、Tree Shaking开启(开发模式环境)
- webpack.config.js中配置(标记):
module.exports = {
mode: 'development', // 我们先使用开发模式下验证
devtool: 'cheap-module-source-map', //使用source map的这个模式
optimization: {
usedExports: true, // 表示开启使用tree shaking
},
}
上面表示的是tree shaking开启,开启后webpack会对代码中的无效代码进行标记,需要注意的是:这里还不会进行剔除。看下如下示例
- app.js
import { cube } from '../src/pages/index';
cube(5)
- index.js
export function cube(x) {
console.log(1111111111111);
}
export function square(x) {
console.log(222222222222);
}
打包后的未使用的代码前面会有个unused harmony export square标记,表示square这段未使用,说明tree shaking发挥作用了。
注意:想要看到标记的无用代码,
devtool选项只能设置source-map,inline-source-map,hidden-source-map和nosources-source-map其中的一种。原因
- 接着开启代码剔除:webpack.config.js中配置剔除
使用TerserWebpackPlugin ,注意,虽然webpack v5 开箱即带有最新版本,但是还是要手动手动安装这个插件!(我在这里踩坑了)
npm install terser-webpack-plugin --save-dev然后在刚才webpack的配置中加上代码压缩即可:
module.exports = {
mode: 'development',
devtool: 'cheap-module-source-map',
optimization: {
usedExports: true,
minimize: true, // 开启代码压缩,压缩会删除已经标记过的无用代码
},
}
再次build可以看到只留下有用到的代码,并且压缩了代码:
三、production 生产模式
这种模式下,会自动进行tree shaking并且进行代码压缩和剔除。所以不用多余的配置。(前提是安装了TerserWebpackPlugin )
四、sideEffects
为了避免有些副作用代码,而导致生产环境代码被误删除,所以有了这个配置,需要配置在package.json中,副作用我这里的理解是书写了非esm语法的文件或者是原型链上面方法的调用。
例如:使用require、module.exports等,这时候就需要把这个文件加入到里面是一个数组格式具体参考weboack5的side的sideeffects。
一般情况下我们都不会这么写,所以会在package.json文件中加上"sideEffects": false
副作用: 简而言之就是代码可能有其他功能或者用法,tree shaking怕把它给误删了,所以是保留着的,所以说这个代码有副作用,所以即使没用到也不会剔除掉。
//utils.js
function fun1(){
console.log(str);
}
fun1.prototype.test = function(){
return 111
}
Array.prototype.arrTest = function(){
return 222
}
export default fun1;
五、Babel编译问题
最新版本的babel已经做了处理,不用担心它会在使用tree shaking之前把代码转为es5的问题。