What is the Babel

Babel is a JavaScript compiler. Specifically, Babel is a tool for converting code written in ECMAScript 2015+ syntax into backward compatible JavaScript syntax. So that it can run in current or older browsers or other environments.





As shown in the figure, let’s review the overall process of V8 js code execution. A section of JS code is resolved into several tokens through lexical analysis, and then an AST number is generated through grammatical analysis, and then context such as scope and domain is resolved through semantic analysis. Eventually generate the code in the middle of the form (intermediate code may be participle form and context object shape), add to the main thread, load related to the global scope, context, such as environmental elements for code execution, in the process of execution can also optimize the code, such as JIT, delayed parsing, hidden classes, such as inline cache technology.



However, if the V8 parser version is too low to support new syntax such as class parsing, an error will be reported during the parsing phase indicating that the parser does not know how to process the syntax. Therefore, we need to convert the high-level syntax to the low-level syntax in advance so that the V8 parser can identify it easily. For example, you can turn a class into a simulation based on function prototypes. So Babel is a tool for converting the JavaScript language’s high-level syntax into low-level syntax. This transformation process is completed during the development of the packaged release code phase, and the code running in the user’s browser is the converted low-level code.

Note: Babel is a tool for converting advanced syntax into low-level syntax. This process is done before release, and V8 parsing runs the transformed code.



How does Babel work

Babel is a tool to convert high-level code into low-level code, input high-level code text, output low-level code text.



As shown, the input is JSX code that JSX V8 cannot parse, and the output is a node created using the createElement function that can be parsed by V8. At its core, Babel provides a framework for transformations. What syntax needs to be transformed and how it needs to be transformed depends on the plugin.



The general execution process of Babel is also the process of constructing AST tree through lexical analysis and syntax analysis, modifying AST tree and converting it into string output. Babel abstracts this process into three processes: Parse, traverse, and generate. For each process, there are exposed hook functions that are provided by plugins, which implement the hook functions.


Note: Babel provides abstraction tools for high-level code to low-level code, with parse, traverse and Generator stages. It also provides specific plugins for handling specific grammars, in which hook functions are implemented to accommodate various grammars.


parse

The parse stage is the most basic stage. The main job is to convert the input source code string through lexical analysis and parsing into an AST intermediate code representation structure that can be processed later. AST followsestreeSpecification and can also be usedastesplorerThe site clearly shows the results of source code parsing into ast. For example, parsing JSX code:





After parsing the code (< div >text</ div >), the AST is represented as shown in the figure below. A complete AST consists of many units. For example, JSXElement, JSXOpeningElement, JSXClosingElement, JSXIdentifier and JSXText units in the figure. Each unit has some common attributes and unique attributes. Common attributes include the type describing the type, the start and end positions of the description words in the file start and end to facilitate positioning with the subsequent code sourcemap generated code. Cells with unique attributes are different, such as JSXElement with the openingElement tag, closingElement tag, and children node.



One of the more overlooked questions is how do lexical analysis identify JSX? JSX participles are indeed not explained in normal ECMAScript standard documentation. But Babel@babel/parserJSX syntax is declared in the parseMaybeAssign method. The source code is 3693 lines of the index file in the lib folder.





It can be seen from the code in Figure 1 that whether hasPlugin has JSX flag bits is judged. Figure 2 shows that hasPlugin is an instance method of BaseParser class. The main purpose is to maintain plugins that are used during the parse process (this.plugins are an array that holds some identifiers). In other words, the purpose of the parse phase is whether the (< div >text</ div >) syntax needs to be parsed into JSX or less than sign or error handling during lexical analysis. So we need to develop a plug-in and explain in the plug-in that we need to parse to recognize JSX, this part of the specific code is in@babel/plugin-syntax-jsxThe source code implemented in the package is as follows:



Opts is the parameter of the BaseParser class. ParserOpts is a BaseParser instance. Parseropts.plugins.push (‘ JSX ‘) then indicates that the JSX syntax needs to be recognized during parse. After the plugins are configured in the.babelrc file, the Parse phase reads the plugins’ manipulateOptions attribute. During parse, hasPlugins(‘ JSX ‘) are set to true. So treat the (< div >text</ div >) syntax as JSX instead of less than sign errors.

