Sit down and talk about babel

What is babel

Official introduction

Babel is a JavaScript compiler

Babel is a tool chain, which is mainly used to convert code written in ECMAScript 2015 + syntax into backward compatible JavaScript syntax, so that it can run in current and old versions of browsers or other environments. Here's what Babel can do for you:

  • grammatical transformation

  • Add missing features in the target environment through Polyfill (through third-party Polyfill modules, such as core-js , implementation)

  • Source code conversion (codemods)

  • More resources! (please review these video (for inspiration)

// Babel input: ES2015 arrow function
[1, 2, 3].map((n) => n + 1);
​
// Babel output: equivalent functions implemented by ES5 syntax
[1, 2, 3].map(function(n) {
  return n + 1;
});

Why Compiler?

As we all know, JavaScript is an interpretive language. Unlike Java, it does not byte code through the mixed mode of code compiler and interpreter, so JavaScript itself runs while interpreting in the browser. So why do you need a babel syntax Compiler?

babel is a static syntax compiler. It does not work when the program runs, but executes the syntax before the program runs. The main reason why babel is needed is that the customization and implementation process of ECMA specification is cumbersome and long. Before the implementation of a specification, mainstream browsers cannot recognize and run new code specifications through the built-in JavaScript engine. babel can compile the new code specifications in babel in advance and output the generated results as the specified es version, This allows the browser to run JavaScript code developed through the ES specification that is not yet supported.

babel has gone through a long development process and continues to provide corresponding implementation for the new ECMA specification, and tries its best to support the output range of the new specification for earlier browser versions, so that developers do not need to pay attention to the problem of JavaScript running environment. Up to now, babel has been updated to the 7th major version, and has been completely separated from the versions before 6 since version 7.

About ECMA specification

ECMA is a standardization organization of JavaScript syntax. It will launch suggestions and proposals for upgrading JavaScript language every year. Mainstream browser manufacturers and JavaScript engine providers around the world will implement the ECMA specification to ensure that the running performance and syntax of JavaScript are always consistent no matter running in any browser.

Of course, the above description is only an ideal state. Since every syntax proposal for JavaScript in ECMA needs a complex process to be finalized, submission, review, demonstration, meeting and discussion are required in this process. Therefore, it may have been a long time before a new proposal is finalized, which means that after the proposal is finalized and enters the hands of browser manufacturers, it still needs to wait for a long implementation process of browser manufacturers. In this case, the proposal proposed in 2019 may not actually enter the browser in 2021.

In view of this situation, browser manufacturers have also made their own efforts, that is, when a proposal is almost certain to pass, or the proposal is speculated to pass in the future, some browser manufacturers will implement it in the form of test functions in the browser in advance. Although this is a good thing, combined with the above description, programmers will become very headache when the task falls into the hands of programmers in actual work.

During the implementation of different proposals, some browsers may have implemented them, and some may not. Some ECMA standards have been implemented by mainstream browsers after being proposed for some time, but these new syntax rules are only applicable to mainstream browsers of newer versions. Therefore, programmers need to ensure that they are compatible with browsers of earlier versions and more comprehensive browser manufacturers as much as possible in the development scenario, You can only choose to continue to use ECMA's early basic specifications for JavaScript programs.

In view of this situation, if the new ECMA specification is better in time, it will be like a chicken rib in actual production. So babel came into being. The core purpose of babel is to fully implement ECMA specification and implement the early version of JavaScript for the new ECMA specification, so as to ensure that programmers do not need to consider whether the browser version or specification is supported by the browser after integrating babel in the project. Just write the code according to the new specification, and hand over the implementation of the specification to babel. babel processes the code as a whole before the program runs, outputs the latest ECMA specification through the syntax before ECMAScript5, or outputs the corresponding code standard for the browser version specified by the programmer. babel only participates in program construction and compatibility processing, and will not invade the code written by programmers.

However, in some scenarios, babel needs to use polyfill technology or core JS technology to supplement some objects of the browser. For example, after the introduction of ES6 + specification, the JavaScript array contains traversal methods in the form of functions such as forEach, map and filler. The browser also provides Promise objects for asynchronous tasks. Based on these new APIs and global objects, if you want to directly use the new syntax to develop support for browsers before ES6, You must compensate for missing APIs and global objects in these legacy browsers. This is also one of babel's workflow.

The ECMAScript specification has evolved over the years, including the following:

  1. ES6 (2015): added class, ES Module, arrow function, parameter default value, template string, deconstruction assignment, expansion operator, object attribute abbreviation, Promise and let const declarators.

  2. ES7 (2016): Array.prototype.includes() and exponential operator.

  3. ES8 (2017): async/await, Object.values(), Object.entries(), String padding, comma allowed at the end of function parameter list, Object.getOwnPropertyDescriptors(), SharedArrayBuffer object and Atomics object

  4. ES9 (2018): asynchronous iteration, Promise.finally(), Rest/Spread attribute, regular expression named capture group, regular expression reverse assertion and regular expression dotAll mode

  5. ES10 (2019): Array.flat() and Array.flatMap(), String.trimStart() and String.trimEnd(), String.prototype.matchAll, Symbol.prototype.description, Object.fromEntries() and optional Catch

  6. ES11 (2020): null coalescing operator, Optional chaining, Promise.allSettled, import(), new basic data types BigInt and globalThis

  7. ES12 (2021): replaceAll, Promise.any, WeakRefs, logical operators and assignment expressions and number separators

It has been six years since the ES6 specification was put forward to ES12, so babel is essential if the iterative browser versions in these six years want to run applications programmed with complete JavaScript from ES6 to ES12.

babel's programming method

Using babel in browser

There are many ways to use babel in programming. The simplest way is to use the browser provided by babel in the browser and write new code in the script tag with type text/babel. However, this method is only applicable to the learning stage. If you directly use babel to run JavaScript in the browser, it is completely unsuitable for the production environment. Because it consumes a lot of resources when executing polyfill, it is recommended to process the code through Webpack and babel Library in the local development environment.

Using babel in Webpack

How babel is used in Webpack Webpack from introduction to mastery 01,Webpack from introduction to mastery 02 as well as Webpack from introduction to mastery 03 The three articles are introduced and explained in detail. You can learn about Webpack in combination with Webpack articles.

Using babel in NodeJS

Today's article takes the use of babel in Node as an independent introduction to babel. The above two methods are not the main contents of today's introduction.

1. Preparation

  1. Create a new empty folder in the editor, initialize the project through npm, and use the npm init -y command to create package.json

    zhangyunpeng@zhangyunpengdeMacBook-Pro babel % npm init -y
    Wrote to /Users/zhangyunpeng/Downloads/uni/test/liantong/babel/package.json:
    ​
    {
      "name": "babel",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "keywords": [],
      "author": "",
      "license": "ISC"
    }
    ​
  2. Create index.js in the root directory and write the following code internally:

    console.log('Hello Node!')
  3. Create the startup command in package.json

    {
      "name": "babel",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "hello":"node ./index.js"
      },
      "keywords": [],
      "author": "",
      "license": "ISC"
    }
  4. Running npm run hello on the command line will output the following

    zhangyunpeng@zhangyunpengdeMacBook-Pro babel % npm run hello
    ​
    > babel@1.0.0 hello
    > node ./index.js
    ​
    Hello Node!
    zhangyunpeng@zhangyunpengdeMacBook-Pro babel % 

