# Babel 核心基础 与 应用实践

TIP

本章节我们来学习 Babel 的入门知识,主要帮助大家快速掌握 Babel 是什么,及简单使用 Babel 来将 ES6 转码为(ES5 或 ES3)的代码,为后面深入学习做准备。

关于 Babel 更高级的用法(与 Webpack 的结合使用),我们在学习 Webpack 的时候再深入讲解。

本章节我们会从以下几个点来展开讲解

  • 什么是 Babel ?
  • 使用 Babel 在线编译器转码
  • Babel 的安装与使用

# 一、Babel 简介与基本使用

TIP

深入浅出 Babel 是什么,Babel 的使用方式,使用 Babel 编译 ES6 代码前后的结果 等

# 1、什么是 Babel

TIP

Babel 是一个 JavaScript 编译器,用来将 ES6 的代码转换成 ES6 之前(ES5 或 ES3)的代码。

说的直白一点,Babel 就是将新版本的代码(ES6)转换成浏览器可以兼容的 ES5 或 ES3 版本的代码,这样我们就可以放心大胆的使用 ES6 ,而不担心兼容性问题了。

关于 ES6 之后的代,其兼容性问题就交给 Babel 来处理了,Babel 可以说是 ES6 的好兄弟 !

# 2、使用 Babel 在线编译器转码

TIP

接下来我们编写了一段简单的 ES6 代码,然后利用 Babel 的在线编译工具来编译,具体如下

注意编译器左边的勾选项

image-20230317185407480

# 2.1、编译前后代码对比解析

编译前 ES6 代码如下

let username = "icoding";
const sex = "male";

const add = (x, y) => x + y;

new Promise((resolve, reject) => {
  resolve("成功 !");
}).then((value) => {
  console.log(value);
});

const obj = Object.assign({ a: 1 }, { b: 4 });
console.log(obj);

利用 Babel 在线编译后的代码如下

var username = "icoding";
var sex = "male";
var add = function add(x, y) {
  return x + y;
};
new Promise(function (resolve, reject) {
  resolve("成功 !");
}).then(function (value) {
  console.log(value);
});
var obj = Object.assign({ a: 1 }, { b: 4 });
console.log(obj);

编译解析:

  • Babel 转码后,let 和 const 转换成了 var,箭头函数转换成了普通函数。
  • 但 Promise、Object.assign()编译后,并没有做任何的修改,还是原样输出了

原因是:

  • Babel 只能编译 ES6 的大部分语法(如:let、const、class、()=>箭头函数这些类似新增的语法),但对于 ES6 新增的 API(如:Set、Map、Promise、Array.from()Object.assign())本身默认是没有办法通过 Babel 编译来转换成 ES5 之前的语法的。
  • 因为语法的转换很简单,直接替换就完事。但像 Promise 等这些新增的全局对象,并没有办法直接替换,除非再实现一份,否则是无法转换的。
  • 所以要解决 ES6 新增的 API,我们只能人为的去实现这些 API 方法,说的直白一点就是在当前代码中通过 ES5 版本的 JS 来手动实现Promise、Set、Map等方法。当然这些方法不需要我们自己去写,官方帮我们实现了,我们只需要引入第三方对应的 JS 模块就可以了。

# 2.2、引入 polyfill

TIP

能过前面的学习,我们知道 Babel 只能编译 ES6 的大部分语法,对 ES6 新的 API 本身是没有办法转的。所以我们需要通过引入第三方模块来解决代码(目标环境-浏览器)中缺失的 API。

polyfill翻译为中文为"垫片",所谓的”垫片“,是指垫平不同浏览器之间差异的东西。比如我们上面提到的,在低版本浏览器中不支持 ES6 的大部分语法,所以polyfill提供了 ES6 中新增的所有 API。通过在我们的项目中引入polyfill就可以补全浏览器缺失的 API。

在 bootcdn 网站上,搜索 babel 官方提供的 polyfill,搜索名字为babel-polyfill,具体如下

image-20230317192727760

代码经过 Babel 转码后,我们再在项目中,手动引入polyfill.min.js文件,如下

