preface

I think the desire of front-end developers is that users always use the latest devices and the latest standard browsers, so that front-end projects will have fewer problems, and THIS idea became more and more strong after I encountered a bug. This bug was a test that an Android 4.X phone could not open our H5 page. Later, according to the data reported by the monitoring system, his phone did not support an ES6 array method. I thought about it for a long time, but I did not understand why. As a result, some older browsers cannot parse some ES6 methods. Out of the blue, I met Babel because of a bug.

Throw out problem

What does Babel do? What does it have to do with the polyfill I mentioned in the preface? How to configure it in the project? Let’s do it step by step.

I met the Babel

Simply put, Babel is a compiler that converts code written in ECMAScript 2015+ syntax into a backward-compatible JavaScript syntax so it can run in current and older browsers or other environments.

Let’s go to the Babel website to write an example. This is a new ES2020 feature (with chain judgment operators), and on the right is Babel compiled code.

We can see a series of configuration parameters on the left, how do we configure them in our project?

Configure the Babel

First of all, we can see that there are presets at the top of the box. They correspond to the following 4 packages. What does the presets contain?

  • @babel/preset-env
  • @babel/preset-flow
  • @babel/preset-react
  • @babel/preset-typescript

Here’s a quick word about @babel/preset-env.

@babel/preset-env

import('./a').then(() = > {
  console.log(123)})Copy the code

If we want the above code block to compile successfully, we will need a plug-in to convert the syntax of import(), and the arrow function may be incompatible with older browsers, so we will need a plug-in to convert. For this you may need to install @babel/plugin-syntax-dynamic-import and @babel/plugin-transform-arrow-functions respectively and configure them in babelrc.

{
    "plugins": ["@babel/plugin-syntax-dynamic-import"."@babel/plugin-transform-arrow-functions"]}Copy the code

If we have other ES6+ syntax code in the project, it means that our plug-ins are growing. Fortunately, Babel has considered this issue and comes out with a preset package @babel/preset-env.

The main purpose of @babel/preset-env is to transcode and load polyfills for features we used and are missing in the target browser. Without any configuration, the plug-ins included in @babel/preset-env will support all the latest JS features (ES6+, preset). Not including stages), and convert it to ES5 code.

It is recommended that @babel/preset-env be used together with Browserslist, browserslist indicates the compatible browser that our project needs, and if our project does not need to be compatible with all browser versions, it is best to specify the lowest version to be compatible. This ensures that our code compiles as little as possible.

Browserslist configuration

Project configuration

What does Babel have to do with Babel-Polyfill? Babel is generally used to solve syntactic problems by converting ES6+ syntax to ES5 syntax, while Babel-polyfill is used to handle API-level translation, such as include and map methods for arrays.

babel-polyfill

Babel-polyfill is a library that includes core-js and regenerator-Runtime /runtime. It is easy to use and can be imported directly into the entry file of our project after installation. In this case, the entire babel-polyfill package is packaged. There are cases where I might only need one method, but I package all the files.

Compile the front:

import 'babel-polyfill';

new Promise((resolve) = > {
  console.log(123123)
  resolve()
})
Copy the code

The compiled:

"use strict";

require("babel-polyfill");

new Promise(function (resolve) {
  console.log(123123);
  resolve();
});
Copy the code

Can methods be loaded on demand?

Since Babel is now v7, we can only use core-js@3, which is recommended by the official website, instead of core-js@2(this version will not be updated), and core-js@3 for the project. To do this we install the following dependencies:

npm i @babel/cli @babel/core @babel/preset-env -D
Copy the code
npm install core-js@3 -S
Copy the code

Babelrc configuration:

{
  "presets": [["@babel/preset-env",
      {   
        "useBuiltIns": "usage"."corejs": 3}}]]Copy the code

UseBuiltIns set to Usage means that Babel will introduce the required polyfills based on the missing functionality of the browser environment.

Modified configuration compilation result:

"use strict";

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

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

// import 'babel-polyfill';

new Promise(function (resolve) {
  console.log(123123);
  resolve();
});
Copy the code

We have now solved the problem of loading on demand.

In fact, babel-Polyfill also has a problem. It will pollute global variables and make changes to the prototype chain of many classes. The impact of babel-Polyfill on normal development business may not be much, but if we develop a library for other developers to use, the situation may become uncontrollable.

In addition to babel-Polyfill, plugins @babel/ plugin-transform-Runtime also help with the API layer.

@babel/plugin-transform-runtime

The plugin @babel/plugin-transform-runtime actually relies on babel-Runtime.

  • When we use ES6+ built-in classes(Promise,Symbols)Or static methods are automatically introducedbabel-runtime/core-js.
  • When we useasync/await, can be introducedbabel-runtime/regenerator.
  • It’s built into the codehelpersWhen used, remove the definition and insert a reference.

Our plugin @babel/ plugin-transform-Runtime automatically introduces polyfills for babel-Runtime.

. Babelrc configuration

{
  "presets": [["@babel/env"]],"plugins": [["@babel/plugin-transform-runtime", {
        "corejs": 3}}]]Copy the code

Compile the front:

async function a() {
  await console.log(123123)}Copy the code

The compiled:

"use strict";

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

var _regenerator = _interopRequireDefault(require("@babel/runtime-corejs3/regenerator"));

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

function a() {
  return _a.apply(this.arguments);
} 

function _a() {
  _a = (0, _asyncToGenerator2["default"]) (/*#__PURE__*/_regenerator["default"].mark(function _callee() {
    return _regenerator["default"].wrap(function _callee$(_context) {
      while (1) {
        switch (_context.prev = _context.next) {
          case 0:
            _context.next = 2;
            return console.log(123123);

          case 2:
          case "end":
            return _context.stop();
        }
      }
    }, _callee);
  }));
  return _a.apply(this.arguments);
}
Copy the code

The _asyncToGenerator2 method is actually a reference to the asyncToGenerator method. Before we introduced a package directly, if there are too many files, the number of such introductions will directly cause our code to compile too large. The way @babel/ plugin-transform-Runtime is referenced means that other files can be compiled by reference instead of being declared repeatedly.

Advantages of @babel/ plugin-transform-Runtime compared to Babel-polyfill:

  • Combined configurationcore-js3Implement on-demand loading to reduce the size of the package
  • Does not pollute global variables
  • Reuse of auxiliary functions to solve the code redundancy when translating syntax layer

Refer to the link

A (long) breath to understand Babel use Babel still need to polyfill?? How do you use Babel Polyfill?