According to Genesis 11, from the earliest days of mankind all lived in one place and spoke one language. They decided to build a tower that reached to the sky, and all the people would live in it, and the human race would never be scattered again. God didn’t agree. He scattered people all over the world, making them speak different languages and difficult to communicate with. As a result, “Babel” became a byword for confusion and language barriers, and is one of the most well-known stories in the Bible.

Applicable version of this article

  "devDependencies": {
    "@babel/core": "^ 7.15.8"."@babel/plugin-transform-runtime": "^ 7.15.8"."@babel/preset-env": "^ 7.15.8"."babel-loader": "^ 8.2.3"."webpack": "^ 5.59.1"."webpack-cli": "^ 4.9.1." "
  },
  "dependencies": {
    "@babel/runtime": "^ 7.15.4"."@babel/runtime-corejs2": "^ 7.15.4"."@babel/runtime-corejs3": "^ 7.15.4"."core-js": "^ 3.18.3"
  }
Copy the code

What is the Babel

Babel is used to convert ECMAScript 2015+ to a backward-compatible version of JavaScript:

  • Conversion syntax (pass@babel/preset-envPlugins for the collection inhelperFunction)
  • Missing from the target environmentPolyfillFunctionality (through third partiespolyfill, e.g.core-js)
  • Source code conversion (codemods)

How Babel works

Babel is divided into three phases:

  1. Resolution (parser) :babel-parser(babylon)Parsed intoAST
  2. Conversion (transform) :All the plugins/presetsASTconversion
  3. Generated (generator) : Final passbabel-generatorGenerate object code +sourcemap.

Babel itself does not have any transformation capabilities, so when we do not configure any plug-ins, the code that goes through Babel and the input are the same.

This paper focuses on the functional mechanism of each package of Babel ecology, so the principle analysis is omitted.

Plugin

In the transform phase, plugins are applied to complete AST transformation:

  1. Convert unsupported grammars to grammars supported by the target environment to achieve the same functionality
  2. Put the unsupportedapiAutomatically introduce the correspondingpolyfill

Plugins fall into three categories:

  1. @babel/plugin-transform-xx: syntax conversion plug-in (the corresponding syntax plug-in will be automatically enabled).
  2. @babel/plugin-proposal-xx: conversion plug-in, which refers to those pairsES Proposal(that is, not yetECMA-262Released feature) the plug-in that performs the transformation, once released, will be renamed as@babel/plugin-transform-xx.
  3. @babel/plugin-syntax-xx: syntax plug-in, which does not need to be configured separately and is dependent on the conversion plug-in for syntax parsing.

Plugins are executed from front to back, and the results of the previous plugin serve as input to the next plugin.

Preset

Preset is a set of officially recommended preset plugins, known as a plugin set, such as:

  • @babel/preset-env for compiling ES2015+ syntax
  • @babel/preset-typescript for TypeScript
  • @babel/preset-react for React
  • @babel/preset-flow for Flow

Preset runs backwards (because I believe most developers will write presets as [” ES2015 “, “stage-0”], stage-x is a set of Javascript syntax proposals, which may depend on ES6 syntax, Parse this into ES6, and then parse ES6 into ES5.)

Plugin will run ahead of Preset.

browserslist

Browserslist is a configuration tool that shares target browsers and Node versions between different front-end tools.

  • caniuse
  • compat-table

eg:package.json:

  "browserslist": [
    "last 1 version"."1%" >."maintained node versions"."not dead"
  ]
Copy the code

core-js

Core-js is a fully modular javascript standard library. Polyfill contains most of ecMA-262’s features so far, such as Promises, Symbols, Collections, Iterators, typed Arrays, etc. The versions currently in use are core-js@2 and core-js@3, among which v2 is not recommended because V3 supports polyfill with more features.

