Babel7对各个es版本的处理

818 阅读3分钟

Babel7

babel用途

  • 语法转换
  • 通过code-js等,polyfill 目标环境缺失的特性
  • Source code transformations (codemods)
  • And more !

名词概念

key worddescriptionexampleuses
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

总结

  1. 使用babel要配合browserlists,按照指定环境目标做代码转换
  2. 使用userBuildIns: usage时,会按需引入
  3. 使用userBuildIns: entry时,要在入口 添加 import "core-js/stable";
  4. 低版本的corejs并不能处理最新es版本,比如使用babel6时就会发现有些新语法处理不了,要手动引入对应plugin

参考