preface

When I had time to study Babel, I searched the official website and a lot of materials. None of them had detailed practices, and all of them lay emphasis on theories. Therefore, I have compiled a practical Babel configuration for learning.

What’s a Babel?

Babel is a JS compiler

Babel is a tool chain for converting ECMAScript 2015+ (also known as ES6, ES7, ES8, etc.) code into backward compatible JavaScript syntax To be able to run on current and older browsers or other environments (such as older Node environments).

What exactly did Babel do

  • The syntax conversion
  • throughPolyfillWay to add missing features to the target environment (through@babel/polyfillModule)
  • Source code conversion (Codemods)

Popular point

  • ES2015+Syntax conversion of arrow functions to normal functions
  • ES2015+New method transformation (e.gincludesMethod conversion compatible with lower version of the viewer)

In this article, you’ll learn how and why Babel7 is configured. @babel/runtime, @babel/polyfill, @babel/plugin-transform-runtime. What is a plug-in and what is a default and how to configure it.

You may have the following questions

Difference between @babel/cli and babel-cli?

When looking for information on the Internet, you will often see that some Babel is configured with Babel -cli and some @babel/cli. Why should it be any different? Because Babel has been upgraded to Babel7. The original packages used in Babel6 were packages like able- CLI. When you upgrade babel7, you use packages that start with @ : @babel/cli,@babel/core, etc. So the ones that start with @ are babel7 and the ones that don’t start with @ are babel6. So don’t install the package wrong.

The plugin?

Babel is a compiler (input source => output compiled code). Just like any other compiler, the compilation process is divided into three stages: parsing, conversion, and printout.

Right now, Babel doesn’t do anything out of the box. It’s basically like const Babel = code => code; , parses the code and prints the same code. If you want Babel to do any real work, you need to add plug-ins to it.

In plain English, Babel can’t do anything without plug-ins, and it can’t compile code to run on lower versions of browsers. Plug-ins need to be converted in the middle to meet our requirements

The default?

Preset? What is this blah blah blah…

Babel offers a concept called preset, which is euphemically called a preset but simply stands for preset packs, meaning that Babel will preset a series of preset packs for us

The plug-in package

A common package of plug-ins that Babel thinks programmers will use

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

Note: in addition to the above add-on packages, there are many more add-on packages. You can go to the official website

Now that you know some of the concepts, let’s put them into practice

project

Create a new project directory XXX (I created the babel-config directory), go to the directory command line to execute

npm init -y

Generate package.json and create app.js as follows

let func = (a)= >{}Copy the code

Babel configuration

@babel/cli @babel/core

Babel comes with a built-in CLI command-line tool that compiles files from the command line

Command line installation

npm install -D @babel/cli @babel/core

@babel/cli is a command line tool provided by Babel, mainly providing the command Babel. The website recommends installing it in a project rather than a global environment, as each project uses a different version of Babel. Can be managed and upgraded separately. The main purpose is to facilitate the future project migration.

The core functions of Babel are contained in the @babel/core module. You see the word core, which means core, and without it, you’re doomed to fail in Babel’s world. Babel cannot be compiled without @babel/core installed

Modify package.json and add it to script

"babel": "babel app.js -o ./dist/app.js"
Copy the code

Then run the command line

npm run babel

Compile successfully, take a look at the app.js file in dist

let func = (a)= > {};
Copy the code

What, what, what? Why hasn’t it changed at all?

This is because Babel doesn’t do anything out of the box, and if you want Babel to do any real work, you need to add a plugin to it (mentioned above)

Use of plug-ins

npm install –save @babel/plugin-transform-arrow-functions

New again. Babelrc

The Babel developers provide various forms for configuration files, and babel7 officially recommends babel.config.js. You can also use.babelrc,.babelrc.js or put it in package.json

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

Run the command again

npm run babel

View dist/app.js file perfect, executed successfully

let func = function () {};
Copy the code

So why isn’t let converted?

Since the plug-in we just introduced was specifically used to transform arrow functions, let was not transformed. If you want to convert lets, you need to import a new plug-in.

There are so many new additions to ES6 that I have to introduce them one by one? Crazy…

You don’t have to introduce them one by one. This is when the above (preset) plugin pack is used.