2. Test module syntax

  1. Create model.js in the root directory and fill in the following code

    // Export objects through cjs module
    module.exports = {
      name:'Xiao Ming',
      age:18
    }
  2. Write the following code in index.js

    // Import the objects exposed by the model module
    const user = require('./model')
    console.log('Hello Node!')
    console.log(user)
  3. Run the code with npm run hello, and the following results will appear:

    zhangyunpeng@zhangyunpengdeMacBook-Pro babel % npm run hello
    ​
    > babel@1.0.0 hello
    > node ./index.js
    ​
    Hello Node!
    { name: 'Xiao Ming', age: 18 }
    zhangyunpeng@zhangyunpengdeMacBook-Pro babel % 
  4. This is how NodeJS exports and imports the default CommonJS module

3. Test ES Module

  1. Create model1.js again in the root directory and write the following code

    //Module export using ES Module
    export default {
      name:'floret',
      age:18
    }
  2. Change index.js to the following code again:

    // Import the objects exposed by the model1 module
    import user1 from './model1.js''
    // Import the objects exposed by the model module
    const user = require('./model')
    console.log('Hello Node!')
    console.log(user)
    console.log(user1)
  3. Run index.js with npm run hello, and the console will display the following error

    zhangyunpeng@zhangyunpengdeMacBook-Pro babel % npm run hello
    ​
    > babel@1.0.0 hello
    > node ./index.js
    ​
    (node:34528) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
    (Use `node --trace-warnings ...` to show where the warning was created)
    /Users/zhangyunpeng/Downloads/uni/test/liantong/babel/index.js:2
    import user1 from './model1'
    ^^^^^^
    ​
    SyntaxError: Cannot use import statement outside a module
        at Object.compileFunction (node:vm:352:18)
        at wrapSafe (node:internal/modules/cjs/loader:1025:15)
        at Module._compile (node:internal/modules/cjs/loader:1059:27)
        at Object.Module._extensions..js (node:internal/modules/cjs/loader:1124:10)
        at Module.load (node:internal/modules/cjs/loader:975:32)
        at Function.Module._load (node:internal/modules/cjs/loader:816:12)
        at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:79:12)
        at node:internal/main/run_main_module:17:47
    zhangyunpeng@zhangyunpengdeMacBook-Pro babel % 
  4. The reason for the error is that NodeJS will execute JavaScript code according to the CommonJS specification by default, so the syntax of NodeJS is different from that of ECMAScript. The module features module.exports and require modes, while the module keywords of ES Module are export and import.

  5. The Node console proposes a solution to this problem. You can define the type as module in packpage.json or use mjs as the suffix to define the file using ES Module.

  6. According to this idea, take the modification scheme of package.json as an example, and modify its code as follows

    {
      "name": "babel",
      "version": "1.0.0",
      "type":"module",//The additional module is defined as ES Module mode
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "hello":"node ./index.js"
      },
      "keywords": [],
      "author": "",
      "license": "ISC"
    }
    ​
  7. Continue to run npm run hello, and a new error arises.

    zhangyunpeng@zhangyunpengdeMacBook-Pro babel % npm run hello
    ​
    > babel@1.0.0 hello
    > node ./index.js
    ​
    file:///Users/zhangyunpeng/Downloads/uni/test/liantong/babel/index.js:4
    const user = require('./model')
                 ^
    ​
    ReferenceError: require is not defined in ES module scope, you can use import instead
    This file is being treated as an ES module because it has a '.js' file extension and '/Users/zhangyunpeng/Downloads/uni/test/liantong/babel/package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
        at file:///Users/zhangyunpeng/Downloads/uni/test/liantong/babel/index.js:4:14
        at ModuleJob.run (node:internal/modules/esm/module_job:183:25)
        at async Loader.import (node:internal/modules/esm/loader:178:24)
        at async Object.loadESM (node:internal/process/esm_loader:68:5)
        at async handleMainPromise (node:internal/modules/run_main:63:12)
    zhangyunpeng@zhangyunpengdeMacBook-Pro babel % 
  8. A new error appears. This error tells us that the current js file contains an unrecognized require keyword. This keyword is the module import of CommonJS specification and is not supported in ES Module. To solve this problem, you can name the file at the end of. cjs or remove the type from package.json.

