Abstract: For beginners, the use of Babel may have been confused, for many parameters configuration and differences are also a little understanding. This article will give you some simple examples of using babel-Runtime and Babel-Polyfill to help you understand the usage scenarios of both.

preface

Babel is a general-purpose JS compiler that allows you to compile JS code from the latest standards down to a general-purpose version of Node that is compatible with all browsers. You can tell Babel how to translate code by installing presets or plugins, for example: @babel/preset-env (preset syntax), @babel/preset-react (preset).

@babel/preset-env

introduce

Preset -env is a collection of ES syntax plug-ins, and is officially no longer recommended for a package like preset-201x, which can be configured with automatic compatibility code, including the automatic introduction of polyfill gaskets to handle new apis (e.g. Promise,Generator,Symbol, etc.) and instance methods (e.g. Array.prototype.includes, etc.).

use

  1. Create the. Babelrc configuration file in the root directory

     {
         "presets": [["@babel/preset-env", {
                 "targets": {},
                 "useBuiltIns": false."corejs": false}}]]Copy the code
    • Targets: Generates context-appropriate code for the project specified. If not configured, Babel will escape all ES6+ for environment adaptation, which is not recommended.
    • UseBuiltIns: This option is used in conjunction with @babel/polyfillBabel > 7.4.0, this library is no longer officially recommended, please selectcore-jsFill in the number 2 or 3 in the Corejs option depending on installing the core-JS version.

  2. Install @babel/preset-env and core-js

    The source code

    const test = (a)= > {
       `es8`.padStart(2)}Copy the code

    Translation results

    // useBuiltIns: false
    
    "use strict";
    
    var test = function test() {
       'es8'.padStart(2);
    };
    Copy the code
    // useBuiltIns: "usage" 
    // corejs: 3
    
    "use strict";
    
    require("core-js/modules/es.string.pad-start");
    
    var test = function test() {
       'es8'.padStart(2);
    };
    Copy the code

    You can see that when using useBuiltIns: false, Babel only converts the arrow function, using useBuiltIns: Usage, Babel dynamically introduces core-js/modules/es.string.pad-start as a global object.

Note: ES+ includes not only new syntax (arrow functions, classes), but also instances of extensions (array.prototype.includes, etc.) and many built-in functions (Promise, Symbol, etc.). However, preset-env is useless for handling these application scenarios without introducing polyfill. To solve this problem, we usually have two methods: to use Polyfill or Babel-Runtime for feature filling. We will illustrate the advantages and disadvantages of both and their application scenarios.

@babel/polyfill

I’ve mentioned a few simple examples of useBuiltIns using polyfill, so let’s take a look at the use of polyfill with a few more examples. Before Babel > 7.4.0, we used to install babel-Polyfill or @babel/polyfill to handle instance methods and new built-in functions added to ES+. After 7.4.0, when we chose @babel/ Polyfill, You will receive the following warning:

Warning @babel/[email protected]: � As of Babel 7.4.0, this package has been deprecatedin favor of directly
including core-js/stable (to polyfill ECMAScript
features) and regenerator-runtime/runtime
(needed to use transpiled generator functions):

  > import "core-js/stable";
  > import "regenerator-runtime/runtime";
Copy the code

Well (▔,▔)ㄏ. What does that mean? Polyfill is itself a stable version of core-js and regenerator-Runtime. Import @babel/polyfill is equivalent to:

import 'core-js/stable';
import 'regenerator-runtime/runtime';
Copy the code

So in the case of Babel >= 7.4.0, we need to install core-js instead of babel-polyfill, and regenerator-Runtime will be installed automatically when we install @babel/ Runtime, so there is no need to install it separately.

According to useBuiltIns, polyfill can be divided into three ways, namely entry, Usage and false.

The source code

/******* useBuiltIns: Add two lines of code to entry ********/ 
import 'core-js/stable';
import 'regenerator-runtime/runtime';
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /

const a = new Promise(a);let b = new Map(a)Copy the code

Translation results

// 1. useBuiltIns: entry
"use strict";

require("core-js/modules/es.symbol");

require("core-js/modules/es.symbol.description");

require("core-js/modules/es.symbol.async-iterator");

/ /... The 400 packages are omitted

require("regenerator-runtime/runtime");

