babel及其使用

news2024/9/24 15:27:35

什么是Babel?

Babel 是一个工具链,由大量的工具包组成,接下来我们逐步了解。主要用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。

核心库 @babel/core

Babel 的核心功能包含在 @babel/core 模块中。看到 core 这个词了吧,意味着核心,没有它,在 babel 的世界里注定寸步难行。不安装 @babel/core,无法使用 babel 进行编译。

babel-core 的作用是把 js 代码分析成 ast(抽象语法树) ,方便各个插件分析语法进行相应的处理。有些新语法在低版本 js 中是不存在的,如箭头函数,rest 参数,函数默认值等,这种语言层面的不兼容只能通过将代码转为 ast,分析其语法后再转为低版本 js。

CLI命令行工具 @babel/cli

babel 提供的命令行工具,主要是提供 babel 这个命令

npm install --save-dev @babel/core @babel/cli 

实例代码:

const fn = () => {console.log('a');
s}; 

package.json中配置:

"scripts": {"build": "babel src --out-dir lib --watch"}, 

执行babel命令后发现输出还是一模一样,并没有转换为es5语法。因为babel想要做一些实际的事情就需要配置plugin。此实例中需要箭头函数的转换插件: babel.config.json中配置

{"plugins": [["@babel/plugin-transform-arrow-functions"]]
} 

最终输出了:

const fn = function () {console.log('a');
}; 

现在,我们仅支持转换箭头函数,而现如今js语法已经发展到了es13,如果想将其它的新的JS特性转换成低版本,需要使用其它对应的 plugin 。如果我们一个个配置的话,会非常繁琐,这时就需要简化配置

预设

通过预设可以让你轻松使用es新语法!!! 官方针对常用的环境编写了一些 preset,如下所示:

  • @babel/preset-env
  • @babel/preset-flow
  • @babel/preset-react
  • @babel/preset-typescript

这几个 preset 是社区维护的,可以通过 npm 命令下载。我们可以根据项目需要来下载使用,例如一个普通的 vue 项目,Babel 的官方预设中,只需要配一个 @babel/preset-env 就可以啦。

@babel/preset-env 会根据你配置的目标环境,生成插件列表来编译。对于基于浏览器的项目,官方推荐使用 .browserslistrc 文件来指定目标环境

browserslist

根据提供的目标浏览器的环境来,智能添加css前缀,js的polyfill垫片,来兼容旧版本浏览器,而不是一股脑的添加。避免不必要的兼容代码,以提高代码的编译质量。

设置语法: 通过浏览器过滤的思路实现默认是兼容所有最新版本

例子说明
> 1%全球超过1%人使用的浏览器
> 5% in US指定国家使用率覆盖
last 2 versions所有浏览器兼容到最后两个版本根据CanIUse.com追踪的版本
Firefox ESR火狐最新版本
Firefox > 20指定浏览器的版本范围
not ie <=8方向排除部分版本
Firefox 12.1指定浏览器的兼容到指定版本
unreleased versions所有浏览器的beta测试版本
unreleased Chrome versions指定浏览器的测试版本
since 20132013年之后发布的所有版本

“browserslist”: [ “>0.2%”, “not dead”, “last 2 versions” ]

这个组合查询的意思是,筛选 最新两个版本、还存活着的、且用户比例大于0.2%  的浏览器

  • 之所以要组合查询,而不单独使用>0.2%,是为了避免流行的浏览器越来越流行,避免出现当初IE6一样的垄断情况。 (有竞争才有进步)
  • 只有当你专门针对某个浏览器(如Chrome)时 ,才直接使用last 2 Chrome versions。 如果不是针对某个浏览器,不要使用这种写法。我们应该尊重所有为用户体验努力的浏览器厂商。
  • 不要因为你不认识某个浏览器,而把它从browerslist配置中去除。

@babel/preset-env

