Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Tree Shaking

Tree Shaking

作者头像
政采云前端团队
发布于 2022-12-01 03:16:30
发布于 2022-12-01 03:16:30
82600
代码可运行
举报
文章被收录于专栏:采云轩采云轩
运行总次数:0
代码可运行

前言

Javascript 绝大多数情况需要通过网络进行加载再执行,加载的文件越小,整体执行时间更短,所以就有了 Tree Shaking 去除无用代码,从而减小文件体积。

什么是 Tree Shaking

Tree-shaking (摇树) 是一个术语,通常指通过打包工具"摇"我们的代码,将未引用代码 (Dead Code) "摇" 掉。在 Webpack 项目中,有一个入口文件,相当于一棵树的主干,入口文件有很多依赖的模块,相当于树枝,虽然依赖了某些模块,但其实只使用其中的某些方法,通过 Tree Shaking,将没有使用的方法摇掉,这样来达到删除无用代码的目的。

Tree Shaking 具体做了什么

我们通过例子来详细了解一下 Webpack 中 Tree Shaking 到底做了什么

  • 未使用的函数消除
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// utils.js
export function sum(x, y) {
  return x + y;
}

export function sub(x, y) {
  return x - y;
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// index.js
import { sum } from "./utils";
// import * as math from "./utils";

console.log(sum(1, 2));

我们在 utils 中定义了 sum 与 sub 两个方法, 仅使用了 sum 方法,而 sub 方法并没有被使用。我们一起看一下打包后的结果

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
(()=>{"use strict";console.log(3)})();
  • 未使用的 JSON 数据消除
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// main.json
{
  "a": "a",
  "b": "b"
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// index.js
import main from "./main.json";

console.log(main.a);

可以看到仅使用了 JSON 中的 a。我们一起看一下打包后的结果

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
(()=>{"use strict";console.log("a")})();

Tree Shaking 的原理

Tree Shaking 在去除代码冗余的过程中,程序会从入口文件出发,扫描所有的模块依赖,以及模块的子依赖,然后将它们链接起来形成一个 “抽象语法树” (AST)。随后,运行所有代码,查看哪些代码是用到过的,做好标记。最后,再将“抽象语法树”中没有用到的代码“摇落”。经历这样一个过程后,就去除了没有用到的代码。

前提是模块必须采用 ES6 Module 语法,因为 Tree Shaking 依赖 ES6 的静态语法:import 和 export。不同于 ES6 Module,CommonJS 支持动态加载模块,在加载前是无法确定模块是否有被调用,所以并不支持 Tree Shaking 。如果项目中使用了 babel 的话, @babel/preset-env 默认将模块转换成 CommonJs 语法,因此需要设置 module:false

CommonJS 与 ES6 Module 模块的依赖的区别在于,CommonJS 是动态的,ES6 Module 是静态的

CommonJS 导入时,require 的路径参数是支持表达式的,路径在代码执行时是可以动态改变的,所以如果在代码编译阶段就建立各个模块的依赖关系,那么一定是不准确的,只有在代码运行了以后,才可以真正确认模块的依赖关系,因此说 CommonJS 是动态的。

ES6 模块不是对象,它的对外接口只是一种静态定义,在代码编译,静态解析阶段就会生成,这样我们就可以使用各种工具对 JS 模块进行依赖分析,优化代码。

Development 模式下
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// webpack.config.js

module.exports = {
  // mode: "production",
  mode: "development",
  devtool: false,
  optimization: {
    usedExports: true, // 目的使未被使用的 export 被标记出来
  },
};

打包后的 bundle.js

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */   "sum": () => (/* binding */ sum)
/* harmony export */ });
/* unused harmony export sub */
function sum(x, y) {
  return x + y;
}

function sub(x, y) {
  return x - y;
}

1、可以看到未被使用的 sub 会被标记为 /* unused harmony export sub */,不会被 __webpack_require__.d 进行 exports 绑定;

“关于 __webpack_require__.d 的含义,可参考 [深入了解 webpack 模块加载原理] https://segmentfault.com/a/1190000024457777 一文。

2、经过压缩工具(UglifyJSPlugin)压缩后,未使用的接口代码会被删除。原理显而易见,未被 __webpack_require__.d 引用,所以压缩工具可以将其安全移除。

Production 模式下

由前面的例子可以看出 dist/bundle.js 中整个 bundle 都已经被 压缩工具 压缩和混淆破坏,但是如果仔细观察,则不会看到引 sub 函数,但能看到 sum 函数的混淆破坏版本(function r(e){return e*e*e}n.a=r)。

再看一下两次打包的文件体积会发现,bundle 的体积明显减少了。

Tree Shaking 和 sideEffects

提到 Tree Shaking 就要聊一下 sideEffects。什么是 sideEffects ,sideEffects 又是与 Tree Shaking 如何搭配使用的?

sideEffect (副作用) 的定义是,在导入时会执行特殊行为的代码,而不是仅仅暴露一个 export 或多个 export。