Core-js provides three packages simultaneously:

  1. Core-js: The most commonly used version. Introducing all or some of the features of Core-JS extends all or corresponding polyfills directly into the global environment in which the code runs (by modifying prototypes, etc.). Business code can be written directly using the latest ES method.

    import 'core-js'; // Import all
    import 'core-js/features/array/flat'; // specify the feature namespace.
    [1[2.3], [4[5]]].flat(2); // => [1, 2, 3, 4, 5]
    Copy the code

    In addition, by looking at the core-js source code, it is clear that: The introduction of core-js means the introduction of core-js/features, which introduces all modules, including ES, ESNext (proposal,stage),web; Core-js /stable includes ES + Web, so use the features namespace if some features are introduced.

  2. Core-js-pure: similar to a utility function, not injected into the global environment, so the whole import is invalid. The module method corresponding to Polyfill should be introduced and used separately, instead of the latest ES writing method.

    import flat from 'core-js-pure/features/array/flat';
    flat([1[2.3], [4[5]]].2); // => [1, 2, 3, 4, 5]
    Copy the code

    In addition, by looking at core-js-pure source code, and core-JS source code only internals and modules folders are different, that is, when the module is exported to do some processing, forming a similar tool function call way.

    It is clear that a direct reference to core-js-pure would require extra coding complexity in real business code, which will be simplified later by integrating with @babel/ Runtime.

  3. Core-js-bundle: compiles a packaged version that contains all the polyfill features and is suitable for loading directly from script in the browser.

Core-js is installed in the Dependencies dependency and is usually not used alone, but integrated with Babel.

regenerator-runtime

The regenerator- Runtime module comes from facebook’s Regenerator module. Generator functions, async and await functions are compiled by Babel, and the Regenerator-Runtime module is used to provide functional implementation.

@babel/core

Babel compiler core package, is the main tool for syntax conversion. After executing the plugins, the result object includes {code, map, ast}, etc., where code is the compiled code. Babel version is the version of the package.

@babel/core is rarely used in business projects. Other compiled plug-ins rely on him to compile. So you can see it in the package.json of these plug-ins:

  "peerDependencies": {
    "@babel/core": "^ 7.0.0-0"
  },
Copy the code

PeerDependencies are not installed automatically below NPM7, and are installed by default starting with NPM7, so it is best to install business items into devDependencies manually as well, to be on the safe side.

babel-loader

Use Babel in Webpack to load files that need to be compiled. Note the use of exclude and include.

@babel/polyfill

Babel 7.4 is deprecated because it only relies on core-js and Regenerator-Runtime, which can be installed. And it will introduce all polyfills indiscriminately, which is not suitable for future operating environments such as browsers, introducing on demand is more suitable for actual needs.

@babel/preset-env

Babel7 discards preset-20xx, preset-stage-x and other preset packages and replaces them with @babel/preset-env. @babel/preset-env is an intelligent preset that includes a set of common plug-ins that automatically convert new features in the code to the target browserslist, compat-Table, etc. (just the syntax) based on the target environment.

