摇树 Tree Shaking是什么?
摇树优化(Tree Shaking)是Webpack中一种用于优化JavaScript代码的技术。它的目标是通过静态分析,从代码中剔除未被使用的模块,从而减少最终打包文件的大小。
在一个大型的JavaScript应用程序中,通常会引入多个模块和库,但并不是所有的模块都会被使用到。如果没有进行优化,所有引入的模块都会被打包到最终的输出文件中,导致文件变得很大,加载时间变长,影响应用的性能。在以往导入导出有时候是动态的,难以预测的,所以需要通过规范来约束和优化性能。
1、基于ES module 用到才引用
//拿常用的'element-ui'举例
import * as ElementUI from 'element-ui' //这是一种糟糕的方式
import {Submenu,CascaderTable,TableColumn } from 'element-ui' //用到什么引入什么
使用ES6模块化:摇树优化要求代码使用ES6模块化的语法。确保你的代码基于ES6模块化进行编写,而不是使用CommonJS或AMD等其他模块化方案。
2、设置sideEffects
在Webpack中,sideEffects是一个用于优化打包输出的配置选项。它用于指示哪些模块具有 副作用,或者说哪些模块是否会对整个应用程序的行为产生影响,以便Webpack可以进行更有效的处理。
设置sideEffects的目的是告诉Webpack哪些模块没有副作用,以便它可以在打包过程中优化代码。Webpack可以根据这些信息,例如删除未使用的导入、通过摇树优化(tree-shaking)消除未使用的代码等。
sideEffects的设置方式有两种:
2.1 在模块的package.json文件中设置:
{
"name": "your-project",
"sideEffects": false
}
将sideEffects设置为false表示该模块没有副作用。如果你确定某个模块没有副作用,可以将其设置为false,以便Webpack可以进行相应的优化。
2.2 在Webpack配置文件中的module.rules中使用sideEffects选项:
module.exports = {
// ...
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader',
sideEffects: false
}
]
}
};
在相应的规则中,通过将sideEffects设置为false来指定该规则匹配的文件没有副作用。
请注意,设置sideEffects为false可能会导致一些副作用的代码被错误地删除,因此在使用时要谨慎。确保你了解你的代码,并进行适当的测试,以确保没有重要的副作用被错误地优化掉。
2.3 配置副作用文件,避免打包压缩的时候误删
"sideEffects": [
"./src/common.js",
"*.css"
]
在实际过程中,我们会发现,有些css模块是全局,因为没有申明副作用,也一起被移除,所以需要单独排除掉,比如 global.css
模块都没被打包。因为它们都算是副作用模块,而我们在package.json中声明了没有副作用,所以它们就被移除了。
3、配置mode的状态来唤醒摇树优化
配置mode
为production
:在Webpack的配置中,将mode设置为production
模式。这会自动启用一系列的优化功能,包括摇树优化。
使用Webpack的TerserPlugin
:TerserPlugin
是一个用于压缩和混淆JavaScript代码的Webpack插件。它内置了摇树优化功能,并可以通过配置选项进行进一步的优化。确保在Webpack配置中使用TerserPlugin
并进行正确的配置。
4、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__*/
注释,这样在做副作用检查的时候,就可以认为该方法没有副作用,标记为"纯函数",方便删除。这样的好处在于一些特别的测试数据不会出现在线上环境中~