# 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 的好兄弟 !
- Babel 的官网:https://babeljs.io/ (opens new window)
- Babel 中文网站(非官方):https://www.babeljs.cn/ (opens new window)
- Babel 的在线编译网址:https://babeljs.io/repl (opens new window)
# 2、使用 Babel 在线编译器转码
TIP
接下来我们编写了一段简单的 ES6 代码,然后利用 Babel 的在线编译工具来编译,具体如下
注意编译器左边的勾选项
# 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
,具体如下
代码经过 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 命令行工具来实现转码,具体如下
注:
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
文件
编译结果
以上编译后的代码,仔细观察会发现,只是将格式调整了下,又原文输出了 !本质上么有发生任何变化。
转码失败原因
- 原因是,缺少了 Babel 的配置文件,我们要能实现 ES6 编译成兼容 ES5 或 ES3 的代码,需要在 Babel 的配置文件中配置相关信息(指定编译规则),告诉 Babel 把 ES6 编译成兼容 ES5 还是 ES3 的代码。
- 如果我们不指定具体将 ES6 的代码编译成兼容 ES5 的,还是 ES3 等,那 Babel 也不知道要如何转,所以他就会原样输出我们的代码。
# 3.4、创建 Babel 配置文件 babel.config.json
TIP
Babel 的配置文件是执行 Babel 时默认在当前目录下搜寻的文件,主要有.babelrc
、.babelrc.js
、babel.config.json
、package.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
注:
这一次终于成功了,恭喜你,你已经学会了如何使用 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
大厂最新技术学习分享群
微信扫一扫进群,获取资料
X