Using package.json, you can see which plugins it contains:

  "dependencies": {
    "@babel/compat-data": "^ 7.15.0"."@babel/helper-compilation-targets": "^ 7.15.4"."@babel/helper-plugin-utils": "^ 7.14.5"."@babel/helper-validator-option": "^ 7.14.5"."@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^ 7.15.4"."@babel/plugin-proposal-async-generator-functions": "^ 7.15.8"."@babel/plugin-proposal-class-properties": "^ 7.14.5"."@babel/plugin-proposal-class-static-block": "^ 7.15.4"."@babel/plugin-proposal-dynamic-import": "^ 7.14.5"."@babel/plugin-proposal-export-namespace-from": "^ 7.14.5"."@babel/plugin-proposal-json-strings": "^ 7.14.5"."@babel/plugin-proposal-logical-assignment-operators": "^ 7.14.5"."@babel/plugin-proposal-nullish-coalescing-operator": "^ 7.14.5"."@babel/plugin-proposal-numeric-separator": "^ 7.14.5"."@babel/plugin-proposal-object-rest-spread": "^ 7.15.6"."@babel/plugin-proposal-optional-catch-binding": "^ 7.14.5"."@babel/plugin-proposal-optional-chaining": "^ 7.14.5"."@babel/plugin-proposal-private-methods": "^ 7.14.5"."@babel/plugin-proposal-private-property-in-object": "^ 7.15.4"."@babel/plugin-proposal-unicode-property-regex": "^ 7.14.5"."@babel/plugin-syntax-async-generators": "^ 7.8.4"."@babel/plugin-syntax-class-properties": "^ 7.12.13"."@babel/plugin-syntax-class-static-block": "^ 7.14.5"."@babel/plugin-syntax-dynamic-import": "^ 7.8.3"."@babel/plugin-syntax-export-namespace-from": "^ 7.8.3"."@babel/plugin-syntax-json-strings": "^ 7.8.3"."@babel/plugin-syntax-logical-assignment-operators": "^ 7.10.4"."@babel/plugin-syntax-nullish-coalescing-operator": "^ 7.8.3"."@babel/plugin-syntax-numeric-separator": "^ 7.10.4"."@babel/plugin-syntax-object-rest-spread": "^ 7.8.3"."@babel/plugin-syntax-optional-catch-binding": "^ 7.8.3"."@babel/plugin-syntax-optional-chaining": "^ 7.8.3"."@babel/plugin-syntax-private-property-in-object": "^ 7.14.5"."@babel/plugin-syntax-top-level-await": "^ 7.14.5"."@babel/plugin-transform-arrow-functions": "^ 7.14.5"."@babel/plugin-transform-async-to-generator": "^ 7.14.5"."@babel/plugin-transform-block-scoped-functions": "^ 7.14.5"."@babel/plugin-transform-block-scoping": "^ 7.15.3"."@babel/plugin-transform-classes": "^ 7.15.4"."@babel/plugin-transform-computed-properties": "^ 7.14.5"."@babel/plugin-transform-destructuring": "^ 7.14.7"."@babel/plugin-transform-dotall-regex": "^ 7.14.5"."@babel/plugin-transform-duplicate-keys": "^ 7.14.5"."@babel/plugin-transform-exponentiation-operator": "^ 7.14.5"."@babel/plugin-transform-for-of": "^ 7.15.4"."@babel/plugin-transform-function-name": "^ 7.14.5"."@babel/plugin-transform-literals": "^ 7.14.5"."@babel/plugin-transform-member-expression-literals": "^ 7.14.5"."@babel/plugin-transform-modules-amd": "^ 7.14.5"."@babel/plugin-transform-modules-commonjs": "^ 7.15.4"."@babel/plugin-transform-modules-systemjs": "^ 7.15.4"."@babel/plugin-transform-modules-umd": "^ 7.14.5"."@babel/plugin-transform-named-capturing-groups-regex": "^ 7.14.9"."@babel/plugin-transform-new-target": "^ 7.14.5"."@babel/plugin-transform-object-super": "^ 7.14.5"."@babel/plugin-transform-parameters": "^ 7.15.4"."@babel/plugin-transform-property-literals": "^ 7.14.5"."@babel/plugin-transform-regenerator": "^ 7.14.5"."@babel/plugin-transform-reserved-words": "^ 7.14.5"."@babel/plugin-transform-shorthand-properties": "^ 7.14.5"."@babel/plugin-transform-spread": "^ 7.15.8"."@babel/plugin-transform-sticky-regex": "^ 7.14.5"."@babel/plugin-transform-template-literals": "^ 7.14.5"."@babel/plugin-transform-typeof-symbol": "^ 7.14.5"."@babel/plugin-transform-unicode-escapes": "^ 7.14.5"."@babel/plugin-transform-unicode-regex": "^ 7.14.5"."@babel/preset-modules": "^ 0.1.4"."@babel/types": "^ 7.15.6"."babel-plugin-polyfill-corejs2": "^ 0.2.2"."babel-plugin-polyfill-corejs3": "^ 0.2.5"."babel-plugin-polyfill-regenerator": "^ 0.2.2"."core-js-compat": "^ 3.16.0"."semver": "^ 6.3.0"
  },
Copy the code

The proposal progress of each proposal Plugin is constantly updated, so keep updated preset-env, which also needs regular attention in business projects. In addition, if we use a new ES feature that is still in the proposal stage and preset-env is not integrated with the plugin, we have to configure plugins ourselves.

The default @babel/preset-env does not convert new apis, such as Iterator, Generator, Set, Maps, Proxy, Reflect, Symbol, Promise, etc. And some methods defined on global objects (such as Object.assign) do not transcode. Core-js and Regenerator-Runtime support is required.

Note that in @babel/preset-env 7.15.8 the plugin @babel/plugin-transform-regenerator is relied on for compiling async and generators. Because it relies on regenerator-transform->@babel/runtime->regenerator-runtime, regenerator-runtime provides compilation capability. Therefore, you do not need to install regenerator-Runtime.

Preset -env Configuration introduction

module.exports = {
  presets: [['@babel/env',
      {
        targets: {
          // Target runtime environment with a higher priority than Browserslist
          browsers: ['> 1%'.'last 2 versions'.'not dead'],},debug: true.// Console at compile time
        modules: false.// The value can be AMD, umd, systemjs, Commonjs and false. If false, it can be used for webpack tree shaking
        useBuiltIns: 'usage'.// Usage - Entry on demand - entry on demand (core-js needs to be introduced manually in code) false- non-entry (defaults), that is, turn off polyfill
        corejs: 3./ / 2 - corejs @ 2 (defaults), a 3 - corejs @ 3},]],};Copy the code