Note: The parse phase is the process of converting incoming and outgoing high-level syntax into an AST. In this process, the BaseParser object is created and the plugins attribute is initialized (execute the manipulateOptions hook function that introduces the pulateOptions hook function mounted from the plug-in). An AST consists of multiple units, each of which corresponds to a token, with common attributes start, end (related to sourcemap), and private attributes of their own characteristics.


traverse

Traverse stage is a depth-first traverse of the AST generated by the Parse stage. The traverse mode determines what the branch is based on the type type to traverse down. Such as:



When traversing the JSXElement element, the type value is “JSXElement”, so we know the following traversal and the openingElement, ClosingElement, children attributes, from this node to the depth traversal. Iterate through the OpeningElement unit, and similarly check that type is “JSXOpengingElement”, so the name field is a property to iterate through, so iterate through name, down until “div” is a string, not a cell location, Then backtrack to continue deep traversal of the closingElement and children attributes.



Special processing may be required during traversal to execute to specific units in order to convert the high-level AST into a low-level AST, so this requires the plug-in to mount the execution method in the response hook. For JSX processing is in@babel/plugin-transform-react-jsxPackage, as shown in the source code:



The returned object is a visitor object with attributes of type type for each element of the AST. During the traverse, If you go into a cell like JSXElement you do visitor enter for the JSXElement property, exit is called when you leave the cell, If only Enter is available, you can omit enter by JSXElement(){}.

Each plug-in callback hook has path as an input parameter. Path can be used to retrieve the AST unit using the Node field and replacewith to replace the unit with a partial AST. You can also quickly replace AST elements with @babel/type @babel/template.

Note: Traverse can traverse AST cells and then call visitor field to perform specific handler functions on specific cells (enter, exit) to handle replacement AST cells. In the process of writing plug-ins, you can use the @babel/type @babel/template package to write and process plug-in code quickly and conveniently.


generate

Generate is a module that converts the AST with traverse traversals to source code, except that it calls a different generate function for each cell based on type, as shown in the figure@babel/generatorThe code in the package is the process of generating a string for the JSXOpeningElement unit.





The Generator can configure whether or not it needs to output sourcemap, which is another important point of the Generator. For sourcemap, it is a kind of mapping between generation and source code after compilation. The advantages of Sourcemap are that first, source code can be easily and quickly located during development, and second, source code and corresponding Sourcemap can be deployed separately when online. Catching errors on the line makes it easy to locate the source code using Sourcemap. Specific can refer to the articlesourcemapLearn more about Sourcemap.

All you need to know here is that Sourcemap essentially maintains a mapping between the source line and line positions of the final output code. So we need the following information: number of source code lines, number of source code columns, number of object code lines, number of object code columns.

When the source code is parsed into the AST tree, each unit maintains the start, end, and LOC information of the token, which is the position and column of the source code corresponding to the token. Although the contents of the cell may be replaced after the transform processing, the location information is still old and will not be replaced. In the process of generate converting AST into object code, the previous position information, namely the number of source code lines and source code columns, can be obtained when the AST unit is traversed, and then the output position of the next output string, namely the number of target code lines and target code columns, can be known. This gives you the mapping, and after some compression algorithms, the Sourcemap is generated.

Note: The Generator outputs the TRANSFORMED AST as object code, forming the SourcemAP from the old and new locations in the process.

So far we’ve learned where Babel is at the overall engineering level, what Babel does, how Babel works, how Babel’s integrated packages work and how they relate upstream and downstream. Ultimately, however, Babel will need to be configured in a project using a variety of plug-ins to achieve a project-appropriate configuration. Next, we’ll take a closer look at Babel in terms of several conceptual aspects to focus on at configuration time.



plugin

The plugin based

From the Babel workflow described earlier, you can get an idea of what the plugin does. Babel abstracts high-level source code into low-level source code by parsing traverse generate several abstractions, and plugin is the implementation of specific syntax transformations. Here is an example of a plug-in:

const pluginUtils = require("@babel/helper-plugin-utils");

const plugin = api= > {
    return {
        name: "plugin-demo".manipulateOptions(opts, parserOpts) {
            parserOpts.plugins.push("jsx");
        },

        visitor: {
            JSXElement: {
                exit(path, file){}}}}; };exports.default = pluginUtils.declare(plugin);