@babel/preset-env 主要作用是对我们所使用的并且目标浏览器中缺失的功能进行代码转换和加载 polyfill,在不进行任何配置的情况下,@babel/preset-env 所包含的插件将支持所有最新的JS特性(ES2015,ES2016等,不包含 stage 阶段),将其转换成ES5代码。如果你不是要兼容所有的浏览器和环境,推荐你指定目标环境,这样你的编译代码能够保持最小。

例如,仅包括浏览器市场份额超过0.25%的用户所需的 polyfill 和代码转换

//.browserslistrc
> 0.25%
not dead 

我们修改下 src/index.js

const isHas = [1,2,3].includes(2);

const p = new Promise((resolve, reject) => {
    resolve(100);
}); 

编译出来的结果为:

"use strict";

var isHas = [1, 2, 3].includes(2);
var p = new Promise(function (resolve, reject) {
  resolve(100);
}); 

这个编译出来的代码在低版本浏览器中使用的话,显然是有问题的,因为低版本浏览器中数组实例上没有 includes 方法,也没有 Promise 构造函数。

这是为什么呢?因为语法转换只是将高版本的语法转换成低版本的,但是新的内置函数、实例方法无法转换。这时,就需要使用 polyfill 上场了,顾名思义,polyfill的中文意思是垫片,所谓垫片就是垫平不同浏览器或者不同环境下的差异,让新的内置函数、实例方法等在低版本浏览器中也可以使用。

Polyfill

Babel对于语法的转换,有两种情况需要处理:

  • 语法层: let、const、箭头函数、class等,这些需要在构建时进行转译,是指在语法层面上的转译
  • api方法层:Promise、includes、map等,这些是在全局或者Object、Array等的原型上新增的方法,它们可以由相应es5的方式重新定义。

对于api方法层,需要用到Polyfill。在Babel 7.4.0版本之前,使用的方案是在项目入口处直接引入

@babel/polyfill 模块包括 core-js 和一个自定义的 regenerator runtime 模块,可以模拟完整的 ES2015+ 环境

这意味着可以使用诸如 PromiseArray.fromObject.assign 之类的静态方法、Array.prototype.includes 之类的实例方法。为了添加这些功能,polyfill 将添加到全局范围中(会对全局环境造成污染)。

babel v7.4版之后,@babel/polyfill已经被废弃,需要直接安装core-js 和 regenerator-runtime去替代之前的@babel/polyfillcroe-js 提供了 ES5、ES6 规范中新定义的各种对象、方法的polyfill,regenerator-runtime 用来实现 ES6/ES7 中 generators、yield、async 及 await 等相关的 polyfill。

在项目入口处引入:

import "@bable/polyfill";
// 引用"@bable/polyfill"相当于引用了下面这两个库,是等价的
import "core-js/stable"; 
import "regenerator-runtime/runtime";

// ...项目代码 

很多时候,我们未必需要完整的 @babel/polyfill,这会导致我们最终构建出的包的体积增大,并且会造成全局环境污染。

我们更期望的是,如果我使用了某个新特性,再引入对应的 polyfill,避免引入无用的代码。

值得庆幸的是, Babel 已经考虑到了这一点。

@babel/preset-env参数

@babel/preset-env 中与 @babel/polyfill 的相关参数有 targets 和 useBuiltIns 两个

targets:  支持的目标浏览器的列表

useBuiltIns:  参数有 “entry”、”usage”、false 三个值。默认值是false,此参数决定了babel打包时如何处理@babel/polyfilll 语句。

“entry”: 会将文件中 import‘@babel/polyfilll’语句 结合 targets ,转换为一系列引入语句,去掉目标浏览器已支持的polyfilll 模块,不管代码里有没有用到,只要目标浏览器不支持都会引入对应的polyfilll 模块。

“usage”: 不需要手动在代码里写import‘@babel/polyfilll’,打包时会自动根据实际代码的使用情况,结合 targets 引入代码里实际用到 部分 polyfilll 模块

false: 对 import‘@babel/polyfilll’不作任何处理,也不会自动引入

实例源代码:

const isHas = [1,2,3].includes(2);

const p = new Promise((resolve, reject) => {resolve(100);
}); 

构建后代码:

"use strict";

require("core-js/modules/es.array.includes.js");
require("core-js/modules/es.object.to-string.js");
require("core-js/modules/es.promise.js");
var isHas = [1, 2, 3].includes(2);
var p = new Promise(function (resolve, reject) {resolve(100);
}); 

总结: 在业务项目中需要用到polyfill时, 可以使用和 @babel/preset-env 的 targets 和 useBuiltIns: usage来根据目标浏览器的支持情况,按需引入用到的 polyfill 文件。

有一点需要注意:配置此参数的值为 usage ,必须要同时设置 corejs (如果不设置,会给出警告,默认使用的是"corejs": 2) 。

corejs@2已停止维护,所有新的功能添加到corejs@3中(例如:Array.prototype.flat、Array.prototype.flatMap、Symbol.prototype.description等)

core-js (点击了解更多) : JavaScript 的模块化标准库,包含 PromiseSymbolIterator和许多其他的特性,它可以让你仅加载必需的功能。

@babel/plugin-transform-runtime

一个插件,可以重用 Babel 注入的帮助程序代码以节省代码大小。以模块化方式包含功能实现的包。

假如,我们的 src/index.js 是这样的:

class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    };
    getX() {
        return this.x;
    }
}

let cp = new ColorPoint(25, 8);
复制代码 

编译出来的 lib/index.js,如下所示:

"use strict";

require("core-js/modules/es.object.define-property.js");
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
var Point = /*#__PURE__*/function () {function Point(x, y) {_classCallCheck(this, Point);this.x = x;this.y = y;}_createClass(Point, [{key: "getX",value: function getX() {return this.x;}}]);return Point;
}();
var cp = new ColorPoint(25, 8); 

我们联想到如果多个文件中引用了该class,是不是每次都要注入这些方法,显而易见包的体积会变大

这个时候,就是 @babel/plugin-transform-runtime 插件大显身手的时候了,使用 @babel/plugin-transform-runtime 插件,所有帮助程序都将引用模块 @babel/runtime,这样就可以避免编译后的代码中出现重复的帮助程序,有效减少包体积。

@babel/plugin-transform-runtime 是一个可以重复使用 Babel 注入的帮助程序,以节省代码大小的插件。 另外,@babel/plugin-transform-runtime 需要和 @babel/runtime 配合使用。

首先安装依赖,@babel/plugin-transform-runtime 通常仅在开发时使用,但是运行时最终代码需要依赖 @babel/runtime,所以 @babel/runtime 必须要作为生产依赖被安装,如下 :

npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime 

除了前文所说的,@babel/plugin-transform-runtime 可以减少编译后代码的体积外,我们使用它还有一个好处,它可以为代码创建一个沙盒环境,如果使用 @babel/polyfill 及其提供的内置程序(例如 PromiseSetMap ),则它们将污染全局范围。虽然这对于应用程序或命令行工具可能是可以的,但是如果你的代码是要发布供他人使用的库,或者无法完全控制代码运行的环境,则将成为一个问题。

@babel/plugin-transform-runtime 会将这些内置别名作为 core-js 的别名,因此您可以无缝使用它们,而无需 polyfill

@babel/plugin-transform-runtime作用:

  • babel-runtime编译过程中会重复生成冗余代码。
  • babel-runtime无法做到智能化分析,需要我们手动引入。

@babel/plugin-transform-runtime插件会智能化的分析我们的项目中所使用到需要转译的js代码,从而实现模块化从babel-runtime中引入所需的polyfill实现。

  • babel-runtime编译过程中会重复生成冗余代码。

@babel/plugin-transform-runtime插件提供了一个helpers参数。 最终配置:

regenerator-runtime 包其实可以不用手动安装,因为在安装 @babel/preset-env 的时候会自动安装 @babel/runtime,而安装 @babel/runtime 的时候会自动安装regenerator-runtime 包。