You need to manually install the dependencies corejs@3(dependencies), which is configured as the default configuration. You need to pay attention to the configuration of different useBuiltIns.

entry

If useBuiltIns is set to Entry, you need to manually introduce the Polyfill package in your code. Example code:

import 'core-js'; // Manually import
import 'regenerator-runtime/runtime'; // Manually import

const c = [5.6.7].includes(2);
const d = async() = > {const e = await a;
  console.log(e);
};
Copy the code

RegeneratorRuntime/Runtime is introduced to add a polyfill for regeneratorRuntime. Otherwise, regeneratorRuntime is not defined.

The result of webpack is 18000 rows. If you change the targets configuration:

targets: 'last 1 Chrome versions'.Copy the code

The repackage contains over 6500 lines, indicating that in entry mode, the import of core-JS will be replaced with modules reference of the lowest level of core-js according to the targets configuration, and all of them will be packaged.

  • Advantages: All polyfills are brought in, so you don’t have to worry about polyfills for a particular feature, just write code.

  • Disadvantages: The generated code package is too large and many features are not needed, which inevitably affects front-end performance. It is possible to refer to a separate section of core-js in your code:

    import 'core-js/es/promise';
    import 'core-js/es/array';
    Copy the code

    This can reduce some useless code, but I am very familiar with FE and ES characteristics, and it is still difficult to operate.

usage

Usage automatically introduces the corresponding polyfill based on the ES feature +target configuration used in each file. If the targets minimum environment does not support an ES feature, the corresponding Core-JS module of the ES feature will be injected.

Example code:

index.js:

import 'test.js';
const c = [5.6.7].includes(2);
const d = async() = > {const e = await a;
  console.log(e);
};
Copy the code

test.js:

const f = async() = > {const g = await a;
  console.log(g);
};
Copy the code

Webpack contains over 3700 lines of code, listing the index.js and test.js modules:

// Omit some code
/ * * * / "./index.js":
/ *! * * * * * * * * * * * * * * * * * *! * \! *** ./index.js ***! \ * * * * * * * * * * * * * * * * * * /
/ * * * / ((__unused_webpack_module, __webpack_exports__, __webpack_require__) = > {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var regenerator_runtime_runtime_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/ *! regenerator-runtime/runtime.js */ "./node_modules/regenerator-runtime/runtime.js");
/* harmony import */ var regenerator_runtime_runtime_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(regenerator_runtime_runtime_js__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var core_js_modules_es_array_includes_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/ *! core-js/modules/es.array.includes.js */ "./node_modules/core-js/modules/es.array.includes.js");
/* harmony import */ var core_js_modules_es_array_includes_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_array_includes_js__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var core_js_modules_es_object_to_string_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/ *! core-js/modules/es.object.to-string.js */ "./node_modules/core-js/modules/es.object.to-string.js");
/* harmony import */ var core_js_modules_es_object_to_string_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_object_to_string_js__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var core_js_modules_es_promise_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/ *! core-js/modules/es.promise.js */ "./node_modules/core-js/modules/es.promise.js");
/* harmony import */ var core_js_modules_es_promise_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_promise_js__WEBPACK_IMPORTED_MODULE_3__);
/* harmony import */ var _test_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/ *! ./test.js */ "./test.js");


function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); }}function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }





var c = [5.6.7].includes(2);

var d = /*#__PURE__*/function () {
  var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
    var e;
    return regeneratorRuntime.wrap(function _callee$(_context) {
      while (1) {
        switch (_context.prev = _context.next) {
          case 0:
            _context.next = 2;
            return a;

          case 2:
            e = _context.sent;
            console.log(e);

          case 4:
          case "end":
            return _context.stop();
        }
      }
    }, _callee);
  }));

  return function d() {
    return _ref.apply(this.arguments); }; } ();/ * * * / }),