var a = new Promise(a);var b = new Map(a);// 2. useBuiltIns: usage
"use strict";

require("core-js/modules/es.array.iterator");

require("core-js/modules/es.map");

require("core-js/modules/es.object.to-string");

require("core-js/modules/es.promise");

require("core-js/modules/es.string.iterator");

require("core-js/modules/web.dom-collections.iterator");

var a = new Promise(a);var b = new Map(a);// 3. useBuiltIns: false
"use strict";

var a = new Promise(a);var b = new Map(a);Copy the code

By comparing the three usage methods, we can find that false only does syntax conversion, Entry introduces all ES extension packages, and only Usage automatically detects the functions used in the code and automatically introduces modules (Note: Babel does not detect third party dependencies by default, so when using Usage, there may be a bug that the imported third party code does not inject the module.

So, if you don’t care about the size of the code package, you can choose entry. If you want the code to be as compact as possible, use Usage, which is officially recommended.

Thinking: By now, do you feel that the project using Polyfill can already write code 6 flying, ha ha ~? Suppose we need to release a library for others to use. We use polyfill to introduce the built-in function Promise. Unfortunately, someone else’s local code also encapsulates a function named Promise, finished, real Li Kui met fake Li Kui. So for peace, this is where our @babel/ Runtime comes in.

@babel/runtime

Babel-runtime is generally used in two scenarios:

  • Develop libraries/tools (generate code that doesn’t pollute global space and built-in object prototypes)
  • With the help of@babel/runtimeRemove redundant utility functions from the helper function in

Note: We should often see in other documentation and usage instructions that the Runtime does not support instance methods. Indeed, in previous use, neither Babel 7.0.0 to 7.4.0 nor Babel < 7.0.0 could do anything about it. They can only by configuring corejs (optional false | 2) to decide whether to use the Babel/runtime – corejs alternative core – js or polyfill (optional true | false) to determine whether the introduction of new global built-in function (new Built-in), however, the two are not fundamentally changed, corejs: 2 is actually equivalent to polyfill: true prior to version 7.0.0.

Important: The real change came after Babel 7.4.0. You can choose to introduce @babel/runtime-corejs3 and set corejs: 3 to help you implement support for instance methods.

Let’s look at some examples based on Babel 7.4.0:

Configuration items

{
    "presets": [["@babel/preset-env"]],"plugins": [["@babel/plugin-transform-runtime", {
            "corejs": false/ / is optionalfalse| 2 | 3}}]]Copy the code

Source code – Remove redundant utility functions

class Person {}
Copy the code

Translation results

// Remove the Runtime configuration in plugins
"use strict";

function _classCallCheck(instance, Constructor) { if(! (instanceinstanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); }}var Person = function Person() {
  _classCallCheck(this, Person);
};


// Introduce the plugin Runtime
"use strict";

var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");

var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/classCallCheck"));

var Person = function Person() {(0, _classCallCheck2["default"]) (this, Person);
};
Copy the code

As you can see, by introducing the Runtime, you can avoid compiling the same utility functions multiple times in multiple files.

Source code – Global contamination and instance method examples

const a = new Promise(a); [1.2.3].includes(1)
Copy the code

Translation results

// corejs: false
"use strict";

var a = new Promise(a); [1.2.3].includes(1);

// corejs: 2
"use strict";

var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");

var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));

var a = new _promise["default"] (); [1.2.3].includes(1);

// corejs: 3
"use strict";

var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");

var _includes = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/includes"));

var _promise = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/promise"));

var _context;

var a = new _promise["default"] (); (0, _includes["default"])(_context = [1.2.3]).call(_context, 1);

Copy the code

Corejs: false is the same as useBuiltIns: false when using @babel/polyfill. It only converts the ES syntax. Corejs: 2 is equivalent to polyfill: true in Babel 6, and both create a sandbox environment for the code and provide core-JS with pseudonyms, so as not to pollute the global space. Corejs: 3 is a perfect build on Corejs: 2 to solve the problem of not being able to instantiate methods without polluting the global space

conclusion

  1. Babel < 7.4.0
    • To develop the library, select @babel/ Runtime
    • Internal project, @babel/ Polyfill
  2. Babel > = 7.4.0Don’t say anything. Just do it@babel/runtimeYeah, because you have everything you need