5. babel rescue site

For this scenario, NodeJS cannot handle the module specification including both ES Module and CommonJS. The problem of fish and bear's paw comes. In order to cater to the new programming style, NodeJS often needs to be programmed according to ES specification. In this way, babel needs to be added to the Node project if you want to maintain the original specification of Node and use the complete ECMA specification.

6. Install the necessary dependencies

If you want to use babel syntax compiler in Node, you first need to install babel's core library @ babel/core. Then, in order to perfectly support comprehensive JavaScript syntax, you need to use @ babel / preset env dependency to configure JavaScript operation mode and plug-in management. Finally, you need to install the babel execution tool @ babel/cli. Finally, you need to install the compensation package corejs for compatibility processing. The installed package.json is as follows:

{
  "name": "babel",
  "version": "1.0.0",
  "type": "module",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "hello": "node ./index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/cli": "^7.15.7",
    "@babel/core": "^7.15.8",
    "@babel/preset-env": "^7.15.8"
  },
  "dependencies": {
    "core-js": "^3.18.3"
  }
}

7. Use babel method to realize the normal operation of the program

  1. Create the src folder in the root directory and move all JavaScript files inside the folder

  2. Modify the original command in package.json and add the babel build command

    {
      "name": "babel",
      "version": "1.0.0",
      "type": "module",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "hello": "node ./src/index.js",//Change the original command path
        "babel-build": "babel src --out-dir lib"//Use the compile entire folder command in babel to output the current src folder to lib
      },
      "keywords": [],
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "@babel/cli": "^7.15.7",
        "@babel/core": "^7.15.8",
        "@babel/preset-env": "^7.15.8"
      },
      "dependencies": {
        "core-js": "^3.18.3"
      }
    }
    ​
  3. Create a file named. babelrc in the root directory and declare the following configuration in it

    {
      "presets": [//Install the preset env management plug-in into babel
        [
          "@babel/preset-env",
          {
            "useBuiltIns": "usage",
            "corejs":"3"
          }
        ]
      ]
    }
  4. You can refer to the configuration methods of useBuiltIns and corejs directly babel official website , because the principle of fixed rules used here is also very simple, I won't introduce more.

  5. Next, run NPM run Babel build on the command line and you will find that there is no error at this time, because the current action only executes the compilation of the code and does not execute the code.

    zhangyunpeng@zhangyunpengdeMacBook-Pro babel % npm run babel-build
    ​
    > babel@1.0.0 babel-build
    > babel src --out-dir lib
    ​
    Successfully compiled 3 files with Babel (324ms).
    zhangyunpeng@zhangyunpengdeMacBook-Pro babel % 
  6. Let's take a look. A lib folder will appear in the root directory, which will contain the following files

  7. //index.js
    "use strict";
    
    var _model = _interopRequireDefault(require("./model1.js"));
    
    function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
    
    // Import the objects exposed by the model1 module
    // Import the objects exposed by the model module
    var user = require('./model');
    
    console.log('Hello Node!');
    console.log(user);
    console.log(_model["default"]);
  8. //model.js
    "use strict";
    ​
    // Export objects through cjs module
    module.exports = {
      name: 'Xiao Ming',
      age: 18
    };
    //model1.js
    "use strict";
    ​
    require("core-js/modules/es.object.define-property.js");
    ​
    Object.defineProperty(exports, "__esModule", {
      value: true
    });
    exports["default"] = void 0;
    //Module export using ES Module
    var _default = {
      name: 'floret',
      age: 18
    };
    exports["default"] = _default;
  9. Here, you will find that the codes of the three files have changed, and the ES Module code no longer exists in the output content. Next, run index.js under lib. Add the following script in package.json. Don't forget to remove the type:"module"

    {
      "name": "babel",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "hello": "node ./src/index.js",
        "babel-build": "babel src --out-dir lib",
        "lib": "node ./lib/index.js"//Append code
      },
      "keywords": [],
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "@babel/cli": "^7.15.7",
        "@babel/core": "^7.15.8",
        "@babel/preset-env": "^7.15.8"
      },
      "dependencies": {
        "core-js": "^3.18.3"
      }
    }
  10. Execute npm run lib on the command line, and the following information will be output:

    zhangyunpeng@zhangyunpengdeMacBook-Pro babel % npm run lib
    ​
    > babel@1.0.0 lib
    > node ./lib/index.js
    ​
    Hello Node!
    { name: 'Xiao Ming', age: 18 }
    { name: 'floret', age: 18 }
    zhangyunpeng@zhangyunpengdeMacBook-Pro babel % 
  11. The code generated by babel compilation can run normally and output the expected results.

