Babel

作用

  • 语法转换

  • 通过 Polyfill 方式在目标环境中添加缺失的特性 (通过 @babel/polyfill 模块)

@babel/preset-env

  • 一系列插件的集合,提供代码转换功能,需配合Polyfillcore-js来提供一些兼容的特性

  • 根据browserslist的配置来指定支持的浏览器环境

    {
    "browserslist": [
      "> 1%", 
          "last 2 versions", 
          "not ie <= 8"
    ]
    }

Polyfill

  • Babel 7.4.0 以上弃用

  • @babel/polyfill 包括了core-jsregenerator runtime 来模拟完整的ES2015+环境,并添加到了全局作用域

  • 直接使用core-js/stableregenerator-runtime/runtime 来取代

  • 两种引入方式都可

      import "@babel/polyfill";
      // webpack
      module.exports = {
        entry: ["@babel/polyfill", "./app/js"],
      };
    • 缺点:完整引入,包括了兼容所有低版本的代码

    • 优化:通过在.babelrc中配置useBuiltIns 参数

        {
          "presets": [
            [
              "@babel/preset-env",
              {
                "useBuiltIns": "entry", // 根据环境需要引入不同的core-js(target参数可指定环境),需手动提前引入@babel/polyfill或core-js
                        "useBuiltIns": "usage", // 在需要兼容的每个文件中引入需要的补丁(一个bunlder只会加载一次相同的补丁),无需手动引入
                        "useBuiltIns": false, // 或未指定,需手动添加到webpack entry数组中
                        "spec": true,    // 为此预设中支持它们的插件启用更多符合规范但可能较慢的转换。不常用        
                        "loose": true // false更符合ES6规范,true更符合ES5风格,速度快兼容性好
              }
            ]
          ]
        }

transform-runtime

  • 重用babel注入的辅助代码

  • 安装npm install --save-dev @babel/plugin-transform-runtime npm install --save @babel/runtime

  • 目的

    • babel使用了一些包含通用函数的辅助代码比如_extend,这些代码默认会被添加到每一个需要它的文件中,这是不必要的。@babel/plugin-transform-runtime插件会让所有的辅助代码引用@babel/runtime模块来避免重复。@babel/runtime会被编辑到包中。

    • 直接引入@babel/polyfillcore-js例如Promise、Set、Map,会污染全局作用

  • 配置

      // 没有选项
      {
        "plugins": ["@babel/plugin-transform-runtime"]
      }
      // 有选项(都是默认值)
      {
        "plugins": [
          [
            "@babel/plugin-transform-runtime",
            {
              "absoluteRuntime": false,
              "corejs": false,
              "helpers": true,
              "regenerator": true,
              "useESModules": false,
              "version": "7.0.0-beta.0"
            }
          ]
        ]
      }
  • 技术细节

    • 当使用generators/async函数时,自动requires @babel/runtime/regenerator (可通过regenerator选项更改)

    • 如有必要可使用core-js替代polyfill(可通过corejs选项更改)

    • 自动删除嵌入的辅助代码,使用@babel/runtime/helpers模块来替代

  • 实现方式:创建别名函数而不是是定义到全局上

    • Regenerator

        function* foo() {}
        //转换后
        "use strict";
      
        var _regenerator = require("@babel/runtime/regenerator");
      
        var _regenerator2 = _interopRequireDefault(_regenerator);
      
        function _interopRequireDefault(obj) {
          return obj && obj.__esModule ? obj : { default: obj };
        }
      
        var _marked = [foo].map(_regenerator2.default.mark);
      
        function foo() {
          return _regenerator2.default.wrap(
            function foo$(_context) {
              while (1) {
                switch ((_context.prev = _context.next)) {
                  case 0:
                  case "end":
                    return _context.stop();
                }
              }
            },
            _marked[0],
            this
          );
        }
    • core-js

        var sym = Symbol();
      
        var promise = Promise.resolve();
      
        var check = arr.includes("yeah!");
      
        console.log(arr[Symbol.iterator]());
      
        // 转换后
        import _getIterator from "@babel/runtime-corejs3/core-js/get-iterator";
        import _includesInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/includes";
        import _Promise from "@babel/runtime-corejs3/core-js-stable/promise";
        import _Symbol from "@babel/runtime-corejs3/core-js-stable/symbol";
      
        var sym = _Symbol();
      
        var promise = _Promise.resolve();
      
        var check = _includesInstanceProperty(arr).call(arr, "yeah!");
      
        console.log(_getIterator(arr));

      实例方法例如"foobar".includes("foo")corejs: 3中才有效

    • Helper

        class Person {}
      
        // 普通转换:辅助代码会被添加到每个需要的文件中
        "use strict";
      
        function _classCallCheck(instance, Constructor) {
          if (!(instance instanceof Constructor)) {
            throw new TypeError("Cannot call a class as a function");
          }
        }
      
        var Person = function Person() {
          _classCallCheck(this, Person);
        };
        // 使用runtime转换后
        "use strict";
      
        var _classCallCheck2 = require("@babel/runtime/helpers/classCallCheck");
      
        var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
      
        function _interopRequireDefault(obj) {
          return obj && obj.__esModule ? obj : { default: obj };
        }
      
        var Person = function Person() {
          (0, _classCallCheck3.default)(this, Person);
        };

Last updated