When I first started to use Babel, I believe that many of you are like me, who have little knowledge about the configuration of Babel. The Babel related package @babel/core, @babel/cli, babel-loader, @babel/polyfill, @babel/plugin-transform-runtime, @babel/plugin/transform-runtime The purpose of this article is to help those of you who have not yet used Or are new to using Babel quickly learn how to use this powerful tool. For those who want to learn more about Babel, the recommended official documentation is in Chinese and English.

Note: Babel version 7 and WebPack version 4 are used in this article. Installation and configuration of different versions are different.

What is the Babel

Babel is a Javascript compiler that is currently one of the most commonly used tools for front-end development. It is primarily used to convert ECMAScript 2015+ code into backward-compatible Javascript syntax so that it can run in current and older versions of browsers or other environments. For example, if you use the arrow function of ES6 in your code, it will cause errors in IE. In order for your code to run in IE, you need to compile your code to the way IE supports it, which is what Babel does.

const fn = arg= > {
    console.log(arg);
};

/ / the Babel after conversion

"use strict";

var fn = function fn(arg) {
  console.log(arg);
};

Copy the code

use

  1. Used in command line tools
// Run NPM i@babel /core @babel-cli -dCopy the code

After installation, you can execute Babel’s script commands in the scripts of package.json. It is possible to install globally, so that you can use the Babel command directly from the command line tool, but this is not recommended.

{
  "scripts": {
    "build": "babel src -d dist"}},Copy the code

NPM run build is then executed from the command line, and Babel compiles the files in the SRC folder and outputs them to the dist folder.

  1. Webpack used in

Instead of using commands directly from the command line, our projects now usually use a packaging tool, and it would be much easier if we could combine Babel with the packaging tool to automatically call Babel to compile code when we package. Using Webpack as an example, if you want to use the compilation function of Babel in Webpack, you need to install babel-loader.

npm i @babel/core babel-loader -D
Copy the code

Then in the webpack configuration file, configure babel-loader to load and process JS files.

// webpack.config.js
const path = require('path');
module.exports = {
    entry: './src/app.js'.output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js'
    },
    module: {
        rules: [{test: /\.js$/.exclude: /node_modules/.loader: 'babel-loader'}}};Copy the code
  1. More ways to use

Babel also provides many other ways to use it, such as directly with the editor, or other packaging tools such as Gulp, Grunt, etc. More information can be found on the website.

Note: @babel/core is the base package of babel7 version and must be introduced.

configuration

It’s easy to use, but that’s not enough. Now when you compile Babel, you’ll find that the compilation is successful, but the compiled content is no different from the compiled content. That’s because we didn’t tell Babel how to compile or what to compile. The configuration file can be used in the following ways:

  1. Set the Babel field in package.json.
  2. .babelrc file or.babelrc.js
  3. Babel. Config. Js file

The first method does not create a file; package.json simply adds configuration information to Babel.

//package.json
{
   "name":"babel-test"."version":"1.0.0"."devDependencies": {
       "@babel/core":"^ 7.4.5"."@babel/cli":"^ 7.4.4." "."@babel/preset-env":"^ 7.4.5"
   }
   "babel": {
       "presets": ["@babel/preset-env"]}}Copy the code

.babelrc and.babelrc.js are the same configuration, but the file format is different, one is json file, the other is JS file.

.babelrc

{
    "presets": ["@babel/preset-env"]}Copy the code

.babelrc.js

// WebPack configuration files are also written this way
module.exports = {
    presets: ['@babel/preset-env']};Copy the code

The two configuration files are folder-specific. That is, the Settings of the configuration file are applied to the folder where the configuration file resides, including subfolders, and the lower-level configuration file overwrites the upper-level configuration file. In this way, you can set different rules for different directories. The third babel.config.js is written the same as.babelrc.js, but babel.config.js is for the entire project, and only one of each project is placed in the project root directory.

Note 1:.babelrc files placed in the project root have the same effect as babel.config.js. If both types of configuration files exist,.babelrc overwrites the configuration of babel.config.js.

Note 2: It makes no difference whether you write configuration in package.json or create configuration files. The react/create-react-app Babel configuration is written in package.json, while the @vue/cli/vue babel.config.js configuration is set in babel.config.js.

The Plugins and Presets

The next step is to use the configuration file to tell Babel what to compile and to introduce Plugins. For example, @babel/plugin-transform-arrow-functions is required to convert arrow functions. We installed the package through NPM and set it in the configuration.