<script src="https://cdn.bootcdn.net/ajax/libs/babel-polyfill/7.12.1/polyfill.min.js"></script>
<script>
  var username = "icoding";
  var sex = "male";
  var add = function add(x, y) {
    return x + y;
  };
  new Promise(function (resolve, reject) {
    resolve("成功 !");
  }).then(function (value) {
    console.log(value);
  });
  var obj = Object.assign({ a: 1 }, { b: 4 });
  console.log(obj);
</script>

注:

为了测试效果,可以安装低版本的浏览器来测试,以下是firefox浏览器所有版本的 下载地址 (opens new window)

我下载的是 firefox32 版来测试,在 firefox32.0 版中,是不支持Object.assign()方法的,这个方法从 firefox34.0 版开始支持。

以上代码在没有引入polyfill前,在 firefox32 中没有会抛出错误TypeError: Object.assign is not a function,引入后,则正常输出结果。

在实际的项目开发中

我们肯定不会手动的在编译好的代码中来引入 polyfill,因为这种方式会把当前代码中没有用到的 ES6API 全都加载进来了,这样项目的体积就太大了。我们希望能实现按需加载(也就是只加载当前项目中用到的 ES6 API)

后面我们会结合 Webpack 来实现按需引入。

# 3、Babel 的安装与使用

TIP

上面使用 Babel 的在线编译是为了让大家能快速的了解 Babel,在实际开发中,我们肯定不会利用在线编译来转码,而是通过安装 Babel 来实现转码。

Babel 有哪些使用方式,在官网中即可查看 https://babeljs.io/setup (opens new window)

习惯性通过官网查看学习,毕竟最新的使用方式也会实时更新和升级(避免现在学习了,未来又会有新的变化)

这里我们先来学习使用 Babel 的 CLI 命令行工具来实现转码,具体如下

image-20230318010312280

注:

Babel 的使用方式非常多以上 官方链接 (opens new window)中都是,我们常见的会使用 CLI 命令行工具 或 在 Webpack 中使用。

当我们点击任意使用方式,即可跳转至 对应的使用步骤,按步骤操作即可

# 3.1、Babel 的安装

TIP

  • 首先新建项目目录文件夹,所有 Babel 都是安装在当前项目下
  • 则在项目录下执行npm init -y 初始化项目(生成package.json文件)
  • 执行下面命令,安装 Babel 相关的两个包,安装成 开发依赖
# 我们可以通过运行以下命令在本地安装 Babel CLI
# 注:以下命令会默认安装最新版本的 babel
# @babel/core Babel 的所有核心功能都在这里
# @babel/cli 是Babel命令行转码工具,如果我们想在通过命令进行Babel转码,就需要安装它,如:在终端通过命令 npx babel...或 npm run bulid  来实现转码
npm install --save-dev @babel/core @babel/cli

在实际开发中

不会每次都使用最新版本,毕竟是第三的包,我们无法控制。如果官方升级,有可能语法也会变化,就会导致项目报错而无法运行,这也是非常常见的情况。

所以大家在学习时,可以参考我现在版本,安装时带上对应的版本号。

安装成功后,会在package.json文件中的devDependencies 属性中,添加如下两个字段

 "devDependencies": {
      // 提供了 CLI 命令,用来执行 babel 相关命令
    "@babel/cli": "^7.21.0",
      // babel 的核心包,用来发号施令调度用的,不做具体的事情,具体怎么做交给其他包来完成
    "@babel/core": "^7.21.3"
  }

温馨提示:

可以在安装前,执行npm view @babel/core versions 来查其所有版本

Babel 相关的包安装好之后,接下来创建项目目录和需要转码的 JS 代码,然后利用 Babel 命令来转码。

# 3.2、创建目录和对应的 ES6 代码

TIP

  • 转码前,在当前目录下新建src目录,然后在src目录下新建main.js文件
  • 把需要转码的代码放在main.js文件中

代码如下

let username = "icoding";
const sex = "male";

const add = (x, y) => x + y;

new Promise((resolve, reject) => {
  resolve("成功 !");
}).then((value) => {
  console.log(value);
});

const obj = Object.assign({ a: 1 }, { b: 4 });
console.log(obj);

# 3.3、在 package.json 文件中添加执行的 babel 命令

TIP