最后

最近还整理一份JavaScript与ES的笔记,一共25个重要的知识点,对每个知识点都进行了讲解和分析。能帮你快速掌握JavaScript与ES的相关知识,提升工作效率。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

‘this’不能用于常量表达式错误(C++)【问题解决】

目录 一、报错问题 1、代码 test.h test.cpp 2、问题描述 二、网上解决思路 三、解决方案 【元旦快乐&#x1f339;&#xff0c;新年快乐&#x1f389;】 最近在编译程序时出现了“ ‘this’不能用于常量表达式错误(C )”的报错问题&#xff0c;查阅多位博主写的文章后&…

mysql 性能优化

mysql 调优可以从这个四个方面来看 1.性能监控 1.1 show profile for query n 查看具体的sql语句各阶段执行时间 show profiles; show profile for query n; 1.2 performance schema 监控mysql 整个服务器中发生的各种事件。 performance schema 表中的数据不会持久化的磁…

一文搞定垃圾回收的三色标记法

我们之前介绍了各种常见垃圾回收器的基本原理&#xff0c;本小节我们讨论一个更深入的问题——垃圾回收器的底层是如何做的。 在并发标记的过程中&#xff0c;因为标记期间应用线程还在继续跑&#xff0c;对象间的引用可能发生变化&#xff0c;多标和漏标的情况就有可能发生。…

计算机视觉(CV)领域Transformer最新论文及资源整理分享

Transformer由论文《Attention is All You Need》提出&#xff0c;现在是谷歌云TPU推荐的参考模型。Transformer模型最早是用于机器翻译任务&#xff0c;当时达到了SOTA效果。Transformer改进了RNN最被人诟病的训练慢的缺点&#xff0c;利用self-attention机制实现快速并行。并…

梯度,GD梯度下降,SGD随机梯度下降

前言 羊了&#xff0c;但是依旧生龙活虎。补补之前落下的SGD算法&#xff0c;这个在深度学习中应用广泛。 梯度&#xff08;Gradient&#xff09; 方向导数 在梯度之前&#xff0c;非常重要一个概念&#xff1a;方向导数&#xff0c;这里uuu是nnn维向量&#xff0c;代表一个…

EMNLP 22:Bi-Directional Iterative Prompt-Tuning for Event Argument Extraction

总结 文中的前向和后向的思想可以借鉴下。 但总的来看&#xff0c;似乎是通过前向和后向来做的ensemble操作&#xff0c;虽然是在一个模型下&#xff0c;但同时前向和后向概率保证&#xff0c;可能能够使得预测更准确。 任务形式&#xff1a;event argument extraction (EAE)…

Java 读取resources下的文件+读取resource文件/路径

Java 读取resources下的文件 文档来源 三种实现方式 pom.xml <!-- commons-io io的工具包 --> <dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version></dependency>…

SSM之Spring(二)

目录 2.3 基于注解管理bean 2.3.1 标记与扫描 2.3.2 基于注解的自动装配 三&#xff1a;AOP 3.1 场景模拟 3.1.1 声明接口 3.1.2 创建实现类 3.1.3 创建带日志功能的实现类 3.1.4 提出问题 3.2 代理模式 3.2.1 概念 3.2.2 静态代理 3.2.3 动态代理 3.2.4 测试 3.3 AO…

ElasticSearch笔记

ELASTICSEARCH笔记 1、安装elastic search dokcer中安装elastic search &#xff08;1&#xff09;下载ealastic search和kibana docker pull elasticsearch:7.6.2 docker pull kibana:7.6.2&#xff08;2&#xff09;配置 mkdir -p /mydata/elasticsearch/config 创建目…

Hex程序烧写到单片机

一、创建一个Keil代码工程 1、在电脑F盘&#xff08;哪个盘可以随意选择&#xff09;上创建项目工程文件夹Template 2、在Template文件中&#xff0c;创建一个main.c文件 3、进入keil主页面&#xff0c;工具栏project---->New uVision project---->选则第一步的工程文…

