一、为什么要编译
ES6 是下一代的 JavaScript 标准,虽然目前大部分浏览器都兼容 ES6 的语法。
但是,ES6 带来的不止是之前说到那些简单的语法,更强大的功能在后面。比如可以使用像面向对象语言中的模块化编程。
但是,大部分浏览器都不支持这样的语法,所以我们需要借助一些工具来把 ES6 的语法转换为可以让浏览器识别到 ES5的语法。
Yes!
这就是 Babel 要做的。
二、快速使用
1. 安装一下的包
假如环境中没有安装淘宝NPM 镜像,就没有
cnpm
, 请使用npm
命令
cnpm install --save-dev @babel/core @babel/cli @babel/preset-env
cnpm install --save @babel/polyfill
2. 在项目的根目录下创建一个命名为 babel.config.js 的配置文件,其内容为:
const presets = [
[
"@babel/env",
{
corejs: 2,
useBuiltIns: "usage",
targets: {
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1",
},
},
],
];
module.exports = { presets };
3. 在项目主目录下创建实例文件
先在项目主目录下创建 src
目录
mkdir src
接下来在 src 目录下创建两个文件 main.js
和 lib.js
touch src/main.js src/lib.js
分别写入如下内容
// lib.js
let name = "shark"
let f = (x, y) => x + y
export {name, f}
// main.js
import {name, f} from './lib';
console.log(name)
console.log(f(2, 4))
4. 运行此命令将 src 目录下的所有代码编译到 dist 目录:
src 目录需要提前创建,并且目录内有需要转码的 js 文件
dist 目录会被自动创建
./node_modules/.bin/babel src --out-dir dist
你可以利用 npm@5.2.0 所自带的 npm 包运行器将
./node_modules/.bin/babel
命令缩短为npx babel
npx babel src --out-dir dist
5. 运行如下命令,验证转码结果
node dist/main.js
也可以直接观察
dist
目录中的两个文件,会发现原来 ES6 中的包导入、导出语法被转换为
Node.js 可以识别的
假如想了解更多,请继续阅读,或者阅读中文官方文档
三、 Babel 语法转换的实现原理
语法转换功能以插件的形式出现,插件是小型的 JavaScript 程序,用于指导 Babel 如何对代码进行转换。
一个插件对应了一种新的语法,比如 ES6 中的箭头函数使用的是插件 @babel/plugin-transform-arrow-functions
。
可以试着在一个目录中执行如下操作
在项目主目录下创建如下文件和内容
./src/index.js
import {name, f} from './lib';
console.log(name)
console.log(f("hello"))
./src/lib.js
let name = "shark"
let f = arg => arg
export {name, f}
之后在 shell 命令行中执行如下命令
npm install --save-dev @babel/plugin-transform-arrow-functions
./node_modules/.bin/babel src --out-dir dist --plugins=@babel/plugin-transform-arrow-functions
- src 是包含最新语法代码的 js 文件目录
- dist 是存放转换后的目录
现在,我们代码中的所有箭头函数(arrow functions)都将被转换为 ES5 兼容的函数表达式了:
const fn = () => 1;
// converted to 转换为
var fn = function fn() {
return 1;
};
这是个好的开始!但是我们的代码中仍然残留了其他 ES6 的特性,我们希望对它们也进行转换。我们不需要一个接一个地添加所有需要的插件,我们可以使用一个 "preset" (即一组预先设定的插件)。
就像插件一样,你也可以根据自己所需要的插件组合创建一个自己的 preset 并将其分享出去。J对于当前的用例而言,我们可以使用一个名称为 env
的 preset。
npm install --save-dev @babel/preset-env
./node_modules/.bin/babel src --out-dir dist --presets=@babel/env
如果不进行任何配置,上述 preset 所包含的插件将支持所有最新的 JavaScript (ES2015、ES2016 等)特性。但是 preset 也是支持参数的。我们来看看另一种传递参数的方法:配置文件,而不是通过终端控制台同时传递 cli 和 preset 的参数。
配置文件的形式
现在,我们首先创建一个名为 babel.config.js
的文件,并包含如下内容:
const presets = [
[
"@babel/env", // 就是这里了
{
targets: {
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1",
},
},
],
];
module.exports = { presets };
此时,就可以这样执行命令了:
./node_modules/.bin/babel src -d dist
或者
// 需要安装 @babel-cli
npx babel src -d dist --presets=@babel/env
-d
是--out-dir
的简写
现在,名为 env
的 preset 只会为目标浏览器中没有的功能加载转换插件。
语法都已经清楚了,接下来我们看看 polyfills 。
Polyfill 填充工具
@babel/polyfill 模块包括 core-js 和一个自定义的 regenerator runtime 模块用于模拟完整的 ES2015+ 环境。
由于我们构建的是一个应用程序,因此我们只需安装 @babel/polyfill
即可:
npm install --save @babel/polyfill
注意,使用
--save
参数而不是--save-dev
,因为这是一个需要在你的源码之前运行的 polyfill。
幸运的是,我们所使用的 env
preset 提供了一个 "useBuiltIns"
参数,当此参数设置为 "usage"
时,就会加载上面所提到的最后一个优化措施,也就是只包含你所需要的 polyfill。注意,使用此参数时,需要使用 corejs
选项指定版本,
使用此新参数后,修改配置如下:
const presets = [
[
"@babel/env",
{
corejs: 2,
useBuiltIns: "usage",
targets: {
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1",
},
},
],
];
module.exports = { presets };
Babel 将检查你的所有代码,以便查找目标环境中缺失的功能,然后只把必须的 polyfill 包含进来。示例代码如下:
Promise.resolve().finally();
将被转换为:
"use strict";
require("core-js/modules/es7.promise.finally");
Promise.resolve().finally();
总结
-
@babel/cli
实现从终端运行 Babel, -
@babel/polyfill
来模拟所有新的 JavaScript 功能 -
env preset
只对我们所使用的并且目标浏览器中缺失的功能进行代码转换和加载 polyfill。
三、配置
1. 选择配置文件的格式
目前官方推荐使用的配置文件为: babel.config.js 格式的配置文件。
当然也可以使用 .babelrc 格式的配置文件。
配置文件的位置
无论选择那种格式的配置文件,都需要放置在项目的根目录(package.json 文件所在目录)下。
配置文件名:
babel.config.js
// 或者
.babelrc
配置文件内容
babel.config..js
官方建议的配置方式如下
项目主目录下的 babel.config.js 文件中的内容:
module.exports = function (api) {
api.cache(true);
const presets = [
[
"@babel/env", // 就是这里了
{
corejs: 2,
useBuiltIns: "usage",
targets: {
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1",
},
},
],
];
return {
presets
};
转换命令
npx babel src -d dist