接下来,在package.json文件的scripts属性中,新增"build": "babel src -d dist"

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "babel src -d dist"
  }

scripts 属性解析

  • scripts属性用于存放通过npm run命令来执行的命令。
  • 通过在命令行中输入npm run build 就相当于是执行后面的babel src -d dist,那你可能会想,那我直接把babel src -d dist命令在终端执行,为什么会报错呢?这个问题,我们放在后面来给大家讲。
  • test用于测试使用,可以删除,也可以保留。

"build": "babel src -d dist" 命令解读

  • build:构建创建的意思,这个名字可以自己取,主要用于 npm run build 时来执行后面的babel src -d dist命令
  • babel:表示编译执行的是 babel 命令
  • src:表示将 src 目录下的所有 JS 文件进行编译(用于存放需要编译的 ES6 文件),也可以指定单独的某个 JS 文,如:babel src/main.js -d dist
  • -d:表示输出,-d--out-dir 的缩写,表示输出目录的意思
  • dist:表示编译后的文件输出到 dist 目录下,这个文件夹的名字可以自定义

当我们执行上面的命令后,在当前目录下生成了 dist 目录,同时在目录中有main.js文件

image-20230318015957682

编译结果

以上编译后的代码,仔细观察会发现,只是将格式调整了下,又原文输出了 !本质上么有发生任何变化。

转码失败原因

  • 原因是,缺少了 Babel 的配置文件,我们要能实现 ES6 编译成兼容 ES5 或 ES3 的代码,需要在 Babel 的配置文件中配置相关信息(指定编译规则),告诉 Babel 把 ES6 编译成兼容 ES5 还是 ES3 的代码。
  • 如果我们不指定具体将 ES6 的代码编译成兼容 ES5 的,还是 ES3 等,那 Babel 也不知道要如何转,所以他就会原样输出我们的代码。

# 3.4、创建 Babel 配置文件 babel.config.json

TIP

Babel 的配置文件是执行 Babel 时默认在当前目录下搜寻的文件,主要有.babelrc.babelrc.jsbabel.config.jsonpackage.json。它们的配置项都是相同的,作用也是一样的的,只需要选择其中一种即可。

接下来我们在根目录中创建一个babel.config.json配置文件并启用一些 预设。我们可以使用env 预设,该预设为 ES2015+ 启用转换(本质:如何将所有 ES6 转换成 ES5,具体转换规则的方法都在这个包里)。

具体配置如下:

{
  "presets": ["@babel/preset-env"]
}

关于预设的理解

预设可以理解为一组插件的集合,我们想要把 ES6 代码转换成 ES5 或 ES3 的代码,需要用到的插件非常多,而预设相当于是把这些需要用到的插件放到了一个包里,我们只需要安装这个包,然后利用这个包里的插件来帮我们实现对应的转码工作。

在 Babel 6 时期,有年代预设,比如

  • babel-preset-es2015 ES2015 标准中的语法转换器预设
  • babel-preset-es2016 ES2016 标准中的语法转换器预设
  • babel-preset-es2017 ES2017 标准中的语法转换器预设
  • .......

现在没有年代预设了,而是把所有预设打包到一起为@balel/preset-env 中,至后新增的语法需要转换,对应的插件也会更新到这个包中,所以我们现在只需要配置这一个预设就可以。

配置后,我们还需要安装@babel/preset-env包,执行以下命令即可

# @babel/preset-env 包只是告诉babel我们如何把ES6转成ES5,转码后,项目上线并不需要这个包,所以安装成开发依赖
npm install @babel/preset-env --save-dev

安装完成后,可在 package.json 文件中查看@babel/preset-env 的配置依赖信息,如下

 "devDependencies": {
     // 提供了 CLI 命令,用来执行 babel 相关命令
    "@babel/cli": "^7.21.0",
     // babel 的核心包,用来发号施令调度用的,不做具体的事情,具体怎么做交给其他包来完成
    "@babel/core": "^7.21.3",
     // 这个包提供了ES6转ES5的语法转换规则,用来告诉 babel 具体该如何将ES6转ES5
    "@babel/preset-env": "^7.20.2"
  }

注:

你可能会想,明明每次 Babel 转码都需要安装三个包,为什么还要把他们拆分,然后分别安装呢 ?