/ * * * / "./test.js":
/ *! * * * * * * * * * * * * * * * * *! * \! *** ./test.js ***! \ * * * * * * * * * * * * * * * * * /
/ * * * / ((__unused_webpack_module, __webpack_exports__, __webpack_require__) = > {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var core_js_modules_es_object_to_string_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/ *! core-js/modules/es.object.to-string.js */ "./node_modules/core-js/modules/es.object.to-string.js");
/* harmony import */ var core_js_modules_es_object_to_string_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_object_to_string_js__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var core_js_modules_es_promise_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/ *! core-js/modules/es.promise.js */ "./node_modules/core-js/modules/es.promise.js");
/* harmony import */ var core_js_modules_es_promise_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_promise_js__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var regenerator_runtime_runtime_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/ *! regenerator-runtime/runtime.js */ "./node_modules/regenerator-runtime/runtime.js");
/* harmony import */ var regenerator_runtime_runtime_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(regenerator_runtime_runtime_js__WEBPACK_IMPORTED_MODULE_2__);




function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); }}function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }

var f = /*#__PURE__*/function () {
  var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
    var g;
    return regeneratorRuntime.wrap(function _callee$(_context) {
      while (1) {
        switch (_context.prev = _context.next) {
          case 0:
            _context.next = 2;
            return a;

          case 2:
            g = _context.sent;
            console.log(g);

          case 4:
          case "end":
            return _context.stop();
        }
      }
    }, _callee);
  }));

  return function f() {
    return _ref.apply(this.arguments); }; } ();/ * * * / }),
// Omit some code
Copy the code

As can be seen from the code:

  1. thewebpackOnce packaged, each module is based on the features it uses (as in this case)includes) introducing the correspondingmoduleGlobal variables are extended.
  2. asyncGeneratorStep,_asyncToGeneratorSuch ashelperFunctions are defined once in each module.

Also change the targets configuration:

targets: 'last 1 Chrome versions'.Copy the code

Webpack results:

(self['webpackChunkbabel_demo'] = self['webpackChunkbabel_demo'] || []).push([
  ['main'] and {/ * * * / './index.js':
      / *! * * * * * * * * * * * * * * * * * *! * \! *** ./index.js ***! \ * * * * * * * * * * * * * * * * * * /
      / * * * / () = > {
        const c = [5.6.7].includes(2);

        const d = async() = > {const e = await a;
          console.log(e);
        };

        / * * * /}},/ * * * * * * / (__webpack_require__) = > {
    // webpackRuntimeModules
    / * * * * * * / var __webpack_exec__ = (moduleId) = > __webpack_require__((__webpack_require__.s = moduleId));
    / * * * * * * / var __webpack_exports__ = __webpack_exec__('./index.js');
    / * * * * * * /},]);//# sourceMappingURL=main.js.map
Copy the code

There are only 24 lines in total, indicating that the feature of ES under this target is directly supported by the browser, without the need to add polyfill.

false

False is polyfill that does not introduce Corejs and only does syntactic conversions. Example code:

const c = [5.6.7].includes(2);
const f = [1.2.3];
const g = [...f, 5.6.7];
const d = async() = > {const e = await a;
  console.log(e);
};
Copy the code

Webpack results:

(self['webpackChunkbabel_demo'] = self['webpackChunkbabel_demo'] || []).push([
  ['main'] and {/ * * * / './index.js':
      / *! * * * * * * * * * * * * * * * * * *! * \! *** ./index.js ***! \ * * * * * * * * * * * * * * * * * * /
      / * * * / () = > {
        function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
          try {
            var info = gen[key](arg);
            var value = info.value;
          } catch (error) {
            reject(error);
            return;
          }
          if (info.done) {
            resolve(value);
          } else {
            Promise.resolve(value).then(_next, _throw); }}function _asyncToGenerator(fn) {
          return function () {
            var self = this,
              args = arguments;
            return new Promise(function (resolve, reject) {
              var gen = fn.apply(self, args);
              function _next(value) {
                asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'next', value);
              }
              function _throw(err) {
                asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'throw', err);
              }
              _next(undefined);
            });
          };
        }

        var c = [5.6.7].includes(2);
        var f = [1.2.3];
        var g = [].concat(f, [5.6.7]);

        var d = /*#__PURE__*/ (function () {
          var _ref = _asyncToGenerator(
            /*#__PURE__*/ regeneratorRuntime.mark(function _callee() {
              var e;
              return regeneratorRuntime.wrap(function _callee$(_context) {
                while (1) {
                  switch ((_context.prev = _context.next)) {
                    case 0:
                      _context.next = 2;
                      return a;

                    case 2:
                      e = _context.sent;
                      console.log(e);

                    case 4:
                    case 'end':
                      return_context.stop(); } } }, _callee); }));return function d() {
            return _ref.apply(this.arguments); }; }) ();/ * * * /}},/ * * * * * * / (__webpack_require__) = > {
    // webpackRuntimeModules
    / * * * * * * / var __webpack_exec__ = (moduleId) = > __webpack_require__((__webpack_require__.s = moduleId));
    / * * * * * * / var __webpack_exports__ = __webpack_exec__('./index.js');
    / * * * * * * /},]);Copy the code

