webpack 5-
TreeShaking顾名思义是将代码中未使用的代码删除掉,从而减小整个文件的打包体积。
让我们先来看看没有进行Tree Shaking之前的打包文件:
mamth.js:
export function square(x) {
return x * x;
}
export function cube(x) {
return x * x * x;
}
入口文件:
import { cube } from './math.js';
function component() {
const element = document.createElement('pre');
element.innerHTML = [
'Hello webpack!',
'5 cubed is equal to ' + cube(5)
].join('\n\n');
return element;
}
document.body.appendChild(component());
webpack.config.js配置文件:
entry: {
index: './src/index.js'
},
mode: 'development',
optimization: {
usedExports: true
},
webpack进行打包:
eval("/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"cube\": () => (/* binding */ cube)\n/* harmony export */ });\n/* unused harmony export square */\nfunction square(x) {\n return x * x;\n}\n\nfunction cube(x) {\n return x * x * x;\n}\n\n\n//# sourceURL=webpack://webpack/./src/math.js?");
可以看到打包文件中包含了math模块中并未引用的square函数,并没有shaking掉
接下里配置是指打包能够shaking掉未使用的代码:
首先配置package.json,加入sideEffects选项:
"sideEffects": false,
sideEffects是配置有副作用的选项,如果所有模块都没有副作用,就将sideEffects的值设置为false即可。
修改webpack.config.js文件,去掉usedExports,将mode设置为上产模式:
entry: {
index: './src/index.js'
},
mode: 'production',
重新打包,可以看到打包文件被压缩,而且压缩代码并没有Square函数,表示未被使用的代码已经被Three shaking掉了。
webpack 5
sideEffects:
在webpack5中已经自带tree-shaking功能,在打包模式为production时,默认开启 tree-shaking功能。
创建2个文件夹:
index.js:
import tool from './util.js'
// 使用a变量,调用文件里面的a函数,不使用b函数
console.log(tool.add(1, 2))
console.log('hello world')
// 不可能执行的代码
if (false) {
console.log('这是一段不可能执行的代码')
}
// 定义了但是没用的变量
const m = 1
util.js:
function add(a, b) {
console.log(a, b)
return a + b
}
function count(num) {
console.log(num)
return num++
}
export default {
add,
count
}
打包之后可以看到以下几个现象:
- 1,import但是没有使用的代码被删除了
- 2,代码中定义但是没有使用的代码也被删除了
这是webpack自动帮我们做的优化,那么如果我们再util.js中添加副作用的代码呢,也就是可能对当前代码没有作用,但可能对全局有作用的一些副作用代码,比如在util.js中添加如下代码:
Array.prototype.side = function () { console.log('这是一段有副作用的代码') }
如果webpack足够智能,那么它打包过程不应该删除这些副作用,实际上webpack也是这样做的,可以查看打包结果,打包文件中确实保留了副作用代码,那么webpack是怎么做到的呢?它是怎么判断一段代码是否有副作用的呢?原来它是借助了terser这个库。terser是一个ES6+的js解析器、处理程序和代码压缩工具,webpack正是依赖这个库进行js的解析和代码压缩。
如果不进行额外的配置,当对一个模块进行导入的时候,不仅会判断使用了哪些导出的代码,还会分析这个模块是否有副作用存在,如果有副作用存在,依然是要将副作用代码一起打包的。
我们如果在package.json中配置:
"sideEffects": false
此配置告诉webpack不用去分析导入的模块是否有副作用,直接保留使用的导出,其他全部删除即可。配置之后在构建,会发现此时打包文件已经不存在副作用代码了。
sideEffects配置项其实更多是用来声明需要进行副作用分析的模块的。因为在实际开发中不可能所有模块都没有副作用。当我们配置了sideEffects,只有包含在sideEffects中的文件,webpack才会进行副作用分析,如果没有包含在sideEffects配置的属组中,webpack就不会去分析,就算这些文件存在副作用,webpack也不会分析,这些不会分析的副作用最终都会被删除。
"sideEffects": [ "**/*.css" ]
最后附上webpack官网的总结:
usedExports: index.js:
import tool from './util.js'
// 使用a变量,调用文件里面的a函数,不使用b函数
// console.log(tool.add(1, 2))
console.log('hello world')
console.log(tool.add(1, 1))
// 不可能执行的代码
if (false) {
console.log('这是一段不可能执行的代码')
}
// 定义了但是没用的变量
const no_usem = 1
util.js:
function add(a, b) {
console.log(a, b)
return a + b
}
function count(num) {
console.log(num)
return num++
}
Array.prototype.side = function () {
console.log('这是一段有副作用的代码')
}
export default {
add,
count
}
将webpack配置mode='development',查看构建结果:
- 不可执行的代码段会被删除
- 没有引用的代码会被保留
- 引入模块的所有代码都会保留
配置webpack.config.js:
mode: 'development',
optimization: {
minimize: true,
usedExports: true,
},
重新进行打包,结果如下:
- 没有引用的代码没有被删除
- 引入模块的所有代码都会保留
可以看到使用usedExports之后,没有被引用的代码被删除了,这时候仍存在一个问题,如果通过模块化引入另一个js文件,即使没有被使用,useExports 也不会进行 tree shaking。我们希望在引入的文件中也进行 tree shaking,删除无用的代码,这个时候在 package.json 中配置 sideEffects 属性来处理。