Babel是什么?Babel到底可以用来干嘛___一文带你从零开始认识Babel

2022-09-08 17:53:31 浏览数 (1)

引入

在此之前或许你已经用过babel,也许听说过什么 babel-loader babel-core、babel-cli、babel-plugin-...、babel-preset-env 反正各种乱七八糟的做项目随便用一一下就可以了,对他只有个一知半解,甚至不知道他到底是干什么的,反正项目要用,照着用就行了,至少博主之前的状态是这样,如果只对他有个一知半解甚至都不了解,那么项目出bug了你都不知道怎么去调试,只能复制-->粘贴-->百度。 基于此,写下自己对Babel的理解。

Babel是什么?

我们在他的官方网站找到这样一句话

Babel is a JavaScript compiler

Babel 是一个 JavaScript 编译器

Babel是一个编译器,针对JavaScript,为什么会有Babel这样一个工具的存在?

本文默认你对es6、es7等有所涉足,我们在写es6 语法的时候是不是很方便,什么promise、async await`,可是es6 语法写的虽然很酸爽,但是浏览器他不兼容啊,你想想你写的代码在浏览器上跑不起来,在好的语法在好的特性又有什么用?

这个时候Babel这样一个工具出来了,他可以将我们写的es6 语法转换为浏览器兼容的语法,比如将箭头函数转换为普通函数,有了这样一个工具我们就即可以写酸爽的语法,又可以让使浏览器兼容。 相信到这你已经知道了Babel的概念,并且可以脑补出Babel可以干什么。

下面介绍Babel的使用和一些细节

Babel 的使用

  • 单体文件
  • 命令行
  • 配合Webpack使用

本文将介绍Babel配合webpack使用的情况

配置文件

babel的配置文件有几种,.babelrcbabel.config.json 配置方法都一样,本文以.babelrc配置文件为主

在初次接触Babel我们只要用到一下两项配置

代码语言:javascript复制
//.babelrc
{
  "presets": [...],
  "plugins": [...]
}

下面介绍presets与plugins

Plugins

Plugins顾名思义插件。 babel 本身不具有任何转化功能,我们要的代码要转换某些功能,比如将es6转换为es5,我们就需要下载相应的插件,并且将这些插件配置到.babelrc文件的plguins里面。

比如将箭头函数转换为浏览器能识别的普通函数 我们就需要用到 @babel/plugin-transform-arrow-functions插件,并将其添加到配置文件 1.首先下载插件 npm i @babel/plugin-transform-arrow-functions -D 2.添加至配置文件

代码语言:javascript复制
//.babelrc
{
    "plugins":[
          "@babel/plugin-transform-arrow-functions"
        ]
}

这样babel就能够将箭头函数转换为普通函数了

代码语言:javascript复制
//转换前
var a = () => {};
//转换后
var a = function () {};

Q:什么?你怎么知道要用这个插件? A:看文档啊!【https://www.babeljs.cn/docs/plugins】

Presets

Presets顾名思义预设。 我们要转换一些语法就得使用各种插件,并且添加到配置文件,如果每次项目需要的babel插件都差不多,而我们每次都要进行重复的下载,配置工作,这样效率是不是很低,很繁琐。 这个时候我们就可以利用presets这个功能,将一些常用的babel插件,配置放入预设中,下载直接将这个预设放入配置文件即可

比如项目中经常要使用到 @babel/plugin-transform-arrow-functions@babel/plugin-transform-for-of插件,那么我们可以将这两个插件设为预设 具体操作参照文档【https://www.babeljs.cn/docs/presets#创建-preset】

将其设为预设后 下次在.babelrc文件配置即可,如假设预设为 myPreset,那么在配置文件

代码语言:javascript复制
//.babelrc
{
    "presets":["myPreset"    ]
}

当然除了我们自定义预设,我们还可以使用别人定义好的一些预设,如你经常看到的 @babel/preset-env@babel/preset-react

使用方法

1.下载preset npm i @babel/preset-env

2.配置文件

代码语言:javascript复制
//.babelrc
{
    "presets":["preset-env"    ]
}

Q:我怎么知道有哪些预设? A:看文档 ,搜npm Q我怎么知道预设里面有哪些插件? A: 要知道预设里面有哪些插件,最好的方式就是搜npm看他的依赖项

可以看到preset-env有 66个插件

不过 preset 分为以下几种: 第一种:官方内容 env, react, flow 等 第二种:stage-x,这里面包含的都是当年最新规范的草案,每年更新。 这里面还细分为 Stage 0 - 稻草人: 只是一个想法,经过 TC39 成员提出即可。

Stage 1 - 提案: 初步尝试。

Stage 2 - 初稿: 完成初步规范。

Stage 3 - 候选: 完成规范和浏览器初步实现。

Stage 4 - 完成: 将被添加到下一年度发布

这也就是你在早期的项目或文档中看到 stage-0,stage-1的字眼,原来他们都是预设,不过现在你不用纠结这个问题Babel7已经放弃stage预设了

Polyfill

Plolyfill 垫片。 babel默认只转换新的 JavaScript 语法,比如箭头函数、扩展运算(spread)。 不转换新的 API,例如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全局对象,以及一些定义在全局对象上的方法(比如 Object.assign)都不会转译。如果想使用这些新的对象和方法,则需要为当前环境提供一个垫片(polyfill)。 Polyfill主要有三种

@babel/polyfill

Babel 包含一个polyfill 库即@babel/polyfill。这个库里包含 regenerator 和 core-js。 什么是regenerator? npm地址 :https://www.npmjs.com/package/regenerator-runtime github地址:https://github.com/facebook/regenerator/blob/master/packages/regenerator-runtime/runtime.js

官方对他的描述直译过来是 重新生成编译的生成器和异步函数的独立运行时 在网上找到这样一句话 生成器函数、async、await函数经babel编译后,regenerator-runtime模块用于提供功能实现。 博主对于生成器(regenerator)也是一知半解,这里我们就简单的理解成,项目中要使用async、await函数就必须使用这个库吧!(有知道的欢迎下方留言)。

什么是core-js? npm 地址 https://www.npmjs.com/package/core-js 下面是官方对他的解释

JavaScript的模块化标准库。包括到2021年的ECMAScript的Polyfill: promisessymbolscollectionsiteratorstypedarrays、许多其他特性、ECMAScript提案、跨平台WHATWG / W3C特性和提案,比如URL。您可以只加载所需的特性,或者在不污染全局命名空间的情况下使用它。

粗暴的理解就是,你要使用一些js高级特性如promise就得使用这个库。

经过上面潦草的描述,我们在总结一下 由于babel只能将es6 语法转换为低级语法,而当我们使用一些高级特性时比如 asyncawait类似的Api,babel就显得无能为力了,因为babel无法实现这些高级Api的功能,这个时候就需要一个垫片(polyfill),而babel又包含了一个polyfill叫@babel/polyfill这个polyfill本身也无法实现像async等高级API的功能,但是市面上有现成的封装好的类库实现了,于是@babel/polyfill将他们包含进来。这样当我们引入@babel/polyfill时,就可以丝滑的写高级语法了!

使用方式

1.npm i @babel/polyfill -S 记住是-S** 因为polyfill要在源代码之前运行!

2.在入口文件导入

代码语言:javascript复制
import "@babel/polyfill";

当然在webpack中你也可以这样干

在@babel/polyfill的描述有这样一段

The polyfill is provided as a convenience but you should use it with @babel/preset-env and the useBuiltIns option so that it doesn't include the whole polyfill which isn't always needed. Otherwise, we would recommend you import the individual polyfills manually

大概意思就是建议我们将@babel/polyfill和@babel/preset-env配合使用并根据需求设置 useBuiltlns选项,这样就不至于将这个polyfill加载进来,显得很大。 不然就使用手动导入各个polyfill的方式。

**在webpack中我们可以将@babel/polyfill和@babel/preset-env配合使用! ** 主要是设置 useBuiltlns选项 更多preset-env的配置请参照 https://babeljs.io/docs/en/babel-preset-env#options

代码语言:javascript复制
{
  "presets" : [
    ["@babel/preset-env",{
      "targets": {
        "browsers": [
          "last 2 versions",
          "not ie <= 9"
        ]
      },
      "useBuiltIns": "usage"
    }]
  ]
}

useBuiltlns:false:此时不对 polyfill 做操作。如果引入 @babel/polyfill,则无视配置的浏览器兼容,引入所有的 polyfill。 useBuiltlns:usage:按需加载polyfill,根据配置的浏览器兼容以及代码所用到的polyfill, 不至于将所有polyfill加载进来,使用这种方式我们不用手动导入polyfill但是需要安装。 useBuiltlns:entry:根据配置的浏览器兼容,引入浏览器不兼容的 polyfill。需要在入口文件手动添加 import @babel/polyfill,会自动根据 browserslist 替换成浏览器不兼容的所有 polyfill。

**@babel/polyfill带来的问题 ** babel-polyfill,通过改写全局prototype的方式实现,它会加载整个polyfill,针对编译的代码中新的API进行处理,并且在代码中插入一些帮助函数,比较适合单独运行的项目。

babel-polyfill解决了Babel不转换新API的问题,但是直接在代码中插入帮助函数,会导致污染了全局环境,并且不同的代码文件中包含重复的代码,导致编译后的代码体积变大。虽然这对于应用程序或命令行工具来说可能是好事,但如果你的代码打算发布为供其他人使用的库,或你无法完全控制代码运行的环境,则会成为问题。

后来@babel/polyfill凉了,通过官方我们知道 从 Babel 7.4.0起 @babel/polyfill已经被弃用了。 之前使用的方式现在改成了

代码语言:javascript复制
//import "@babel/polyfill"; //之前的写法
import "core-js/stable";
import "regenerator-runtime/runtime";

babel-runtime

代码语言:javascript复制
npm i babel-runtime -S

为了解决 @babel/polyfill带来的问题,Babel提供了单独的包babel-runtime用于提供编译模块的工具函数,启用插件babel-plugin-transform-runtime后,Babel就会使用babel-runtime下的工具函数。

babel-runtime插件能够将这些工具函数的代码转换成require语句,指向为对babel-runtime的引用。每当要转译一个api时都要手动加上require(‘babel-runtime’)。简单说 babel-runtime 更像是一种按需加载的实现,比如你哪里需要使用 Promise,只要在这个文件头部 require Promise from ‘babel-runtime/core-js/promise’就行了

不过如果你许多文件都要使用 Promise,难道每个文件都要 import 一遍不成?

babel-plugin-transform-runtime

为了方便使用 babel-runtime,解决手动 require 的苦恼。它会分析我们的 ast 中,是否有引用 babel-rumtime 中的垫片(通过映射关系),如果有,就会在当前模块顶部插入我们需要的垫片。

transform-runtime 是利用 plugin 自动识别并替换代码中的新特性,你不需要再引入,只需要装好 babel-runtime 和 配好 plugin 就可以了。

好处是按需替换,检测到你需要哪个,就引入哪个 polyfill,如果只用了一部分,打包完的文件体积对比 babel-polyfill 会小很多。而且 transform-runtime 不会污染原生的对象,方法,也不会对其他 polyfill 产生影响。

所以 transform-runtime 的方式更适合开发工具包,库,一方面是体积够小,另一方面是用户(开发者)不会因为引用了我们的工具,包而污染了全局的原生方法,产生副作用,还是应该留给用户自己去选择。

babel-runtime 和 babel-plugin-transform-runtime

在大多数情况下,你应该安装 babel-plugin-transform-runtime 作为开发依赖(使用 —save-dev),并且将 babel-runtime 作为生产依赖(使用 —save)。这个看vue-cli生成的 package.json就能发现。

因为babel编译es6到es5的过程中,babel-plugin-transform-runtime这个插件会自动polyfill es5不支持的特性,这些polyfill包就是在babel-runtime这个包里(core-js 、regenerator等)

npm install —save-dev babel-plugin-transform-runtime

npm install —save babel-runtime

使用技巧

以下内容摘自 https://blog.csdn.net/vv_bug/article/details/107092536 @babel/preset-env包含了一些基本es语法转换的插件(箭头函数、类转换等等),同时还支持polyfill,有usage跟entry模式,但是preset-env添加polyfill会像之前使用@babel/polyfill一样,会污染全局变量。

@babel/plugin-transform-runtime主要是利用@babel/runtime提取了一些公共的babel帮助函数,同时也支持polyfill的添加,添加的polyfill都是以一个局部变量的形式引入,不会污染全局变量。 如果你做的是一个二方库,然后需要被别人依赖,那么建议使用@babel/plugin-transform-runtime来引入polyfill,因为你要尽可能的专注于做自己的事,而不是说去影响别人,语法转换可以使用preset-env预设,比如以下配置

代码语言:javascript复制
module.exports = {
    presets: [
        [
            "@babel/preset-env",
        ]
    ],
    plugins: [
        [
            "@babel/plugin-transform-runtime",
            {
                corejs: {version: 3, proposals: true},
                helpers: true,
                useESModules: true,
                regenerator: true,
                absoluteRuntime: "./node_modules"
            }
        ]
    ]
};

如果你做的是一个普通的业务项目的话,可以用preset-env来转换语法和polyfill,然后再利用@babel/plugin-transform-runtime来引入helpers跟generator做到代码重复利用,比如以下配置:

代码语言:javascript复制
module.exports = {
    presets: [
        [
            "@babel/preset-env",
            {
                corejs: 3,
                useBuiltIns: 'usage',
            }
        ]
    ],
    plugins: [
        [
            "@babel/plugin-transform-runtime",
            {
                corejs: false,
                helpers: true,
                useESModules: false,
                regenerator: true,
                absoluteRuntime: "./node_modules"
            }
        ]
    ]
};

@babel/plugin-transform-runtime常见配置参照:https://babeljs.io/docs/en/babel-plugin-transform-runtime#options

下面在介绍几个与Babel相关的

@babel/core:babel的核心库

babel-loader:使用webpack时作为有个loader在代码混淆之前进行代码转换

@babel/preset-env:babel预设的一种

@babel/cli:允许使用babel命令转译文件

0 人点赞