webpack v4 开始新增了一个 sideEffects 特性,通过给 package.json 加入 sideEffects: false 声明该包模块是否包含副作用,从而可以为 Tree Shaking 提供更大的优化空间。

举例说明

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// a.js
// 无副作用,仅仅是单纯的 export
function a () {
  console.log('a')
}
export default {
  a
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// b.js
function b () {
  console.log('b')
}

// 执行了特殊行为
Array.prototype.fun = () => {}

export default {
  b
}

如果 a 在 import 后未使用,Tree Shaking 完全可以将其优化掉;但是 b 在 import 后未使用,但因为存在他还执行了为数组原型添加了方法,副作用还是会被保留下来。这时就需要使用 sideEffects: false ,可以强制标识该包模块不存在副作用,那么不管它是否真的有副作用,只要它没有被引用到,整个 模块/包 都会被完整的移除。

如果你的项目中存在一些副作用代码 b 需要被保留下来,比如 polyfill、css、scss、less 等,可以按下面方法一样配置;保证必要的代码不被 Tree Shaking

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// package.json
{
  "name": "your-project",
  "sideEffects": ["./src/b.js", "*.css"]
}

总结

通过以上讲解,使 Webpack 更精确地检测无效代码,完成 Tree Shaking 操作,需要符合以下条件:

  • 使用 ES6 Module 语法(即 importexport)。
  • 确保没有 @babel/preset-env等工具将 ES6Module 语法转换为 CommonJS 模块。
  • optimization: { minimize: true, usedExports: true }
  • 使用支持 Tree Shaking 的包。

参考链接

Tree shaking 原理及应用 (https://segmentfault.com/a/1190000040037144)

Tree Shaking (https://webpack.docschina.org/guides/tree-shaking/)

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-08-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 政采云技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Webpack 的 Tree Shaking 概念详解
webpack 2.0 开始引入 tree shaking 技术,翻译过来的中文意思就是摇树,它可以在打包时忽略没有用到的代码。
张张
2019/12/31
1.3K0
Webpack 的 Tree Shaking 概念详解
Rspack 作者揭秘,你的 Tree Shaking 真的起作用了吗?
本文主要探讨了 Webpack Tree Shaking 的基本概念,而非深入其底层代码实现。相关的代码示例可以在 这里[1] 查看。
童欧巴
2024/05/09
4920
Rspack 作者揭秘,你的 Tree Shaking 真的起作用了吗?
webpack中tree-shaking技术介绍
之前介绍过webpack3的新特性,里面提到webpack2支持了ES6的import和export,不需要将ES6的模块先转成CommonJS模块,然后再进行打包处理。正基于此,webpack2引入了tree-shaking技术,能够在模块的层面上做到打包后的代码只包含被引用并被执行的模块,而不被引用或不被执行的模块被删除掉,以起到减包的效果。 webpack的tree-shaking案例 下面结合实际代码来解释webpack2是如何实现tree-shaking的,示例代码可到github进行下载。 示例
用户1217459
2018/01/31
1K0
webpack中tree-shaking技术介绍
前端-Webpack 之 treeShaking
在 github 上直接观看 markdown 会把图片转存到缓存中,github 转存后的图片清晰度很有问题,因此如果图片看不清,可以移步知乎上的相同文章
grain先森
2019/03/29
6890
前端-Webpack 之 treeShaking
16、webpack从0到1-tree shaking
tree shaking,这个还是一个比较重要的一个东西吧,可以大大的优化你的项目。 git仓库:webpack-demo 1、是什么? 我们首先从字面意思上来理解一下,tree shaking翻译一下就是摇树罗,摇树的时候就会把不必要的枯枝烂叶给摇下来,同理,到代码中,tree shaking就是把没有用到的代码shaking掉。 tree-shaking只有使用es6的模块化规范才有效,如果你使用commonJs模块化规范是搞不了tree-shaking的,为什么? 因为ES6模块是运行时加载
Ewall
2020/03/25
1K0
聊一聊面试中经常被问到的Tree Shaking
天下武功,唯快不破!最新版的 antd 以及 vue 都对 Tree Shaking 提供了支持。我们内部的组件在支持这部分功能时,也专门梳理了相关的特性。这是四月份写的文章了,长时间不用就会忘,复习一下!
前端迷
2020/08/28
2.1K0
聊一聊面试中经常被问到的Tree Shaking
原来项目打包也有这么技巧 - 浅谈 Tree Shaking 机制
身为一位前端工程师或多或少都有听过 Webpack 这套前端打包工具吧,为了让最终打包的档案不会过于庞大,Webpack 可是下了非常多的苦功,例如:利用 Code Splitting 产出一个又一个的 chunk 让网页不会一次载入一份很大 JS包。
前端小智@大迁世界
2022/06/05
3540
原来项目打包也有这么技巧 - 浅谈 Tree Shaking 机制
Webpack 原理系列九:Tree-Shaking 实现原理
Tree-Shaking 是一种基于 ES Module 规范的 Dead Code Elimination 技术,它会在运行过程中静态分析模块之间的导入导出,确定 ESM 模块中哪些导出值未曾其它模块使用,并将其删除,以此实现打包产物的优化。
Tecvan
2021/12/09
2.6K0
Webpack 原理系列九:Tree-Shaking 实现原理
精准的打包 — Webpack 的 Tree Shaking
作者: 神Q超人 译者:前端小智 来源:medium 前阵子在和朋友聊 Webpack 的时候,突然提到 Tree Shaking,但很惭愧的是我没有办法好好说明 Webpack 是如何做到 Tree Shaking 的,因此就趁这个年假的第一天抽空读 Webpack 的文件,然后把理解到的心得写下来,如果你也有兴趣,就一起看下去吧 🙌。 Tree Shaking 是什麽 Tree Shaking 是个优化的方式,在 JavaScript 中用来表示移除没用的代码的一个常见术语,之所以叫做 Tree Sha
前端小智@大迁世界
2022/03/22
6570
精准的打包 — Webpack 的 Tree Shaking
Webpack 4教程 - 第七部分 减少打包体积与Tree Shaking
在本次Webpack 4教程中,我们会更进一步讲述项目优化。我们会学习什么是tree shaking以及如何使用它。你会找到让Webpack 4中tree shaking运作起来所需要的东西,并知道怎样从中受益。开始吧!
葡萄城控件
2019/05/25
9940
webpack高级配置_2023-03-01
我主要是想说摇树失败的原因(tree shaking 失败的原因),先讲下摇树本身效果
gogo2027
2023/03/01
9790
【Webpack】507- 基于Tree-shaking的多平台Web代码打包实践
在业务中,我们常常会遇到一个场景:同一套web业务代码要在多平台下执行其对应的不同职能。这样很容易出现两个问题:代码里“尸横遍野”的环境判断和分支,提高了代码维护难度;执行环境下载了其他环境的功能代码,造成了资源的浪费。只要我们合理使用Webpack的Tree-shaking功能,就可以很好地解决问题。
pingan8787
2020/02/26
9570
【Webpack】507- 基于Tree-shaking的多平台Web代码打包实践
关于Rollup那些事
下一代打包工具,这是rollup对自己的定位。如今的前端领域,构建工具并不缺少,每个前端工程师都用过或者听过webpack。可以看到的是像React、Vue等框架的构建工具使用的都是rollup。既然如此,这些框架为什么会选择rollup?它的特性是什么?面对不同场景,我们要怎么选择构建工具?本文将一一为你呈现。
腾讯IVWEB团队
2020/06/24
7350
代码体积减少80%!Taro H5转换与优化升级
作为一个多端开发框架,Taro从项目发起时就已经支持编译到H5端。随着Taro 多端能力的不断成熟,对 Taro H5 端应用的要求也不断提升,已经不再满足于“能跑”,更希望 Taro 能跑得快。
京东技术
2019/05/05
3.4K0
代码体积减少80%!Taro H5转换与优化升级
Webpack 实现 Tree shaking 的前世今生
如果看过 rollup 系列的这篇文章 - 无用代码去哪了?项目减重之 rollup 的 Tree-shaking,那你一定对 tree-shaking 不陌生了。如果对 tree-shaking 相关知识不熟悉,请先点开上面这篇文章花 5 分钟了解一下:什么是 tree-shaking。
zz_jesse
2021/07/12
1.3K0
Webpack 实现 Tree shaking 的前世今生
Import 方式对 Tree-shaking 的影响
最近从小被子那里学了不少 Tree-shaking 的知识,Tree-shaking 译作“摇树优化”,是 DCE(Dead Code Elimination)优化的一种实现。
猫哥学前班
2019/06/27
4.1K0
Import 方式对 Tree-shaking 的影响
Rollup 与 Webpack 的 Tree-shaking
Rollup 和 Webpack 是目前项目中使用较为广泛的两种打包工具,去年发布的 Vite 中打包所依赖的也是 Rollup;在对界面加载效率要求越来越高的今天,打包工具最终产出的包体积也影响着开发人员对工具的选择,所以对 Tree-shaking 的支持程度和配置的便捷性、有效性就尤为重要了。本文就来简单分析下两者 Tree-shaking 的流程和效果差异。
政采云前端团队
2022/12/01
1.5K0
Rollup 与 Webpack 的 Tree-shaking
webpack2 的 tree-shaking 好用吗?
IMWeb前端团队
2018/01/08
1.6K0
webpack2 的 tree-shaking 好用吗?
webpack高级配置
我主要是想说摇树失败的原因(tree shaking 失败的原因),先讲下摇树本身效果
gogo2027
2022/10/18
9180
Webpack 性能系列五:使用 Scope Hoisting
默认情况下,经过 Webpack 打包后的模块资源会被组织成一个个函数形式,例如:
Tecvan
2021/12/09
1.6K0
相关推荐
Webpack 的 Tree Shaking 概念详解
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验