Babel developers have been thinking about this for a long time and have provided us with a number of plug-in packages. The most common is @babel/preset-env

npm install --save-dev @babel/preset-env

Run the command again

"use strict";

var func = function func() {};
Copy the code

Conversion of success

It looks perfect, so let’s add some code to app.js

let func = (a)= >{}let arr = [1.2.4]
arr.includes(3)
Copy the code

Run the command again, result

"use strict";
var func = function func() {};
var arr = [1, 2, 4];
arr.includes(3);
Copy the code

Includes has not been converted, it still does not work on the earlier version of the browser.

Babel just transforms the syntax, es6 adds new methods into includes that cannot be transformed

@babel/polyfill

That’s where @babel/polyfill comes in.

The @babel/ Polyfill module includes core-JS and a custom ReGenerator Runtime module that can simulate a full ES2015+ environment (not including pre-phase 4 proposals).

This means you can use new built-in components like Promise and WeakMap, static methods like Array.from or Object.assign, and array.prototype.includes And generator functions (provided you use the @babel/plugin-transform-regenerator plug-in). To add these capabilities, Polyfill is added to global scopes and built-in stereotypes like String

Polyfill is a way of smoothing out differences between browsers or environments, because some environments support this function, some environments don’t, and it’s a matter of whether or not, This cannot be solved simply by @babel/preset-env, because @babel/preset-env solves the problem of switching a higher version to a lower version, because preset may be different in different environments.

npm install --save @babel/polyfill

Then introduce it at the very beginning of our code. App. Js as follows:

import '@babel/polyfill'; // This is how @babel/polyfill is used

let func = (a)= >{}let arr = [1.2.4]
arr.includes(3)
Copy the code

We then execute the compile command NPM run Babel to execute the results

"use strict";
require("@babel/polyfill");
var func = function func() {};
var arr = [1, 2, 4];
arr.includes(3);
Copy the code

After compiling the code, we find that there seems to be a problem. I introduced @babel/polyfill, which compiles to require. This works on nodes, but not on browsers.

why

All Babel does is help you convert ES6 modular syntax to CommonJS modular syntax, where require exports and so on are CommonJS variables provided in the implementation.

Any environment that implements CommonJS (such as Node) can run this code directly. Browser environments do not support CommonJS, so we need to use bundler to package the code. Make some wraps for our code so it can be used in the browser. Form a regular JS file. There are packaging tools like Browserify, Webpack, etc

webpack

Let’s install webPack

npm install --save-dev webpack webpack-cli babel-loader

Modify package.json configuration add “dev”: “webpack”

"scripts": {
    "babel": "babel app.js -o ./dist/app.js",
    "dev": "webpack"
},
Copy the code

New webpack. Config. Js

const path = require('path');

module.exports = {
    // Mode is production mode
    mode: 'production'.entry: {
        app: './app.js'
    },
    // The packaged file
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js'
    },
    // Turn off webPack automatic compression of obfuscated code
    optimization: {
        minimize: false.// <---- disable uglify.
    },
    module: {
        rules: [{// All js files are processed by babel-loader
                test: /\.js$/.use: 'babel-loader'.exclude: '/node_modules/',}]}}Copy the code

Run the new build command NPM run dev successfully compiled and can run normally on the browser side. But it turns out that the uncompressed code has 259K

Open compression also has 88.9K