Polyfill corresponding to includes has not been added.

@ Babel/runtime series

The @babel/ Runtime series consists of the following three types:

  1. @babel/runtime
  2. @babel/runtime-corejs2:@babel/runtime + core-js@2
  3. @babel/runtime-corejs3:@babel/runtime + core-js-pure@3

Babel /runtime supports runtime helpers and Regenerator-Runtime apis. Install to dependencies and use @babel/ plugin-transform-Runtime dependencies.

@babel/plugin-transform-runtime

The @babel/ plugin-transform-Runtime plugin uses internal modules of the @babel/ Runtime series to replace helpers, core-js and Regenerator-Runtime Related variables:

  1. rightBabelGenerated repeatedly in each module during compilationhelperMethod to reaggregate (all points to@babel/runtime/helpersthismoduleIn order to achieve the purpose of reducing packaging volume.
  2. Avoid global patch contamination by providing “sandbox” patches for each module.

A few examples

Prepare the following test files:

index.js:

import 'test.js';
const c = [5.6.7].includes(2);
const d = async() = > {const e = await a;
  console.log(e);
};
Copy the code

test.js:

const f = async() = > {const g = await a;
  console.log(g);
};
Copy the code

Patients with a

Add a plugin and turn off polyfill effects of PRESET -env:

babel.config.js:

module.exports = {
  presets: [['@babel/preset-env',
      {
        targets: {
          // Target runtime environment with a higher priority than Browserslist
          browsers: ['> 1%'.'last 2 versions'.'not dead'],},useBuiltIns: false.// corejs:3,
        debug: true,}]].plugins: [['@babel/plugin-transform-runtime',
      {
        corejs: 3.If false, install @babel/runtime; if 2, install @babel/runtime-corejs2; if 3, install @babel/runtime-corejs3},]],};Copy the code

By default, transform-Runtime does not enable the polyfill processing of core-js. In that case, @babel/ Runtime should be installed manually. In this case, @babel/runtime-corejs3 should be installed manually. Webpack results (with some code reserved) :

// Omit some code
/ * * * / "./index.js":
/ *! * * * * * * * * * * * * * * * * * *! * \! *** ./index.js ***! \ * * * * * * * * * * * * * * * * * * /
/ * * * / ((__unused_webpack_module, __webpack_exports__, __webpack_require__) = > {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _babel_runtime_corejs3_helpers_asyncToGenerator__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/ *! @babel/runtime-corejs3/helpers/asyncToGenerator */ "./node_modules/@babel/runtime-corejs3/helpers/esm/asyncToGenerator.js");
/* harmony import */ var _babel_runtime_corejs3_regenerator__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/ *! @babel/runtime-corejs3/regenerator */ "./node_modules/@babel/runtime-corejs3/regenerator/index.js");
/* harmony import */ var _babel_runtime_corejs3_regenerator__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_corejs3_regenerator__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _babel_runtime_corejs3_core_js_stable_instance_includes__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/ *! @babel/runtime-corejs3/core-js-stable/instance/includes */ "./node_modules/@babel/runtime-corejs3/core-js-stable/instance/includes.js");
/* harmony import */ var _babel_runtime_corejs3_core_js_stable_instance_includes__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_corejs3_core_js_stable_instance_includes__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _test_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/ *! ./test.js */ "./test.js");


var _context;





var c = _babel_runtime_corejs3_core_js_stable_instance_includes__WEBPACK_IMPORTED_MODULE_2___default()(_context = [5.6.7]).call(_context, 2);

var d = /*#__PURE__*/function () {
  var _ref = (0,_babel_runtime_corejs3_helpers_asyncToGenerator__WEBPACK_IMPORTED_MODULE_0__["default"]) (/*#__PURE__*/_babel_runtime_corejs3_regenerator__WEBPACK_IMPORTED_MODULE_1___default().mark(function _callee() {
    var e;
    return _babel_runtime_corejs3_regenerator__WEBPACK_IMPORTED_MODULE_1___default().wrap(function _callee$(_context2) {
      while (1) {
        switch (_context2.prev = _context2.next) {
          case 0:
            _context2.next = 2;
            return a;

          case 2:
            e = _context2.sent;
            console.log(e);

          case 4:
          case "end":
            return _context2.stop();
        }
      }
    }, _callee);
  }));

  return function d() {
    return _ref.apply(this.arguments); }; } ();/ * * * / }),

