Tree-Shaking 作用和实现原理

一、什么是Tree-shaking

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

在前端开发中,特别是在使用模块化工具(如Webpack、Rollup等)构建应用程序时,通常会引入许多库和模块。然而,应用程序可能只使用了这些库的一小部分功能,导致最终生成的代码包含了大量未被使用的代码。Tree-shaking通过静态分析代码来确定哪些代码是可到达的并且被使用的,然后去除那些未被使用的部分。这样一来,可以显著减小最终部署的代码大小,提高应用程序的性能。

Tree Shaking 较早前由 Rich Harris 在 Rollup 中率先实现,Webpack 自 2.0 版本开始接入,已经成为一种应用广泛的性能优化手段。

上图形象的解释了Tree-shaking 的本意,本文所说的前端中的tree-shaking可以理解为通过具"摇"我们的JS文件,实际开发中,虽然依赖了某个模块,但其实只使用其中的某些功能。通过 tree-shaking,将没有使用的模块摇掉,这样来达到删除无用代码的目的。

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

  • 使用 ESM 规范编写模块代码
  • 配置 optimization.usedExportstrue,启动标记功能
  • 启动代码优化功能,可以通过如下方式实现:
    • 配置 mode = production
    • 配置 optimization.minimize = true
    • 提供 optimization.minimizer 数组
