介绍
Babel用于将ES6+转换为ES5。
Babel本身不具有任何转换功能,它把转换的功能分解到一个个插件中。如果不配置插件,使用babel命令转换的代码并没有什么变化。
Babel转换ES6或其他规范可能需要十几二十个插件,为了使开发者不需要一个个添加安装配置,Babel提供了几组插件的集合,称为预设(preset)。开发者可以直接使用预设。
例如推荐的预设 env(@babel/preset-env),此预设将包含所有支持现代JavaScript的插件(ES6 ES7等)。
预设可以通过配置文件配置。
配置
Babel 有两种并行的配置文件方式,可以一起使用,也可以单独使用,
- 项目范围的配置
- babel.config.json 及其他扩展babel.config.[js/cjs/mjs]
- 相对文件配置
- .babelrc.json 及其他扩展babel.config.[js/cjs/mjs]。由于兼容原因,.babelrc 相当于 .babelrc.json
- package.json中的babel选项
// json 文件
{
"presets": [...],
"plugins": [...]
}
// js文件
module.exports = function (api) {
api.cache(true);
const presets = [ ... ];
const plugins = [ ... ];
return {
presets,
plugins
};
}
// package.json文件
{
"name": "my-package",
"version": "1.0.0",
"babel": {
"presets": [ ... ],
"plugins": [ ... ],
}
}
示例
安装
npm install -D @babel/core @babel/cli @babel/preset-env
创建目录和文件
// babel.config.json
{
"presets": [
[
"@babel/preset-env", // 指定预设
{
"targets": {
"ie": "8" // 指定目标环境
}
}
]
]
}
// src/util.js
// 语法:箭头函数
const a = () => {
throw new Error('my name is a')
};
// 内置函数:Promise
let b = new Promise(function(resolve,reject){
resolve();
});
// 全局方法:includes
let c = [1,2,3].includes(1);
终端运行
npx babel src/util.js --out-dir dist
查看结果,箭头函数已被转换
// dist/util.js
"use strict";
// 语法:箭头函数
var a = function a() {
throw new Error('my name is a');
};
// 内置函数:Promise
var b = new Promise(function (resolve, reject) {
resolve();
});
// 全局方法:includes
var c = [1, 2, 3].includes(1);
polyfill
上例转换结果发现,Promise和includes没有被转换。
@babel/polyfill
Babel默认只转换语法,而不转换新的API(内置函数),例如Iterator Set Map Proxy Promise Weakmap Array.from Object.assign includes等全局对象和定义在全局对象上的新方法。
Babel提供一个polyfill(@babel/polyfill),它是个代码块,它通过改变全局(将所有方法都加到原型链上)来兼容新API。
它需要在使用API前引入(import)。或在webpack 的 入口 entry中优先添加@babel/polyfill的入口。
@babel/polyfill由core-js2和regenerator-runtime组成。
安装
npm install --save @babel/polyfill
本例polyfill作为生产环境的依赖(require),所以使用--save安装。
// src/util.js
import '@babel/polyfill';
// 语法:箭头函数
const a = () => {
throw new Error('my name is a')
};
// 内置函数:Promise
let b = new Promise(function(resolve,reject){
resolve();
});
// 全局方法:includes
let c = [1,2,3].includes(1);
转换结果:
// dist/util.js
require("@babel/polyfill");
// 语法:箭头函数
var a = function a() {
throw new Error('my name is a');
};
// 内置函数:Promise
var b = new Promise(function (resolve, reject) {
resolve();
});
// 全局方法:includes
var c = [1, 2, 3].includes(1);
@babel/polyfill集成了core-js和regenerator:
core-js:转换一些内置类 promises, symbols, collections, iterators, typed arrays等。可以仅加载必需的功能。
regenerator:作为core-js的补充。
@babel/polyfill有两个缺点:
1.导致打包生成的文件很大,因为它是一整个代码代码块。当只使用部分API时,其他的也会被包含进去。这个问题可以通过单独加载core-js的某个功能来解决。
2.污染全局变量,给很多类的原型链都作了修改。
@babel/plugin-transform-runtime & @babel/runtime
上面两个问题主要在于polyfill的引入是内联的,直接插入了一行代码从而无法优化。
babel提供了插件transform-runtime,使每个文件里不用重复定义polyfill,而改为直接从core-js自动引入对应的方法。
core-js@2 仅支持全局变量(例如Promise)和静态属性(例如Array.from)
core-js@3 增加支持实例属性(例如[].includes)
@babel/plugin-transform-runtime 默认不使用core-js ,需要配置corejs指定core-js版本。
安装
本例@babel/runtime作为生产环境的依赖(require),所以使用--save安装。
npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime core-js@3
使用插件 指定core-js版本
// babel.config.json
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"ie": "8"
}
}
]
],
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"corejs": 3
}
]
]
}
// src/util.js
// import '@babel/polyfill'; // 不用手动引入
// 语法:箭头函数
const a = () => {
throw new Error('my name is a')
};
// 内置函数:Promise
let b = new Promise(function(resolve,reject){
resolve();
});
// 全局方法:includes
let c = [1,2,3].includes(1);
转换结果: Promise和includes改为引用模块中的方法
// dist/util.js
"use strict";
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _includes = _interopRequireDefault(require("@babel/runtime-corejs3/core-js/instance/includes"));
var _promise = _interopRequireDefault(require("@babel/runtime-corejs3/core-js/promise"));
// 语法:箭头函数
var a = function a() {
throw new Error('my name is a');
};
// 内置函数:Promise
var b = new _promise["default"](function (resolve, reject) {
resolve();
});
// 全局方法:includes
var c = (0, _includes["default"])(_context = [1, 2, 3]).call(_context, 1);
代替它们更方便配置polyfill的方式是声明 useBuiltIns。
useBuiltIns
Babel推荐使用的预设 @babel/preset-env 可以根据指定目标环境判断需要做哪些编译。它也支持针对指定目标环境选择需要的polyfill。
@babel/polyfill不支持core-js 2和3 的平滑过渡,Babel 7建议启用core-js3代替使用@babel/polyfill。
如此配置 (“corejs”: { “version”: 3, “proposals”: true }) 而不是 (“corejs”: 3)。需要升级core-js版本为3。
在配置中声明 useBuiltIns ,Babel就会自动引入所需的polyfill,而不需要手动引入@babel/polyfill。
安装
npm install --save-dev @babel/cli @babel/core @babel/preset-env core-js@3
配置
// babel.config.json
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"ie": "8"
},
"useBuiltIns": "usage",
"corejs": 3
}
]
]
}
// src/util.js
"use strict";
require("core-js/modules/es.array.includes");
require("core-js/modules/es.object.to-string");
require("core-js/modules/es.promise");
// 语法:箭头函数
var a = function a() {
throw new Error('my name is a');
};
// 内置函数:Promise
var b = new Promise(function (resolve, reject) {
resolve();
});
// 全局方法:includes
var c = [1, 2, 3].includes(1);
babel-loader
安装
npm install -D babel-loader
// webpack.config.js
module.exports = {
//...
module:{
rules: [
{
test: /\/.js$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader'
}
]
}
]
}
}
其他
Babel 7 中 @babel/preset-env 同 @babel/env 在配置中和安装依赖效果一样