8. babel shortcut for node

According to the introduction in Section 6, the code compilation and running problems are solved through babel, but there is a tangled point here. When compiling with babel, you need to output the file in the room first and then execute the file in the room through the node command, which will be troublesome in program execution. Therefore, babel has another solution for node, which needs to add @ babel/node dependency in the project:

  1. dev install @ babel/node dependency

  2. Add the following command in package.json

    {
      "name": "babel",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "hello": "node ./src/index.js",
        "babel-build": "babel src --out-dir lib",
        "lib": "node ./lib/index.js",
        "babel-node": "babel-node ./src/index.js"//Babel node run command
      },
      "keywords": [],
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "@babel/cli": "^7.15.7",
        "@babel/core": "^7.15.8",
        "@babel/node": "^7.15.8",
        "@babel/preset-env": "^7.15.8"
      },
      "dependencies": {
        "core-js": "^3.18.3"
      }
    }
    ​
  3. Here, the Babel node command is used to specify to run index.js in the src directory, which means to directly run the code mixed with ES Module and CommonJS syntax. Running NPM run Babel node will find that the code in index can be executed directly without generating the contents of lib file

    zhangyunpeng@zhangyunpengdeMacBook-Pro babel % npm run babel-node
    ​
    > babel@1.0.0 babel-node
    > babel-node ./src/index.js
    ​
    Hello Node!
    { name: 'Xiao Ming', age: 18 }
    { name: 'floret', age: 18 }
    zhangyunpeng@zhangyunpengdeMacBook-Pro babel % 

8. Description of @ Babel / node

@babel/node is a command line tool specially provided by babel for node. Its actual operation principle is to perform code conversion and parsing first, but do not generate physical files. Therefore, it is not necessary to generate code through @ babel/cli before running node commands@ babel/node processes the two operations directly in memory, which is equivalent to directly executing the target file, and makes developers think that more ECMA syntax can be used in NodeJS.

summary

For babel, this article will stop here for the moment. The use of. Browerslist and other aspects have been mentioned in the author's previous Webpack introduction, so this article will not introduce it. Students interested in the use of other properties and dependencies of babel can go to the official documents to learn. babel plays an important role in modern front-end development, so I hope that students who are practicing on the front-end road will pay attention to it and can deeply learn this tool, so that we can take the engineering front-end development to a higher level.

Tags: Javascript Front-end Babel

Posted on Sat, 23 Oct 2021 02:22:34 -0400 by olsrey