Copy the code

The plugin returns an object processed by pluginUtils. More importantly, the function passed in returns a description object that implements the key hooks in Babel abstraction. Name indicates the unique identifier of the plug-in.

Babel first converts advanced source code into AST through parse lexical and syntax analysis. In the manipulateOptions hook, Babel states in advance that JSX style syntax needs to be recognized during parse. Traverse each element in the AST. The processing is done in the visitor object, where the key of the object is the type of the processing element. Passing in the path description of the element and executing the function corresponding to the key can pass the high-level source code to the low-level implementation. It then outputs a string through generate.

Advanced syntax support

Since plugins are the implementation of specific syntax conversions, there are a lot of plugins, and Babel classifies them according to the content of the conversions, starting with higher-level syntax conversions to lower-level syntax conversions.

There is a class of high-level syntax that can be implemented using lower-level syntax, such as the power operator. Higher-level syntax looks like this:

x = 10民运分子2;
Copy the code

The resulting low-level code processed by Babel’s power-supporting plugin is as follows:

x = Math.pow(10.2);
Copy the code

After the operator is recognized at parse, it is converted to math. pow at traverse. Plugin @babel/ plugin-transformation-exponentiation-operator package.

You will notice that this type of transformation does not introduce non-standard syntax, that is, there is no artificial helper function to implement it. This type of syntax transform is called syntax transform.

There is also a class of grammars that require a helper function to be written. The purpose is that low-level grammars do not support this implementation and can only be implemented by writing the basic function in low-level low-level grammars. For example, before class syntax conversion:

class Test {
  constructor(name) {
    this.name = name;
  }

  logger() {
    console.log("Hello".this.name); }}Copy the code

Function/prototype ();

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

    this.name = name;
  }

  Test.prototype.logger = function logger() {
    console.log("Hello".this.name);
  };

  returnTest; }) ();Copy the code

The ability to use helper functions such as _classCallCheck to achieve advanced syntax is called helper. For example, the new array feature has find Prototype, and we need to add polyfill to support find. Collectively referred to here as API Polyfill.

So the syntax Transform + API polyfill allows you to implement advanced syntax and advanced APIS.


Classification of language characteristics

1.ecma

Ecma language features are standard features that are already included in the ECMAScript standard document. All host environments must be compatible with the implementation, such as ES2015, ES2016, ES2017, etc.

2. proposal

Proposal language features refer to those features that have not yet entered the standard document, but have entered the proposal process. For grammatical features, there will be a process from the proposal to the standard through the following stages:

  • Stage 0 – Strawman: Just an idea, possibly implemented with the Babel Plugin.
  • Stage 1-proposal: A Proposal worth continuing with.
  • Stage 2 – Draft: Build specs.
  • Stage 3 – Candidate: Complete the spec and implement it in the browser.
  • Phase 4-FINISHED: Will be added to the next es20XX Spec.

3. other

Other prediction features are those that are not part of a standard or proposal but are used in code, such as JSX, typescript, Flow, etc. These also need to be identified and parsed at Babel compilation time, otherwise interpretation will fail.

Classification of the plugin

According to the parsing process and the classification of prediction features, Babel divides plugin into three types: syntax, Transform and proposal. If you have used Babel, you will find plugin-syntax-*, plugin-transform-*, plugin-proposal-* in the node_modules@babel folder of your project. The differences between these plugins are described below.

1. syntax

Syntax plugin is just an implementation of the pulateOptions hook function. The purpose is to enable Babel to support specific syntax during parsing. As described in the Parse chapter



JSX = JSX = JSX = JSX = JSX = JSX = JSX = JSX = JSX = JSX = JSX Of course configuring syntax can be separate from the visitor implementation used on specific traverse because syntax recognition can also be done without parsing into low-level syntax form. Maybe you’re running an environment that supports JSX syntax

2. transform

Transform Plugin is mostly the transformation implementation of high-level syntax, such as various ES20XX language features, typescript, JSX and other language features. In this plugin, the specific conversion action is implemented for the different AST units of the visitor object, so the premise is that the parse phase needs to recognize the parse syntax, So normally @babel/plugin-transform-** will refer to @babel/plugin-syntax-**.

