babel配置解读

@babel/polyfill其实就是core-js和regenerator-runtime的集合。

@babel/preset-env负责把新的语法转换成适配目标浏览器的语法,它的功能是由@babel/core来完整的,所以需要安装这个包。

.babelrc的配置:

1
2
3
4
{
"presets": ["@babel/preset-env"],
"plugins": []
}

于是以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 箭头函数
const sum = (a, b) => a + b;
const result = sum(10, 20);

const str = [1, 2, 3, 4];

if (str.includes(1)) {
console.log(1);
}

Promise.resolve(10).then(data => console.log(data));

class People {
constructor(name) {
this.name = name;
}
}

const chenhaha = new People('陈哈哈');

就被转换成了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
"use strict";

function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
// 箭头函数
var sum = function sum(a, b) {
return a + b;
};
var result = sum(10, 20);
var str = [1, 2, 3, 4];
if (str.includes(1)) {
console.log(1);
}
Promise.resolve(10).then(function (data) {
return console.log(data);
});
var People = /*#__PURE__*/_createClass(function People(name) {
_classCallCheck(this, People);
this.name = name;
});
var chenhaha = new People('陈哈哈');

你可以发现箭头函数、class等语法进行了转换,但是includes、Promise等新的api并没有做任何的处理。

在很早以前,会直接使用@babel/polyfill

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 箭头函数
import '@babel/polyfill';

const sum = (a, b) => a + b;
const result = sum(10, 20);

const str = [1, 2, 3, 4];

if (str.includes(1)) {
console.log(1);
}

Promise.resolve(10).then(data => console.log(data));

class People {
constructor(name) {
this.name = name;
}
}

const chenhaha = new People('陈哈哈');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
"use strict";

function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
require("@babel/polyfill");
function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
// 箭头函数
var sum = function sum(a, b) {
return a + b;
};
var result = sum(10, 20);
var str = [1, 2, 3, 4];
if (str.includes(1)) {
console.log(1);
}
Promise.resolve(10).then(function (data) {
return console.log(data);
});
var People = /*#__PURE__*/_createClass(function People(name) {
_classCallCheck(this, People);
this.name = name;
});
var chenhaha = new People('陈哈哈');

这样就会引入所有的polyfill进行全局的更改,无论这个新的api有没有被用到。

现在我们把.babelrc的配置改一下:

1
2
3
4
5
6
7
8
9
10
11
12
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": 3
}
]
],
"plugins": []
}

因为这个功能是依赖core-js和regenerator-runtime这两个包的,所以要安装一下(生产依赖)。因为现在@babel/polyfill已经被废弃了,所以直接安装这两个包。其实安装了@babel/polyfill也是相当于安装了这两个包。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 箭头函数
const sum = (a, b) => a + b;
const result = sum(10, 20);

const str = [1, 2, 3, 4];

if (str.includes(1)) {
console.log(1);
}

Promise.resolve(10).then(data => console.log(data));

class People {
constructor(name) {
this.name = name;
}
}

const chenhaha = new People('陈哈哈');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
"use strict";

require("core-js/modules/es.symbol.js");
require("core-js/modules/es.symbol.description.js");
require("core-js/modules/es.symbol.iterator.js");
require("core-js/modules/es.symbol.to-primitive.js");
require("core-js/modules/es.array.iterator.js");
require("core-js/modules/es.date.to-primitive.js");
require("core-js/modules/es.number.constructor.js");
require("core-js/modules/es.object.define-property.js");
require("core-js/modules/es.string.iterator.js");
require("core-js/modules/web.dom-collections.iterator.js");
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
require("core-js/modules/es.array.includes.js");
require("core-js/modules/es.function.name.js");
require("core-js/modules/es.object.to-string.js");
require("core-js/modules/es.promise.js");
function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
// 箭头函数
var sum = function sum(a, b) {
return a + b;
};
var result = sum(10, 20);
var str = [1, 2, 3, 4];
if (str.includes(1)) {
console.log(1);
}
Promise.resolve(10).then(function (data) {
return console.log(data);
});
var People = /*#__PURE__*/_createClass(function People(name) {
_classCallCheck(this, People);
this.name = name;
});
var chenhaha = new People('陈哈哈');

就达到了按需引用的效果。

到这里其实还是有问题的

  • 这些polyfill其实污染了全局环境,因为是通过全局替换的形式实现的,一般要是做一个独立的web系统,是没有问题的,但是要是做一个第三方的库,使用的人不知道全局环境被污染了,也做了同样的更改,可能会引发问题。
  • 代码转化生成了_classCallCheck等帮助函数,每个用到的地方都重复生成了,造成了重复的代码。

@babel/plugin-transform-runtime的方案就可以解决这个问题。

其中@babel/plugin-transform-runtime的配置corejs的配置不一样会有比较大的差异。

  • corejs默认为false,只做全局替换,提取帮助函数,需要安装生产依赖@babel/runtime。@babel/runtime的作用就是提取babel语法转换的帮助函数。
  • corejs设置为2,对Promise等全局变量做polyfill,inlcudes等原型方法只做全局替换,需要安装生产依赖@babel/runtime-corejs2
  • corejs设置为3,对全局变量和原型方法都做polyfill,需要安装生产依赖@babel/runtime-corejs3

安装@babel/runtime(生产依赖)和@babel/plugin-transform-runtime(开发依赖)。

.babelrc配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"presets": [
[
"@babel/preset-env",
]
],
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"corejs": 3,
"proposals": true
}
]
]
}

当corejs为空或者false的时候:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
// 箭头函数
var sum = function sum(a, b) {
return a + b;
};
var result = sum(10, 20);
var str = [1, 2, 3, 4];
if (str.includes(1)) {
console.log(1);
}
Promise.resolve(10).then(function (data) {
return console.log(data);
});
var People = /*#__PURE__*/(0, _createClass2["default"])(function People(name) {
(0, _classCallCheck2["default"])(this, People);
this.name = name;
});
var chenhaha = new People('陈哈哈');

当corejs为2的时候:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
"use strict";

var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
var _createClass2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/createClass"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/classCallCheck"));
var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));
// 箭头函数
var sum = function sum(a, b) {
return a + b;
};
var result = sum(10, 20);
var str = [1, 2, 3, 4];
if (str.includes(1)) {
console.log(1);
}
_promise["default"].resolve(10).then(function (data) {
return console.log(data);
});
var People = /*#__PURE__*/(0, _createClass2["default"])(function People(name) {
(0, _classCallCheck2["default"])(this, People);
this.name = name;
});
var chenhaha = new People('陈哈哈');

当corejs为3的时候:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
"use strict";

var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _createClass2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/createClass"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/classCallCheck"));
var _includes = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/includes"));
var _promise = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/promise"));
// 箭头函数
var sum = function sum(a, b) {
return a + b;
};
var result = sum(10, 20);
var str = [1, 2, 3, 4];
if ((0, _includes["default"])(str).call(str, 1)) {
console.log(1);
}
_promise["default"].resolve(10).then(function (data) {
return console.log(data);
});
var People = /*#__PURE__*/(0, _createClass2["default"])(function People(name) {
(0, _classCallCheck2["default"])(this, People);
this.name = name;
});
var chenhaha = new People('陈哈哈');