npm i @babel/plugin-transform-arrow-functions -D
Copy the code
// babel.config.js
module.exports = {
    plugins: ['@babel/plugin-transform-arrow-functions']};Copy the code

Now the arrow functions in our code will be compiled as normal functions, but the problem is that we can’t always import these plugins one by one to translate each new feature we use. This can be very cumbersome, so we have something called Presets.

A preset is a preset list of plugins, and using a preset is to install and use all preset plugins, such as @babel/preset-es2015, which includes @babel/plugin-transform-arrow-functions, And conversion plug-ins for other new ES2015 features like for-of, Class, template strings, etc. By simply installing the default package via NPM and setting it up like this, we are free to use the new ES2015 features in our code, which Babel will convert at compile time into compatible code that will be recognized by lower-version browsers.

npm i @babel/preset-es2015 -D
Copy the code
// babel.config.js
module.exports = {
    presets: ['@babel/preset-es2015']};Copy the code

Note: Babel not only supports conversion of new syntax features, react and Vue syntax are also converted via Babel, for example, react projects can use preset- React.

preset-env

Preset is greatly convenient, but if we want to use newer syntax, such as ES2016 ** (equivalent to POw ()), ES2017 async/await, etc., we introduce @babel/preset-es2016, @babel/preset-es2017 and these presets will be more and more as JS syntax is updated. Babel has released babel-Env, an intelligent preset that will automatically convert new features in the code to preset supported by the target browser based on which you set it.

As an example of a converted arrow function, NPM installs @babel/preset-env and configures it.

npm i @babel/preset-env -D
Copy the code
// babel.config.js
module.exports = {
    presets: [['@babel/preset-env',
            {
                targets: {
                    chrome: '58'}}]]};Copy the code

If we set the target browser to support Internet Explorer 9, since Internet Explorer 9 doesn’t support arrows, Once compiled, you’ll see that the arrow function is converted to a normal function.

For details on how to set the target browser version, see Browserslist. The browser features support querying caniuse.

Note 1: Even if targes is not set, there will be a default value with the rule > 0.5%, last 2 Versions, Firefox ESR, not dead. Note 2: Preset -env is officially recommended.

The plugin – transform – runtime and runtime

When I was compiling with Babel, I needed utility functions to help implement some of the features, such as class compilation.

class People{}// Babel is compiled
'use strict';

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

Copy the code

In the compiled code, _classCallCheck is a utility function for helper functionality implementation. If you use class in multiple files, and each file is compiled to generate a utility function, you end up with a lot of duplicate code, which increases the size of the file. The plugin-transform-Runtime solves this problem by converting these utility functions into imported forms.

npm i @babel/plugin-transform-runtime -D
Copy the code
module.exports = {
    presets: ['@babel/preset-env'].plugins: ['@babel/plugin-transform-runtime']};Copy the code

Install Babel and set it up again.

"use strict";

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

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

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

The _classCallCheck2 utility function has been imported from an NPM package and no separate utility function code is generated. However, you can see that the utility functions are imported from the @babel/ Runtime package, so that the @babel/ Runtime dependency package is installed so that no errors are reported when the project is packaged.

npm i @babel/runtime
Copy the code

Note: Babel/Runtime is not a development dependency, but a project production dependency. With plugin-transform-Runtime compiled, your project relies on Babel/Runtime, so the two are used together.

babel-polyfill

Babel can translate some new features, but for new built-in functions (Promise,Set,Map), static methods (array. from, object.assign), Example methods (array.prototype.includes) for this, babel-Polyfill will simulate an ES2015+ environment completely.

For example, if your code uses array. from, but the target browser doesn’t support array. from, introducing babel-Polyfill adds a from method to the Array. The array. from function used when executing the code is actually simulated by Babel-Polyfill, which contaminates Array’s static methods but does provide compatibility. The previous approach was to install @babel/ Polyfill at NPM and introduce the @babel/ Polyfill package at the project entrance.

npm i @babel/polyfill
Copy the code
// entry.js
import "@babel/polyfill";
Copy the code

However, this method has been abandoned and is not recommended, because @babel/ Polyfill is large, and the whole introduction increases the project volume and contaminates too many variables, so preset-env is recommended to be used to introduce polyfill as needed.