【数据结构】时间与空间复杂度

&#x1f3d6;️作者&#xff1a;malloc不出对象 ⛺专栏&#xff1a;《初识C语言》 &#x1f466;个人简介&#xff1a;一名双非本科院校大二在读的科班编程菜鸟&#xff0c;努力编程只为赶上各位大佬的步伐&#x1f648;&#x1f648; 目录前言一、算法效率1.1 如何衡量一个算…

【华为上机真题 2022】太阳能板的最大面积

&#x1f388; 作者&#xff1a;Linux猿 &#x1f388; 简介&#xff1a;CSDN博客专家&#x1f3c6;&#xff0c;华为云享专家&#x1f3c6;&#xff0c;Linux、C/C、云计算、物联网、面试、刷题、算法尽管咨询我&#xff0c;关注我&#xff0c;有问题私聊&#xff01; &…

ArcGIS基础实验操作100例--实验27细分栅格

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 基础编辑篇--实验27 细分栅格 目录 一、实验背景 二、实验数据 三、实验步骤 方法一&#xff1a;使用…

oneblog博客系统 让你的博客实现图片显示的功能

背景 \ 闲来无事&#xff0c;希望捣腾捣腾计算机&#xff0c;玩一玩网络&#xff0c;自己搭一个博客系统。那么在家搭建一个自己的服务器&#xff0c;并且让别人通过你的博客系统与你交流。多么神奇的事情。 在搭建博客系统的过程中&#xff0c;你需要在后台写好文章。但是在上…

网赚不要当苦力,流量变现才是王道

事实上&#xff0c;大多数互联网从业者脑子里只想到一件事。无脑搬砖一个月挣一万多元。不可否认&#xff0c;有这样的副业&#xff0c;但也需要前提条件。你需要在早期阶段努力工作&#xff0c;然后才能分批赚钱。这是两个概念&#xff0c;一开始就听话。 我从来不建议你做那…

leetcode 155. 最小栈-java题解

题目所属分类 辅助栈 或者一个栈 原题链接 设计一个支持 push &#xff0c;pop &#xff0c;top 操作&#xff0c;并能在常数时间内检索到最小元素的栈。 实现 MinStack 类: MinStack() 初始化堆栈对象。 void push(int val) 将元素val推入堆栈。 void pop() 删除堆栈顶部…

关于gets()与scanf()输入字符串与\0,\n,空格之间的问题

我们都知道输入字符串的话&#xff0c;用gets()函数与scanf()加%s的话都是可以的。同时&#xff0c;一个字符串的结尾默认有一个\0也是老生常谈。 空格 gets() 1. 当gets()碰到空格时就把它当成一个普通的字符来看&#xff0c;没有任何特殊之处可言。 scanf() 1. 如果再输入…

【自学Python】Python特点

Python特点 Python特点教程 Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 Python 的设计具有很强的可读性&#xff0c;相比其他语言经常使用英文关键字&#xff0c;其他语言的一些标点符号&#xff0c;它具有比其他语言更有特色语法结构。 Py…

计算机组成原理实验——一、ALU实验

一、实验目的 1.掌握ALU模块的组成和接口&#xff0c;理解ALU的功 能。 2.通过编程调用ALU模块计算斐波那契数。 3.掌握Verilog中多模块编程方法和实现。 二、实验内容 用 Verilog 设计一个算术运算单元 ALU&#xff0c;采 用纯组合逻辑设计&#xff0c;32bit 宽。 利用该 …

2022(终)最后一篇博客—继承和多态

目录 文章目录 一、继承 1.1为什么要继承 1.2继承概念 1.3继承的语法 1.4成员访问 1.5方法访问 1.6初始化代码块 1.7继承方式 二、多态 1.1多态的概念 1.2多态实现条件 1.3动态绑定与静态绑定 1.4向上转型与向下转型 1.5多态的优缺点 1.6需要注意的地方&#x…