/ * * * / "./test.js":
/ *! * * * * * * * * * * * * * * * * *! * \! *** ./test.js ***! \ * * * * * * * * * * * * * * * * * /
/ * * * / ((__unused_webpack_module, __webpack_exports__, __webpack_require__) = > {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _babel_runtime_corejs3_helpers_asyncToGenerator__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/ *! @babel/runtime-corejs3/helpers/asyncToGenerator */ "./node_modules/@babel/runtime-corejs3/helpers/esm/asyncToGenerator.js");
/* harmony import */ var _babel_runtime_corejs3_regenerator__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/ *! @babel/runtime-corejs3/regenerator */ "./node_modules/@babel/runtime-corejs3/regenerator/index.js");
/* harmony import */ var _babel_runtime_corejs3_regenerator__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_corejs3_regenerator__WEBPACK_IMPORTED_MODULE_1__);



var f = /*#__PURE__*/function () {
  var _ref = (0,_babel_runtime_corejs3_helpers_asyncToGenerator__WEBPACK_IMPORTED_MODULE_0__["default"]) (/*#__PURE__*/_babel_runtime_corejs3_regenerator__WEBPACK_IMPORTED_MODULE_1___default().mark(function _callee() {
    var g;
    return _babel_runtime_corejs3_regenerator__WEBPACK_IMPORTED_MODULE_1___default().wrap(function _callee$(_context) {
      while (1) {
        switch (_context.prev = _context.next) {
          case 0:
            _context.next = 2;
            return a;

          case 2:
            g = _context.sent;
            console.log(g);

          case 4:
          case "end":
            return _context.stop();
        }
      }
    }, _callee);
  }));

  return function f() {
    return _ref.apply(this.arguments); }; } ();/ * * * / }),
// Omit some code
Copy the code

As can be seen from the code:

  1. repeatedhelperFunctions are converted to common, separate dependencies (./node_modules/@babel/runtime-corejs3/helpers/esm/asyncToGenerator.js) introduction, not repeated definition;
  2. Create a sandbox environment that can convert the global variables corresponding to these features into pairscore-jsregenerator-runtimeReferences to versions of non-global variables (e.gincludesIs converted).

Example 2

Targets: targets: ‘last 1 Chrome versions’, otherwise unchanged, again webpack the result (keep some code) :

// Omit some code
/ * * * / "./index.js":
/ *! * * * * * * * * * * * * * * * * * *! * \! *** ./index.js ***! \ * * * * * * * * * * * * * * * * * * /
/ * * * / ((__unused_webpack_module, __webpack_exports__, __webpack_require__) = > {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _babel_runtime_corejs3_core_js_stable_instance_includes__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/ *! @babel/runtime-corejs3/core-js-stable/instance/includes */ "./node_modules/@babel/runtime-corejs3/core-js-stable/instance/includes.js");
/* harmony import */ var _babel_runtime_corejs3_core_js_stable_instance_includes__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_corejs3_core_js_stable_instance_includes__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _test_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/ *! ./test.js */ "./test.js");
/* harmony import */ var _test_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_test_js__WEBPACK_IMPORTED_MODULE_1__);
var _context;




const c = _babel_runtime_corejs3_core_js_stable_instance_includes__WEBPACK_IMPORTED_MODULE_0___default()(_context = [5.6.7]).call(_context, 2);

const d = async() = > {const e = await a;
  console.log(e);
};

/ * * * / }),

/ * * * / "./test.js":
/ *! * * * * * * * * * * * * * * * * *! * \! *** ./test.js ***! \ * * * * * * * * * * * * * * * * * /
/ * * * / (() = > {

const f = async() = > {const g = await a;
  console.log(g);
};

/ * * * / }),
// Omit some code
Copy the code

As can be seen from the code:

Syntax conversions are reduced in higher versions of code by preset-env target configuration, but corejs’ polyfill is not reduced. The reason is that the Transform-Runtime polyfill does not judge the target environment and replaces it whenever it recognizes the new ES feature in the code.