// babel.config.js
module.exports = {
    presets: [['@babel/preset-env',
            {
                useBuiltIns: 'usage'.// Usage - On demand import - Entry import (overall import) false- Do not import polyfill
                corejs: 2  // 2-corejs@2 3-corejs@3}}]].Copy the code

Corejs is a library that provides an interface to earlier versions of browsers and is the core of polyfill’s implementation. The version specified here is the one introduced into Corejs. You need to install the corejs library of the specified version through NPM as a production dependency.

npm i core-js@2
Copy the code

After executing Babel compilation, you can see the following effect:

const a = Array.from([1])

/ / the Babel compiled
"use strict";

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

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

var a = Array.from([1]); 

Copy the code

You can see that prior to using array. from, the corresponding polyfills were introduced from core-js, and we can guess what they do based on the file name.

Discussion of plugin-transform-Runtime and Babel-polyfill

Plugin-transform-runtime is mainly responsible for converting utility functions into imported methods to reduce duplicate code, while babel-Polyfill is responsible for importing related files to simulate compatible environments. One problem with babel-polyfill is that introducing files contaminates variables. Plugin-transform-runtime also provides a polyfill for runtime. Let’s modify the configuration file.

module.exports = {
    plugins: [['@babel/plugin-transform-runtime', { corejs: 2}}]].Copy the code

The run-time corejs library is used to install the corejs package. The run-time corejs library is used to install the corejs package.

npm i @babel/runtime-corejs2
Copy the code

And then we run the Babel compilation to see the difference.

const a = Array.from([1])

/ / the Babel compiled
"use strict";

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

var _from = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/array/from"));

var a = (0, _from["default"([])1]);

Copy the code

As you can see, the difference between this method and using babel-polyfill is that instead of changing array. from, a _FROM is created to simulate array. from, and calling array. from is compiled to call _from, The obvious advantage of this is that it does not pollute static methods on Array. From, plugin-transform-Runtime provides runtime polyfills of this form.

After my tests, in addition to the methods on the prototype such as array.prototype.includes, other built-in functions mentioned earlier (Promise,Set,Map), Static methods (array. from, object. assign) can take the plugin-transform-runtime form.

Then I thought, since this form does not pollute variables, of course it can be used in this way, but after asking the group, the leaders gave a view (thanks to justJavac and Brother Hour for the explanation).

Runtime does not pollute global variables, but can result in duplicate code in multiple files. Write libraries using Runtime, system projects using Polyfill. The runtime is the safest way to write a library. If we use an includes, but our dependency library B also defines this function, we will have a problem introducing polyfill globally: we will overwrite the dependency library B’s includes. This is especially true for Promises. Many libraries rely on Bluebird or other Promise implementations. Libraries should generally not provide any polyfill schemes when writing libraries. Instead, the user manual explains what new features are being used and lets the user go to Polyfill.

This will depend on the type of project, but for general business projects, the plugin-transform-Runtime function is compatible with babel-polyfill.

The final summary

The package name function instructions
@babel/core Babel compiles the core package Must install development dependencies
@babel/cli Command line to execute the Babel command tool The Babel command must be installed if the script in packages. Json uses the Babel command
babel-loader Babel is used to load files in Webpack Non-mandatory development dependencies, used in webPack projects
@babel/plugin-* Babel compiler function implementation plug-in Develop dependencies and install them as required
@babel/preset-* Function to achieve plug-in presets Develop dependencies and install preset functions as required. Preset -env is recommended for conversion of new features in THE JS language
@babel/plugin-transform-runtime Reuse tool function Optional development dependencies that coexist with @babel/ Runtime
@babel/runtime Tool library Optional production dependencies, and @babel/plugin-transform-runtime coexist
@babel/polyfill Browsers of earlier versions are compatible with libraries It is not required to install production dependencies and is not recommended. Preset -env is recommended to be used as required
core-js@* Browsers of earlier versions are compatible with libraries Non-mandatory production dependencies, preset-env introduced to Polyfill requires this package to be installed and the version specified by corejs
@babel/runtime-corejs* Browser compatibility libraries with lower versions that do not pollute variables The plugin-transform-Runtime setting is not required to install production dependencies, so the plugin-transform-Runtime setting can be turned on without contaminating variable introduction to polyfill

These are the basic contents of Babel use, and the internal implementation of Babel compilation can be studied in detail, or you can write some Babel plugins and preset published to NPM for everyone to use. Hope that after reading this article, it will help everyone to understand and use Babel.

The ability is general, the level is limited, welcome everybody to point out a lot to discuss.