Babel7
babel用途
- 语法转换
- 通过code-js等,polyfill 目标环境缺失的特性
- Source code transformations (codemods)
- And more !
名词概念
| key word | description | example | uses |
|---|---|---|---|
| preset | 插件的集合 | babel/preset-env | 语法转换,不包含polyfill |
| babel/preset-react、babel/preset-typescript、babel/preset-flow | |||
| plugin | 语法转换 | @babel/plugin-proposal-optional-chaining | |
| polyfill | 添加新的API、实例或者静态方法 | @babel/polyfill (old versions before babel 7.4.0) | 添加到全局作用域 |
| core-js/stable regenerator-runtime/runtime(new babel versions) | |||
| @babel/runtime、@babel/plugin-transfrom-runtime | 按需引入,不污染全局作用域 |
测试用例
如下测试用例,是我按照每个es版本新增内容添加的,语法和api各找一个
// --------es6-----------
// 语法
let a = 123
// 新api
let p = new Promise(()=>{})
// --------es2016--------
// 语法
let x = 2**10
// 新api
let y = [1, 2].includes(1)
// --------es2017--------
// 新api
let z = Object.entries({a:1})
// --------es2018--------
// 新语法
let { x1, y1, ...z1 } = { x1: 1, y1: 2, a: 3, b: 4 };
// 新api
let p1 = new Promise(()=>{}).finally(() => {})
// --------es2019--------
// 新语法
try { } catch (unused) { }
try { } catch { }
// 新api
let s = Symbol('s')
s = s.description
// --------es2020--------
// 新语法
let c = s?.a
// 新api
let d = 'ab ab ac'.matchAll(/ab/g)
// --------es2021--------
// 新语法
let f = 1_000_000_000
// 新api
let e = 'ab ab'.replaceAll('ab', 'ac')
// --------es2022--------
// 新语法
let getX;
class C {
#x = 1;
static {
getX = c => c.#x;
}
}
// 新api
// --------es2023--------
// 新语法
// 新api
let i = [2, 1, 2].findLastIndex(item => item == 2)
console.log(a, p, x, y, z, x1, y1, z1, p1, s, c, d, e, f, i, getX(new C()))
尝试babel-cli
1. 没有babel.config.json
不做转换,原样输出
2. 有preset/env
babel.config.json
{
"presets": ["@babel/preset-env"]
}
"@babel/cli": "^7.19.3",
"@babel/core": "^7.19.3",
"@babel/preset-env": "^7.19.3"
转换后:2023的语法都给转了,api都没加上polyfill 转换后如下:
"use strict";
var _s;
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); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); }
function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } }
function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); }
function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); }
function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; }
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
// --------es6-----------
// 语法
var a = 123; // 新api
var p = new Promise(function () {}); // --------es2016--------
// 语法
var x = Math.pow(2, 10); // 新api
var y = [1, 2].includes(1); // --------es2017--------
// 新api
var z = Object.entries({
a: 1
}); // --------es2018--------
// 新语法
var _x1$y1$a$b = {
x1: 1,
y1: 2,
a: 3,
b: 4
},
x1 = _x1$y1$a$b.x1,
y1 = _x1$y1$a$b.y1,
z1 = _objectWithoutProperties(_x1$y1$a$b, ["x1", "y1"]); // 新api
var p1 = new Promise(function () {})["finally"](function () {}); // --------es2019--------
// 新语法
try {} catch (unused) {}
try {} catch (_unused) {} // 新api
var s = Symbol('s');
s = s.description; // --------es2020--------
// 新语法
var c = (_s = s) === null || _s === void 0 ? void 0 : _s.a; // 新api
var d = 'ab ab ac'.matchAll(/ab/g); // --------es2021--------
// 新语法
var f = 1000000000; // 新api
var e = 'ab ab'.replaceAll('ab', 'ac'); // --------es2022--------
// 新语法
var getX;
var _x = /*#__PURE__*/new WeakMap();
var C = /*#__PURE__*/_createClass(function C() {
_classCallCheck(this, C);
_classPrivateFieldInitSpec(this, _x, {
writable: true,
value: 1
});
}); // 新api
// --------es2023--------
// 新语法
// 新api
getX = function getX(c) {
return _classPrivateFieldGet(c, _x);
};
var i = [2, 1, 2].findLastIndex(function (item) {
return item == 2;
});
console.log(a, p, x, y, z, x1, y1, z1, p1, s, c, d, e, f, i, getX(new C()));
3. babel.config.json 更改如下后,打包无变化
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "entry",
"corejs": "3.22"
}
]
]
}
4. 配合browserslist使用
.browserslistrc 还是没啥用
> 0.25%
not dead
5. 配合 core-js使用,入口添加
import "core-js/stable";
所有的满足browserslist的polyfill都引入了 , 不管用没用到
require("core-js/modules/es.symbol.js");
require("core-js/modules/es.symbol.description.js");
require("core-js/modules/es.symbol.async-iterator.js");
...
6. 更改.browserslistrc 兼容更低的浏览器
> 1%
last 2 versions
not ie <= 8
引入的polyfill更多了
7. 按需引入
更改babel.config.json
"useBuiltIns": "usage",
只引入了 使用到的polyfill
多个了
require("core-js/stable");
删除入口的, 当使用usage时 不需要这个
import "core-js/stable";
8. corejs版本测试
去除babel.config.json, "corejs": "3.22",默认会使用版本2
es2019及以后的api没有添加上polyfill
总结
- 使用
babel要配合browserlists,按照指定环境目标做代码转换 - 使用
userBuildIns: usage时,会按需引入 - 使用
userBuildIns: entry时,要在入口 添加import "core-js/stable"; - 低版本的corejs并不能处理最新es版本,比如使用babel6时就会发现有些新语法处理不了,要手动引入对应plugin