3. proposal

AST transformation plugins that do not include language standard features are called proposal Plugin, which is also a Transform Plugin, but is called as such to distinguish it from standard features. To complete the support for proposal features, sometimes the syntaxPlugin and proposal Plugin are also needed, such as function bind (::). Operator) requires both @babel/plugin-syntax-function-bind and @babel/plugin-proposal-function-bind.

note: Plugin is the implementation of concrete syntax transformations in the Babel abstract process, Advanced syntax can be transformed into low-level syntax through syntax Transform + API polyfill. Plugin can be divided into three categories: syntax, transform and proposal according to language characteristics and Babel abstract process.

preset

Preset base

Since there are so many plugins, preset is formed by clustering some plugins together for convenience. According to the @babel/preset-react source, preset returns an object containing the plugins attribute. Organized plugins are located in plugins.





Babel evolution

babel6

In Babel6 version, there are many preset types according to the language features. For example, special preset-env such as ECMA supported preset -ES2015 is always compatible with the latest standard syntax. Non-standard preset features are supported, such as preset-stage-draft, and preset-react and preset-typescript are supported for other types of features.

But progressive use of Babel6 Preset reveals some problems:

  • How best to support incremental compilation in the target environment? For example, all standard presets after preset- ES2015 will be preset to low-level ES5 syntax, but the users may be the latest group of Chrome users who already support some ES2015 features, only some of the new features are not supported, but all the changes bring extra burden. I did a little bit of useless work. Therefore, incremental compilation is required based on the agent environment support that the user product faces.
  • Preset packages change very frequently and are not flexible enough. Babe6 has preset- ES2015 and preset- ES2016 for specific standards, for example, PRESET – ES2015, and preset-stage-draft and preset-stage-proposal for non-standard proposal versions. However, all package references need to be changed when the syntax changes from the draft stage to the proposal stage, which is very inflexible, and even the proposal syntax used in the development process is limited to a few high frequency ones, and the introduction of all preset brings about the maintenance cost of team collaboration.


babel7

Targets is used in Babel7 to set incremental compilation of the target environment by setting the version to compile to maintain inconsistent differentiation between different product agent environments. For packages that change a lot, introduce your own plugins based on usage.

Preset – env configuration (0)

The main configuration of @babel/preset-env consists of targets, useBuiltIns, and Corejs fields, as shown in the following figure. The configuration in the presets field of the Babel configuration file:



The targets field sets the target environment version, indicating the extent to which the latest standard syntax needs to be resolved to achieve incremental compilation. It has been introduced in plugin that compilation from a high-level language to a low-level language requires syntax + API polyfill, so corejs useBuiltIns limits how polyfill can be used. For example, whether to introduce helper/polyfill functions in full or incrementally in your code. Use the new version or the old version, etc. Targets and polyfill are introduced in detail below.

(1) targets

  • A targes value of false means es5 is compiled by default. Equivalent to the introduction of preset-env in Babel6, there is no incremental processing based on the target broker environment.
  • Targets indicates the target of the lowest version compatible with the proxy environment.
{
  "targets": {
    "chrome": "58"."ie": "11"}}Copy the code

The preceding configuration indicates that the compiled code requires the >= 58 support of Chrome and the >= 11 support of Internet Explorer. How do I know what syntax is supported by different versions of Chrome, for example, preset-envcompat-tableLibrary in which the syntax is maintained and supported in that environment, for example:



Class syntax is already supported on chrome49. So how to set targets in Chrome 58 class does not need to compile into a function prototype.

  • Targets value is BrowswesList query (browserslist query document), such as “last 1 version, > 1%”. This is shorthand for the previous proxy environment object. Perset-env translates query with @babel/compat-data.



(2) polyfill

Before introducing Polyfill, let’s talk about helper functions in the code. Helper functions fall into two categories: helper functions that have to be added to support the new syntax. For example, in order to support the class, you need to use _classCallCheck and other helper functions to simulate the implementation of the class in the function Prototype way. Another kind of polyfill is introduced from outside. For example, array’s fill from method.

For example, the SRC /index.js file looks like this:

class par {};class sub extends par {};new Array(5).fill('1'); Chrome 45 version support