其实这就是模块化开发思想,这样模块化拆分,每一个包的分工都会非常的明确,需要什么就用什么(避免用不到的都统统引入项目,造成资源的浪费)

# 3.5、再次执行编译命令

以上配置好后,我们接下来再次执行以下命令来编译

npm run build

image-20230318021725730

注:

这一次终于成功了,恭喜你,你已经学会了如何使用 Babel 来实现转码。不过上面 ES6 新增的 API 目前还是实现不了,只能通过手动引入Polyfill来补全。

等我们后面学到Webpack时,我们就可以通过Webpack来实现安需引入空缺的 API。

# 二、总结:Babel 转码流程

TIP

我们利用 Babel 来转码,需要经过以下 7 个步骤

  • ①、创建项目的根目录,如 icoding 新建文件夹
  • ②、在根目录,利用npm init -y来初始化项目,创建package.json文件
  • ③、把需要转码的 JS 文件(main.js)放在当前目录的src目录下(目录名可以自定义)
  • ④、执行以下命令,一次安装 Babel 需要的包,安装成开发依赖
npm install --save-dev @babel/core @babel/cli @babel/preset-env
  • ⑤、在根目录下创建babel.config.json配置文件,配置以下信息
{
  "presets": ["@babel/preset-env"]
}
  • ⑥、在package.json中添加执行 babel 的命令,这样我们就可以通过npm run build命令来执行 babel 命令完成转码。
"scripts": {
    "build": "babel src -d dist"
  }
  • ⑦、最后在当前目录终端执行以下命令,完成转码
npm run build

注:

不过 Babel 只能编译 ES6 的大部分语法,但对于 ES6 新增的 API 是没有办法转的。我们只能通过引入 polyfill 来补全缺失的 API,这样我们的项目就可以在不同版本的浏览器上运行,而不用担心兼容性问题。

不过手动引入 polyfill 会造成我们的 JS 文件过大,因为我们可能只用了部分的 ES6 新特性,但我们把所有缺失的新特性都添加进来了。

这个问题,我们后面学了 Webpack 再来解决。

# 1、npm run build 背后到底做了什么 ?

TIP

package.json中通过配置以下信息,就可以通过npm run build命令来执行 babel 了。

"scripts": {
    "build": "babel src -d dist"
  }

我们说npm run build就相当于是执行了babel src -d dist,那为什么我们直接在命令终端输出babel src -d dist命令会报错呢 ?

原因在于

当我们执行npm run build时, 他会默认找到node_modules/.bin/下的 babel,也就是node_modules/.bin/babel ,打开这个文件,文件内容如下

#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")

case `uname` in
    *CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
esac

if [ -x "$basedir/node" ]; then
  exec "$basedir/node"  "$basedir/../@babel/cli/bin/babel.js" "$@"
else
  exec node  "$basedir/../@babel/cli/bin/babel.js" "$@"
fi

上面的 babel 文件中,相当于执行了以下命令

  node  C:/Users/EDY/Desktop/test/icoding/node_modules/@babel/cli/bin/babel.js  src -d dist
 # 我们在命令行执行上面命令,也可以实现同样的转码效果
 # 在当前目录下,上面命令可以简写成如下
 node .\node_modules\@babel\cli\bin\babel.js src -d dist

总结:

我们把命令配置在 package.json 中,这样在每次执行相同命令时,就可以达到减化输入的命令。

# 2、npx 命令

TIP

npx 是新版的 Node.js 里附带的命令,我们也可能通过在当前目录的命令终端执行以下代码,来实现转码。

npx 的功能和 npm 类似,他在运行时,也会默认找到node_modules/.bin/下面 babel 来执行

npx babel src -d dist

这里我们来补充种写法

# 将当目录下的src目录中的main.js文件转码后,在当前目录下生成转码成功后bundle.js文件
npx babel .\src\main.js -o bundle.js

# -o 右侧是编译后js的存放位置,不过不会自动创建文件,需要手动把文件夹新建好
npx babel .\src\main.js -o .\dist\bundle.js

上次更新时间: 6/8/2023, 9:23:17 PM

大厂最新技术学习分享群

大厂最新技术学习分享群

微信扫一扫进群,获取资料

X