// webpack.config.js
module.exports = {entry: "./src/index",mode: "production",devtool: false,optimization: {usedExports: true // 启用tree-shaking}
}

示例代码

// bar.js
const bar = 'bar'
const foo = 'foo'export {bar,foo
}// index.js
import { bar } from './bar'  // 引入bar.js
console.log(bar)

示例中bar.js 模块导出了 bar 、foo 但只有 bar 导出值被其它模块使用,经过 Tree Shaking 处理后,foo 变量会被视作无用代码删除。

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

  • ESM:export + import
  • Common JS:module.exports + require
// 导入所有内容(不会触发 tree-shaking)
import lodash from 'lodash'// 导入命名导出 (会触发 tree-shaking)
import { debounce } from 'lodash'

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

二、实现原理

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

Webpack 中,Tree-shaking 的实现一是先「标记」出模块导出值中哪些没有被用过,二是使用 Terser 删掉这些没被用到的导出语句。标记过程大致可划分为三个步骤:

  • Make 阶段,收集模块导出变量并记录到模块依赖关系图 ModuleGraph 变量中
  • Seal 阶段,遍历 ModuleGraph 标记模块导出变量有没有被使用
  • 生成产物时,若变量没有被其它模块使用则删除对应的导出语句

标记功能需要配置 optimization.usedExports = true 开启

在ES Module中,我们可以将模块的加载分为两个阶段:静态分析和编译执行;

所谓静态分析,即在代码执行前就能对整体代码依赖调用关系等进行分析读取;

下面我们看下ES Module的特性:

  1. 只能作为模块顶层的语句出现(而不嵌套在条件语句中)
  2. import 的模块名只能是字符串常量(只对文件进行字符串读取)
  3. 导入和导出语句没有动态部分(不允许使用变量等)

三、sideEffects 副作用

webpack 2 正式版本内置支持 ES2015 模块(也叫做 harmony modules)和未使用模块检测能力。新的 webpack 4 正式版本扩展了此检测能力,通过 package.json 的 "sideEffects" 属性作为标记,向 compiler 提供提示,表明项目中的哪些文件是 "pure(纯正 ES2015 模块)",由此可以安全地删除文件中未使用的部分。

Webpack 中有一个 sideEffects 配置,用于标识哪些模块是无副作用的,可以被 Tree-shaking 移除。如果你的模块包含副作用,但你明确知道这些副作用是无害的,可以通过配置 sideEffects 来告诉 Webpack 哪些模块可以被 Tree-shaking 移除。

// package.json
{"sideEffects": ["*.css", "*.scss"]
}

四、哪些框架可以使用Tree-shaking

  • Webpack

    Webpack 是一个强大的 JavaScript 模块打包工具,支持 Tree-shaking。在 Webpack 2 及以上版本中,配置 mode 为 'production',Webpack 默认启用 Tree-shaking。同时确保你的项目使用了 ES6 模块系统,以便 Webpack 能够更好地进行静态分析。
  • Rollup

    Rollup 是专注于 ES6 模块的打包工具,天生支持 Tree-shaking。Rollup 的设计目标之一就是生成更小、更高效的代码,因此它是一个非常适合 Tree-shaking 的选择。
  • Parcel

    Parcel 是一个零配置的打包工具,它通过自动检测和处理模块间的依赖关系,实现了快速且有效的 Tree-shaking。Parcel 可以用于快速搭建项目,而无需复杂的配置。
  • Snowpack

    Snowpack 是一个现代的构建工具,专注于提供快速的开发体验。它支持 ES6 模块和 Tree-shaking,并在开发环境中实现了即时开发(Instant Development)的特性。
  • Vite

    Vite 是一个基于 Vue.js 的新型构建工具,它利用原生 ES 模块导入的特性,支持 Tree-shaking,并在开发环境中实现了快速的冷启动。
  • ESBuild

    ESBuild 是一个极快的 JavaScript 构建工具,它具有强大的 Tree-shaking 功能。ESBuild 以速度为特点,能够在短时间内完成快速的构建。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/244135.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IPoE技术汇总

在国内并没有遇到这么多的IPoE(IP over Ethernet)技术,可能也是因为我来日本多年了,没有接触国内的IPv4 over IPv6的技术,感觉国内IPv4地址紧张,用的传统NAT和PPPoE非常多,大多数设备还是建立在…

记一次Flink通过Kafka写入MySQL的过程

一、前言 总体思路:source -->transform -->sink ,即从source获取相应的数据来源,然后进行数据转换,将数据从比较乱的格式,转换成我们需要的格式,转换处理后,然后进行sink功能,也就是将数…

Linux|centos7操作系统|rtl8188gu芯片的网卡驱动使用DKMS安装管理

前言: DKMS是一个外置模块管理工具,可以自动build,安装各类驱动 DKMS (Dynamic Kernel Module Support) 是一种框架,用于在 Linux 操作系统中构建和维护内核模块。内核模块是 Linux 内核的一部分,它们提供了许多功能&…

(C++)简单计算器

文章目录 一、实验目的、内容二、实验程序设计及结构1.需求分析变量函数 2.设计结构或流程图 三、设计过程四、测试分析第一组第二组实验中出现的bug及解决方案 五、设计的特点和结果 一、实验目的、内容 输入是一个带有括号的四则运算表达式,输出是计算得出的正确…

详细分析Java中的list.foreach()和list.stream().foreach()

目录 前言1. 基本知识2. 差异之处2.1 执行顺序2.2 串行并行2.3 复杂数据处理2.4 CRUD集合2.5 迭代器 3. 总结4. 彩蛋 前言 典故来源于项目中使用了两种方式的foreach,后面尝试体验下有何区别! 先看代码示例: 使用List的forEach&#xff1a…

手写Vue3源码

Vue3核心源码 B站视频地址:https://www.bilibili.com/video/BV1nW4y147Pd?p2&vd_source36bacfbaa95ea7a433650dab3f7fa0ae Monorepo介绍 Monorepo 是管理项目代码的一种方式,只在一个仓库中管理多个模块/包 一个仓库可以维护多个模块,…

打 jar 包运行 在windows 平台控制台和日志 乱码解决

--拒絕鷄巴囉嗦,直接解決問題 我们在Windows下运行jar包时,常常会出现乱码,主要分为dos窗口输出的日志中出现乱码和程序返回数据出现乱码。 dos窗口输出的日志中出现乱码 执行如下命令,将控制台输出编码改为UTF8: ch…

基于springboot+vue的足球青训俱乐部管理系统(前后端分离)

博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容:毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 研究背景…

Tkinter + removebg实现Ai抠图

我们先对removebg进行一个说明: "removebg" 是一个在线服务,它允许用户自动去除图片的背景。用户只需上传图片,系统会通过算法自动识别并去除背景,生成透明背景(PNG格式)或者用户指定的新背景图…

Qt6入门教程 10:菜单栏、工具栏和状态栏

目录 一.菜单栏 1.Qt Designer 1.1添加菜单和菜单项 1.2添加二级菜单 1.3给菜单和菜单项添加图标 1.4给菜单项添加功能 2.纯手写 二.工具栏 1.Qt Designer 1.1添加工具栏按钮 1.2工具栏的几个重要属性 2.纯手写 三.状态栏 1.Qt Designer 2.纯手写 用Qt Creator新…

excel学习1

直接ctrl cctrl v会报错位移选择粘贴时用123那个数字粘贴而不是ctrl V 只要结果不要公式 上面复制的为数值这里是复制的公式他们两个不一样 这个方法太麻烦了直接用格式刷,选择一个区域一个单元格,不要选择多个一刷就出来了 第一个计算后向下拖就行了&…

Overleaf(LaTeX文档在线编写平台)使用学习记录

一、LaTeX简概[1] LaTeX,是一种基于TEX的排版系统,是一种可以处理排版和渲染的标记语言。由美国计算机科学家莱斯利兰伯特在20世纪80年代初期开发,利用这种格式系统的处理,即使用户没有排版和程序设计的知识也可以充分发挥由TEX所…

SpringBoot整合ElasticSearch实现基础的CRUD操作

本文来说下SpringBoot整合ES实现CRUD操作 文章目录 概述spring-boot-starter-data-elasticsearch项目搭建ES简单的crud操作保存数据修改数据查看数据删除数据 本文小结 概述 SpringBoot支持两种技术和es交互。一种的jest,还有一种就是SpringData-ElasticSearch。根据…

centos7安装Redis7.2.4

文章目录 下载Redis解压Redis安装gcc依赖(Redis是C语言编写的,编译需要)编译安装src目录下二进制文件安装到/usr/local/bin修改redis.conf文件启动redis服务外部连接测试 参考: 在centos中安装redis-5.0.7 Memory overcommit must…

docker 部署及命令

一、容器概述 1、为什么要用到容器? ①容器可以屏蔽底层操作系统的差异性,让业务应用不管在哪里都是使用容器的环境运行,从而保证开发测试环境与生产环境的一致性 ②容器部署起来非常便捷和迅速,缩短开发测试部署的周期时间 2…

神经网络的学习(Neural Networks: Learning)

1.代价函数 案例:假设神经网络的训练样本有𝑚个,每个包含一组输入𝑥和一组输出信号𝑦,𝐿表示神经网络层数,𝑆𝐼表示每层的 neuron 个数(𝑆&#…

【Java-框架-SpringSecurity】单点登录(认证和授权)- 随笔

项目文件&#xff1b; 【1】 预览 文件 文件01 名称 pom.xml&#xff1b; 内容 &#xff08;01&#xff09;总的 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http:…

18.鸿蒙HarmonyOS App(JAVA)日期选择器-时间选择器

18.鸿蒙HarmonyOS App(JAVA)日期选择器-时间选择器 点击button按钮触发事件显示月份与获取的时间 Button button3 (Button) findComponentById(ResourceTable.Id_button3);button3.setClickedListener(new Component.ClickedListener() {Overridepublic void onClick(Compon…

【趣味CSS3.0】粘性定位属性Position:sticky是不是真的没用了?

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享博主 &#x1f40b; 希望大家多多支持一下, 我们一起学习和进步&#xff01;&#x1f604; &#x1f3c5; 如果文章对你有帮助的话&#xff0c;欢迎评论 &#x1f4ac;点赞&a…

Webpack5 基本使用 - 2

常用 loader loader 是辅助打包工具。webpack 默认只能打包 js 文件&#xff0c;打包其它模块就需要配置 loader 来告诉 webpack 该怎么去打包其它文件。loader 可以将文件从不同的语言转换为 JavaScript。一类文件如果需要多个 loader 处理&#xff0c;loader 的执行顺序是从…