Array.from([]); // Chrome 45 is not supported
Copy the code

1. UseBuiltIns to false

The original handling of polyfill configuration. Babelrc:

{
  "presets": [["@babel/preset-env", {
        "targets": { "chrome": 45 },
        "useBuiltIns": false // The default value is false and can be omitted.}]],"plugins": []}Copy the code

Babel SRC / -d dist/ Babel SRC / -d dist/

"use strict";

function _inherits(subClass, superClass) { if (typeofsuperClass ! = ="function"&& superClass ! = =null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true.configurable: true}});if (superClass) _setPrototypeOf(subClass, superClass); }

function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }

function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this.arguments); } return _possibleConstructorReturn(this, result); }; }

function _possibleConstructorReturn(self, call) { if (call && (typeof call === "object" || typeof call === "function")) { return call; } else if(call ! = =void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); }

function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }

function _isNativeReflectConstruct() { if (typeof Reflect= = ="undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy= = ="function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean[],function () {})); return true; } catch (e) { return false; }}function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }

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

;
var sub = /*#__PURE__*/function (_par) {
  _inherits(sub, _par);

  var _super = _createSuper(sub);

  function sub() {
    _classCallCheck(this, sub);

    return _super.apply(this.arguments);
  }

  return sub;
}(par);

;
new Array(5).fill('1');
Array.from([]);
Copy the code

You’ll notice that the first 17 lines of code are designed to support helper functions for the class syntax, and that neither fill nor from adds polyfill, which would be an error on Chrome 45.

Advantages: Targets intelligently parse syntax. Preset -env can be parsed based on the targets intelligence syntax. Disadvantages: No API polyfill processing. Only plugin of syntax type is added, that is to say, only compatibility processing is carried out in the transformation process of advanced syntax, that is to say, advanced syntax can be converted into low-level syntax through syntax transform + API polyfill. But here only the Syntax Transform action is done, and API polyfill is not handled.

2. UseBuiltIns for entry

Handle polyfill configuration. Babelrc:

{
  "presets": [["@babel/preset-env", {
        "targets": { "chrome": 45 },
        "useBuiltIns": "entry"."corejs": 3}]],"plugins": []}Copy the code

When useBuiltIns is configured as entry, you need to add the following headers to the SRC /index.js file and install core-js and regenerator-Runtime packages

import "core-js"; / / add
import "regenerator-runtime/runtime.js"; / / add

class par {};class sub extends par {};new Array(5).fill('1');

Array.from([]);
Copy the code

The command output is as follows:

"use strict";

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

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

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

require("core-js/modules/es.symbol.has-instance.js"); .require("regenerator-runtime/runtime.js");

function _inherits(subClass, superClass) { if (typeofsuperClass ! = ="function"&& superClass ! = =null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true.configurable: true}});if (superClass) _setPrototypeOf(subClass, superClass); }

function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return_setPrototypeOf(o, p); }...function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }

function _classCallCheck(instance, Constructor) { if(! (instanceinstanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); }}var par = function par() {
  _classCallCheck(this, par); }; ; . ;new Array(5).fill('1');
Array.from([]);
Copy the code

Advantages: It can solve the API polyfill problem. The resulting code is pretty straightforward: reference all modules under core-js/modules to the file, depending on the module type of the file. Disadvantages: manual code import package, full reference, wasted volume, helper function duplication. Tree Shaking is not done based on targets and the syntax used. Waste volume, this way is also the most primitive way. If you move multiple JS files, you will find that the Class Helper functions have one copy of each file.

3. UseBuiltIns for usage

Handle polyfill configuration. Babelrc:

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

Introduction of SRC /index.js file swap.

"use strict";

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

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

function _inherits(subClass, superClass) { if (typeofsuperClass ! = ="function"&& superClass ! = =null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true.configurable: true}});if(superClass) _setPrototypeOf(subClass, superClass); }...function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }

function _classCallCheck(instance, Constructor) { if(! (instanceinstanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); }}var par = function par() {
  _classCallCheck(this, par); }; ; . ;new Array(5).fill('1');
Array.from([]);
Copy the code