I wrote only a few lines of code, how to compile such a large JS. Because @babel/ Polyfill is a shim (Understand: each viewer supports the ES6 method differently. This will introduce all of the ES6 methods you use in your code, as well as those you don’t.

Okay, that works, too. You can have fun writing ES6 code.

Optimization (According to the need to load)

@babel/preset-env provides a useBuiltIns parameter, and when set to Usage, only polyfills needed by the code will be included. Note that to set this parameter to usage, corejs must be set at the same time (warning will be given if not set, default is “corejs”: 2). Note: Here you still need to install @babel/polyfill(the current @babel/polyfill version installs “corejs”: 2 by default):

First of all, the reason for using core-js@3 is that no new features are added to the core-js@2 branch. New features are added to core-js@3. For example, if you’re using array.prototype.flat (), if you’re using core-js@2, it doesn’t include this new feature. In order to use more of the new features, we recommend that you use core-js@3

npm install --save core-js@3

Modify the. Babelrc configuration

{
    "presets": [["@babel/preset-env",
            {
                "targets": {
                    "browsers": [
                        "1%" >."last 2 versions"]},"useBuiltIns": "usage"."corejs": 3}}]]Copy the code

Remove the import ‘@babel/polyfill’ from the code to unload the @babel/polyfill package

npm uninstall @babel/polyfill

Package. The json as follows

"Dependencies" : {" core - js ":" ^ 3.6.5 "}, "devDependencies" : {" @ Babel/cli ":" ^ 7.8.4 ", "@ Babel/core" : "^ 7.9.0 @", "Babel/preset - env" : "^ 7.9.5", "Babel - loader" : "^ 8.1.0", "webpack" : "^ 4.42.1", "webpack - cli" : "^ 3.3.11"},Copy the code

Compressed and compiled, the size is only 10.1K

It’s a lot less. It’s perfect now.

but

Let’s modify some source code and create a new file app2.js

class BBB {}Copy the code

Modify the app. Js

import './app2';

let func = (a)= >{}let arr = [1.2.4]
arr.includes(3)


class AAAA {}Copy the code

Let’s compile this (without webpack’s compression package) and look at our packaged app.js

In the compiled code, the _classCallCheck method is defined twice. A JS file is defined once. There are a lot of files in that project, aren’t there many definitions?

@babel/plugin-transform-runtime

This is where the @babel/plugin-transform-runtime plugin comes in. With the @babel/ plugin-transform-Runtime plugin, all helpers will reference the @babel/runtime module. This avoids duplicate helpers in compiled code and reduces package size

@babel/ plugin-transform-Runtime is a plug-in that can reuse Babel injected helper to save code size.

@babel/plugin-transform-runtime needs to work with @babel/ Runtime

@babel/plugin-transform-runtime is usually only used for development purposes, but the final code needs to rely on @babel/runtime, so @babel/runtime must be installed as a production dependency, as follows:

npm install --save-dev @babel/plugin-transform-runtime

npm install --save @babel/runtime

Modify the. Babelrc configuration file

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

Run the package command

It’s already presented as a public method. Great.

The overall configuration

Webpack configuration

const path = require('path');

module.exports = {
    // Mode is production mode
    mode: 'production'.entry: {
        app: './app.js'
    },
    // The packaged file
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js'
    },
    // Turn off webPack automatic compression of obfuscated code
    optimization: {
        minimize: false.// <---- disable uglify.
    },
    module: {
        rules: [{// All js files are processed by babel-loader
                test: /\.js$/.use: 'babel-loader'.exclude: '/node_modules/',}]}}Copy the code

.babelrc

{
    "presets": [["@babel/preset-env",
            {
                "targets": {
                    "browsers": [
                        "1%" >."last 2 versions"]},"useBuiltIns": "usage"."corejs": 3}]],"plugins": [
        "@babel/plugin-transform-runtime"]}Copy the code

package.json

{
  "name": "es8"."version": "1.0.0"."description": ""."main": "index.js"."scripts": {
    "test": "webpack"."babel": "babel app.js"
  },
  "keywords": []."author": ""."license": "ISC"."devDependencies": {
    "@babel/cli": "^ 7.8.4"."@babel/core": "^ 7.9.0"."@babel/plugin-transform-runtime": "^ 7.9.0"."@babel/preset-env": "^ 7.9.5"."babel-loader": "^ 8.1.0"."webpack": "^ 4.42.1"."webpack-cli": "^ 3.3.11." "
  },
  "dependencies": {
    "@babel/runtime": "^ 7.9.2"."core-js": "^ 3.6.5." "}}Copy the code

app.js

import './app2';

let func = (a)= >{}let arr = [1.2.4]
arr.includes(3)


class AAAA {}Copy the code

app2.js

class BBB {}Copy the code

conclusion

The above is my understanding and configuration of Babel. It is inevitable that there are many problems in this paper. Please point out if you find them.

Reference article (really great)

  • Babel Chinese website
  • Babel7 knowledge not to be missed
  • Personal understanding of Babel 7 use
  • Babel/es6 / require

Git address:

Github address can be directly downloaded, like help under star