一文了解webpack和vite中Tree-Shaking

1、什么是Tree-Shaking

1.1 摇树优化(Tree Shaking)是Webpack中一种用于优化JavaScript代码的技术。它的目标是通过静态分析,从代码中剔除未被使用的模块,从而减少最终打包文件的大小

1.2 Tree-shaking 它的名字来源于通过摇晃(shake)JavaScript代码的抽象语法树(AST),是一种用于优化JavaScript代码的技术,主要用于移除未被使用的代码,使得最终生成的代码包含应用程序中实际使用的部分。这主要用于减小应用程序的体积,提高加载性能。

2、适用范围&实现原理

1.1 适用范围:

Tree Shaking 只支持 ESM (ES6 Module)的引入方式,不支持 Common JS 的引入方式。

摇树优化要求代码使用ES6模块化的语法。确保你的代码基于ES6模块化进行编写,而不是使用CommonJS或AMD等其他模块化方案。

ESM:export + import

Common JS:module.exports + require

javascript 复制代码
// 导入所有内容(不会触发 tree-shaking)
import lodash from 'lodash'
 
// 导入命名导出 (会触发 tree-shaking)
import { debounce } from 'lodash'

注意📢:如果想要做到 tree shaking,那么在引入模块时就应该避免全部引入。应该采用按需引入,才可以触发 tree shaking 机制。

2.2 实现原理

以webpack为例,webpack 会从入口文件开始,对你 import 的代码进行静态分析,如果发现某个模块没有被任何地方使用,就会将该模块标记为 unused harmony exports,并且在生成产物时不再 export 该模块。最后,再将生成产物交给 uglify 或 terser 这样的压缩工具进行处理,此时未被 export 的代码就会被当成死代码删除。 需要注意的是,tree shaking 并不会直接删除代码,只是分析模块依赖关系并去掉未引用代码的 export,真正进行死代码消除的是 uglify 或 terser 这样的压缩工具。

相关配置

javascript 复制代码
// webpack.config.js
module.exports = {
  optimization: {
    usedExports: true, // 开启 tree shaking
    concatenateModules: false, // 关闭模块合并
    minimize: false // 关闭代码压缩
  }
}

3、webpack中的Tree-Shaking

Webpack 5对Tree Shaking进行了改进,可以更有效地删除未使用的代码,从而使打包后的文件更小,加载更快

在 Webpack 中,启动 Tree Shaking 功能必须同时满足三个条件:

  • 使用 ESM 规范编写模块代码
  • 配置 optimization.usedExports 为 true,启动标记功能
  • 启动代码优化功能,可以通过如下方式实现:
    • 配置 mode = production:在Webpack的配置中,将mode设置为production模式。这会自动启用一系列的优化功能,包括摇树优化
    • 配置 optimization.minimize = true
    • 提供 optimization.minimizer 数组
javascript 复制代码
// webpack.config.js
module.exports = {
  entry: "./src/index",
  mode: "production",
  devtool: false,
  optimization: {
    usedExports: true // 启用tree-shaking
  }
}

4、vite中的Tree-Shaking

生产模式下vite会默认开启所有优化通过tree-shaking摇掉未使用代码


Vite中未使用资源仍被打包问题简单参考

5、为什么Tree-shaking失效

5.1 sideEffects副作用

在Webpack中,sideEffects是一个用于优化打包输出的配置选项。它用于指示哪些模块具有副作用 ,或者说哪些模块是否会对整个应用程序的行为产生影响,以便Webpack可以进行更有效的处理。

设置sideEffects的目的是告诉Webpack哪些模块没有副作用,以便它可以在打包过程中优化代码。Webpack可以根据这些信息,例如删除未使用的导入、通过摇树优化(tree-shaking)消除未使用的代码等。

详细说明:https://zhuanlan.zhihu.com/p/260724544

5.2 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)中进行如下配置:

javascript 复制代码
{
  "presets": [
    ["@babel/preset-env", {
      "modules": false
    }]
  ]
}

在上述配置中,将modules选项设置为false,以保持ES6模块的形式。这样Babel在转换代码时就不会将ES6模块转换为CommonJS模块。

通过pure标记一些只在开发环境中,但生产环境不需要的代码

javascript 复制代码
var test = /*#__PURE__*/function () {
  return 996;
}();

在Babel 6之后的版本可以用/#PURE/注释,这样在做副作用检查的时候,就可以认为该方法没有副作用,标记为"纯函数",方便删除。这样的好处在于一些特别的测试数据不会出现在线上环境中~

5.3 export default 会导致 Tree Shaking 失败

javascript 复制代码
import {add} from './add';
import {sub} from './sub';

export default {add, sub}

具体说明:https://zhuanlan.zhihu.com/p/123268547

参考文档:https://zhuanlan.zhihu.com/p/549543919

相关推荐
2401_85763803几秒前
【Perl CGI脚本全解析】打造动态Web应用的秘籍
前端·scala·perl
下一站丶36 分钟前
前端引用vue/element/echarts资源等引用方法Blob下载HTML
前端·vue.js·echarts
前端扎啤1 小时前
高效前端开发:解密pnpm的存储与链接
前端·前端框架·npm·pnpm·依赖
苏十八1 小时前
前端基础:JavaScript(篇一)
开发语言·前端·javascript·面试·html·ecmascript·html5
narukeu2 小时前
React 中 useState 和 useReducer 的联系和区别
前端·react.js·前端框架
38kcok9w2vHanx_2 小时前
v-html 空格/换行不生效
前端·html
shootero@126.com2 小时前
npm常用命令
前端·npm·node.js
余十步2 小时前
Vue整合echarts
前端·vue.js·echarts
QD_ANJING2 小时前
2024年前端面试中面试官常拷打的“项目细节”!
前端·面试·职场和发展