Advantages: Introduction on demand. Introduces the Core-JS polyfill of array from used in this file. The fill function for array is not added because targets is still in effect. Disadvantages: global pollution, helper function duplication. But to the core – js/modules/es. Array. From the js function back to found that the polyfill is directly in the original array add modified prototype. The same class helper function has one for each file.

4. The runtime patterns

The configuration of polyfill. Babelrc is as follows, and the @babel/runtime-corejs3 package is installed. SRC /index.js doesn’t need to import dependencies manually. Install @babel/ plugin-transform-Runtime to dynamically manage dependencies in files. If the helper parameter is true, it indicates that all helper functions should have external public helper functions, rather than one for each file.

{
  "presets": [["@babel/preset-env", {
        "targets": { "chrome": 45}}]],"plugins": [["@babel/plugin-transform-runtime",
      {
        "helper": true."corejs": 3  / / install @ Babel/runtime - corejs3}}]]Copy the code

The results are as follows:

"use strict";

var _Reflect$construct = require("@babel/runtime-corejs3/core-js-stable/reflect/construct");

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

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

var _context;

function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2.default)(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2.default)(this).constructor; result = _Reflect$construct(Super, arguments, NewTarget); } else { result = Super.apply(this.arguments); } return (0, _possibleConstructorReturn2.default)(this, result); }; }

function _isNativeReflectConstruct() { if (typeof Reflect= = ="undefined"| |! _Reflect$construct)return false; if (_Reflect$construct.sham) return false; if (typeof Proxy= = ="function") return true; try { Boolean.prototype.valueOf.call(_Reflect$construct(Boolean[],function () {})); return true; } catch (e) { return false; }}var par = function par() {(0, _classCallCheck2.default)(this, par); }; ; . ; (0, _fill.default)(_context = new Array(5)).call(_context, '1');
(0, _from.default)([]);
Copy the code

Advantages: Helper functions are not repeated, polyfill imports on demand, no global pollution. The hepler and Polyfill functions are imported from the runtime-corejs3 new core package. The code in this package does not pollute the global prototype, but is managed as a module. All are imported on demand, without the need to manually import functions into the code. Disadvantages: Causes targets to fail. In the previous examples, all array.fill functions are supported in Chrome 45 and there is no _fill.default modification because targets are in effect in preset-env, but why is this not used here? This depends on how Babel parses plugin & Preset sequences.

Babel will deal with Plugin first, then preset. Plugin for left to right processing, preset for right to left processing. So the transform-Runtime plugin is used to process the code first, because the transform-Runtime does not have the concept of targets. So you’ve parsed all the polyfills that can be parsed (just the API polyfill part, of course). By the time preset-env is processed, the incoming code is already processed, so targets are deactivated here. Thankfully, Babel8 has fixed this problem.

babel8

Faced with the problem of targets failure left by Babel7, Babel8 has started to solve it. Specifically at github.com/babel/babel… The document is so clear that you can look directly at the official document. The configuration is available at github.com/babel/babel… In the document.

Install the babel-plugin-polyfill-corejs3 package.

{
  "presets": [["@babel/preset-env", {
        "targets": { "chrome": 45}}]],"plugins": [
    "@babel/plugin-transform-runtime"["babel-plugin-polyfill-corejs3",
      {
        "targets": { "chrome": 45 },
        "method": "usage-pure"}}]]Copy the code

The resulting code:

"use strict";

var _Reflect$construct = require("core-js-pure/stable/reflect/construct.js"); .function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2.default)(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2.default)(this).constructor; result = _Reflect$construct(Super, arguments, NewTarget); } else { result = Super.apply(this.arguments); } return (0, _possibleConstructorReturn2.default)(this, result); }; }

function _isNativeReflectConstruct() { if (typeof Reflect= = ="undefined"| |! _Reflect$construct)return false; if (_Reflect$construct.sham) return false; if (typeof Proxy= = ="function") return true; try { Boolean.prototype.valueOf.call(_Reflect$construct(Boolean[],function () {})); return true; } catch (e) { return false; }}var par = function par() {(0, _classCallCheck2.default)(this, par); }; ; . ;new Array(5).fill('1');
(0, _from.default)([]);
Copy the code

The resulting code is targets compliant, helper non-repetitive, polyfill on demand volume-friendly, auto-import dependent, and non-polluting globally coded.