Example 3

Enable polyfill for preset-env and Transform-Runtime simultaneously:

babel.config.js:

module.exports = {
  presets: [['@babel/preset-env',
      {
        targets: {
          browsers: ['> 1%'.'last 2 versions'.'not dead'],},useBuiltIns: 'usage'.corejs: 3.debug: true,}]].plugins: [['@babel/plugin-transform-runtime',
      {
        corejs: 3,},],],};Copy the code

index.js:

Promise.resolve().finally();
Copy the code

Webpack results (with some code reserved) :

// Omit some code
/ * * * / "./index.js":
/ *! * * * * * * * * * * * * * * * * * *! * \! *** ./index.js ***! \ * * * * * * * * * * * * * * * * * * /
/ * * * / ((__unused_webpack_module, __webpack_exports__, __webpack_require__) = > {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _babel_runtime_corejs3_core_js_stable_promise__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/ *! @babel/runtime-corejs3/core-js-stable/promise */ "./node_modules/@babel/runtime-corejs3/core-js-stable/promise.js");
/* harmony import */ var _babel_runtime_corejs3_core_js_stable_promise__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_corejs3_core_js_stable_promise__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var core_js_modules_es_object_to_string_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/ *! core-js/modules/es.object.to-string.js */ "./node_modules/core-js/modules/es.object.to-string.js");
/* harmony import */ var core_js_modules_es_object_to_string_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_object_to_string_js__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var core_js_modules_es_promise_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/ *! core-js/modules/es.promise.js */ "./node_modules/core-js/modules/es.promise.js");
/* harmony import */ var core_js_modules_es_promise_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_promise_js__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var core_js_modules_es_promise_finally_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/ *! core-js/modules/es.promise.finally.js */ "./node_modules/core-js/modules/es.promise.finally.js");
/* harmony import */ var core_js_modules_es_promise_finally_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_promise_finally_js__WEBPACK_IMPORTED_MODULE_3__);





_babel_runtime_corejs3_core_js_stable_promise__WEBPACK_IMPORTED_MODULE_0___default().resolve().finally();

/ * * * / }),
// Omit some code
Copy the code

As can be seen from the code:

Polyfill of preset-env and polyfill of transform-Runtime coexist. So two polyfills cannot be enabled at the same time.

Conclusions can be drawn from the above 3 examples and the usage example:

  1. plugin-transform-runtimepreset-envTo provide thepolyfillThe scenarios are completely different, the former for development libraries and the latter for developmentapplication
  2. plugin-transform-runtimepreset-envpolyfillCannot be enabled simultaneously
  3. plugin-transform-runtimepolyfillDo not judge the target operating environment becausepluginTo perform thepresetbefore

babel 8

In future babel8, babel-polyfills will fix the above problem, support custom configuration of a polyfill provider as needed, and build what transform-Runtime does into @babel/preset-env, The Plugin can also use targets.

Babel7 best practices

Polyfill is used with @babel/preset-env

NPM install:

npm i @babel/core @babel/preset-env @babel/plugin-transform-runtime -D
npm i core-js@3
Copy the code

Babel. Config. Js configuration:

module.exports = {
  presets: [['@babel/env',
      {
        targets: {
          browsers: ['> 1%'.'last 2 versions'.'not dead'],},useBuiltIns: 'usage'.corejs: 3,}]].plugins: [['@babel/plugin-transform-runtime',
      {
        corejs: false.regenerator: false,},],],};Copy the code

This solution will pollute the global within the module, but will reduce the polyfill to some extent according to target, thus reducing the volume to fit the business project.

Polyfill with @babel/ plugin-transform-Runtime

NPM install:

npm i @babel/core @babel/preset-env @babel/plugin-transform-runtime -D
npm i @babel/runtime-corejs3
Copy the code

Babel. Config. Js configuration:

module.exports = {
  presets: [['@babel/env',
      {
        targets: {
          browsers: ['> 1%'.'last 2 versions'.'not dead'],},useBuiltIns: false,}]].plugins: [['@babel/plugin-transform-runtime',
      {
        corejs: 3,},],],};Copy the code

This scheme does not pollute the whole world, but the Transform-Runtime does not take advantage of the target, so introducing full polyfill increases the volume suitable for the development library.

reference

  • babel
  • peerdependencies
  • npm 7 is now generally available
  • TC39
  • babel-polyfills
  • ecma-standards
  • core-js@3, babel and a look into the future