一、@babel/preset-env
preset-env根据配置的浏览器的列表,自动加载当前浏览器所需要的插件,然后对ES语法做转换。
1. targets
string | Array<string> | { [string]: string }
描述项目所在环境,比如
{
"targets": "> 0.25%, not dead"
}或者
{
"targets": {
"chrome": "58",
"ie": "11"
}
}babel中内置了browserslist,也可以用.browserslistrc配置文件配置,比如
> 0.25%, not dead或者在package.json中指定:
"browserslist": "> 0.25%, not dead"可以用下面命令查看> 0.25%, not dead代表的浏览器列表:
$ npx browserslist "> 0.25%, not dead"
and_chr 94
and_ff 92
and_uc 12.12
chrome 94
chrome 93
chrome 92
chrome 91
chrome 87
edge 94
...如果不指定targets,将会转化所有的ES2015-ES202语法到ES5。不推荐这么做,这样不能发挥preset-env针对性转化的作用。
2. loose
boolean,默认false。设为true的时候是会preset的插件开启宽松模式。loose模式会生成简单的ES5代码,正常模式则会尽可能遵循ECMAScript 6的语义,一般不建议开启。
举个例子,对于下面的代码:
class Test {
say(){}
}如果开启loose模式,会十分接近我们的ES5写法,直接在Test.prototype上增加属性:
var Test = /*#__PURE__*/function () {
function Test() {}
var _proto = Test.prototype;
_proto.say = function say() {
console.log('say');
};
return Test;
}();如果未开启loose,会利用Object.defineProperty在Test上增加属性:
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
var Test = /*#__PURE__*/function () {
function Test() {
_classCallCheck(this, Test);
}
_createClass(Test, [{
key: "say",
value: function say() {
console.log('say');
}
}]);
return Test;
}();3. moduels
"amd" | "umd" | "systemjs" | "commonjs" | "cjs" | "auto" | false,默认为"auto".
是否把ESM语法转为其他类型,如果是false就不转化。
比如对于以下代码:
import { a } from './a.js'
var b = 1;
export default b;
export { a }如果是modules是cjs,会转为:
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "a", {
enumerable: true,
get: function get() {
return _a.a;
}
});
exports["default"] = void 0;
var _a = require("./a.js");
var b = 1;
var _default = b;
exports["default"] = _default;默认情况下,@babel/preset-env会根据caller data确定是否转换ES6的模块,比如使用babel-loader、@rollup/plugin-babel时。
4. debug
boolean,默认为false。
开启后,会在控制台输出当前的targets、使用的插件列表等信息。
5. include/exclude
Array<string|RegExp>,默认为[]
表示增加或排除的插件列表
6. useBuiltIns
"usage" | "entry" | false,默认为false。
@babel/preset-env使用polyfill的配置。
什么是polyfill?polyfill可翻译为垫片,就是为旧浏览器提供新的功能(API)。
Babel只转换不兼容的新语法,比如箭头函数和class,对于新的API,比如Iterator、Generator、Set、Map、Proxy、Reflect、Symbol、Promise、Object.assign()等,是不会转换的。这时候就需要polyfill了。
babel在7.4.0版本后弃用了@babel/polyfill,建议我们直接使用core-js,并且设置corejs的版本来替换polyfill。
(1)false
useBuiltIns为false的话,不对polyfill做操作。如果引入了core-js,则无视配置的浏览器兼容,引入所有的polyfill。
(2)entry
useBuiltIns是entry的话,引入浏览器不兼容的polyfill,需要在入口文件手动添加import 'core-js',会自动根据browserslist替换为浏览器不兼容的polyfill。这里需要指定core-js的版本:
"useBuiltIns": "entry",
"corejs": 2,比如对于下面代码:
import "core-js";
new Promise(() => {})babel转化结果为:
"use strict";
require("core-js/modules/es6.array.copy-within.js");
require("core-js/modules/es6.array.every.js");
// 省略很多require('core-js/modules/es6...')
new Promise(function () {});(3)usage
useBuiltIns是usage的话,会根据配置的浏览器的兼容性,以及代码中用到的API来进行polyfill,实现了按需添加。
"useBuiltIns": "usage",
"corejs": 2,比如,对于以下代码:
new Promise(() => {})转化结果为:
"use strict";
require("core-js/modules/es6.object.to-string.js");
require("core-js/modules/es6.promise.js");
new Promise(function () {});7. corejs
string or { version: string, proposals: boolean },默认为"2.0"。
执行core-js的版本,该选项仅在与useBuiltIns为entry或usage时有效。
二、@babel/plugin-transform-runtime
如果我们有很多需要编译的文件的时候,每个文件中都会有这些方法的定义,这样整个包就会很大,runtime把这些方法抽离到一个公共的地方@babel/runtime/helpers,所以可以让我们打包出来的源码变小。
注意安装依赖的时候,@babel/runtime要--save而不是--save-dev,因为它是运行时引入的,其实上面的core-js也是一样:
npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime1. corejs
false, 2, 3 or { version: 2 | 3, proposals: boolean },默认false。
指定core-js的版本,注意core-js3版本才包含[].includes语法。
| corejs | 安装命令 |
|---|---|
| false | npm install --save @babel/runtime |
| 2 | npm install --save @babel/runtime-corejs2 |
| 3 | npm install --save @babel/runtime-corejs3 |
举个例子,对于以下代码:
class Test {
}
const c = [1, 2, 3].includes(1)如果设置如下:
{
"presets": [
[
"@babel/preset-env",
]
],
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"corejs": 3
}
]
]
}转换结果:
"use strict";
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _includes = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/includes"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/classCallCheck"));
var _context;
var Test = function Test() {
(0, _classCallCheck2["default"])(this, Test);
};
var c = (0, _includes["default"])(_context = [1, 2, 3]).call(_context, 1);@babel/plugin-transform-runtime中的core-js引入的是局部变量,不会污染环境,比如_includes。而@babel/preset-env中的core-js使用的方式是require("core-js/modules/es7.array.includes.js"),会污染全局变量。
如果指定了这里的core-js为2或3,并且preset-env设置了useBuiltIns为usage,那么preset-env的core-js就用不到了,因为还是使用运行时的。
2. helpers
boolean,默认true。
是否用外部引入的方式使用帮助函数,比如classCallCheck、extends等。
如果设置为false,则会在文件顶部声明这些helper,而不是引入外部文件。
3. regenerator
boolean,默认true。
是否开启添加regenerator函数的polyfill防止全局污染。
举个例子,对于以下代码:
function* testGenerator() {
yield '1';
yield '2';
return '3';
}如果设置为true,转化结果为:
"use strict";
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
var _marked = /*#__PURE__*/_regenerator["default"].mark(testGenerator);
function testGenerator() {
return _regenerator["default"].wrap(function testGenerator$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return '1';
case 2:
_context.next = 4;
return '2';
case 4:
return _context.abrupt("return", '3');
case 5:
case "end":
return _context.stop();
}
}
}, _marked);
}如果设置为false,并且文件中使用了generator,会在文件顶部require("regenerator-runtime/runtime.js"),会造成全局污染。
三、配置示例
// .babelrc
{
"presets": [
[
"@babel/preset-env",
{
// "modules": "cjs",
"useBuiltIns": "usage",
"corejs": 2,
// "loose": false,
// "targets": "chrome 79",
// "debug": true,
}
],
],
"plugins": [
[
"@babel/plugin-transform-runtime",
{
// "corejs": 3,
"helpers": false,
"regenerator": false,
}
],
]
}