Introduction

Two minor releases of Babel were updated in 2021, adding some support for Stage 4 proposals and some top-level configuration items (targets, assumptions). With these updates, let’s explore how to use Babel in 2021, in combination with babel-Loader and babel-preth-react-app.

@babel/preset-env

@babel/preset-env is the official recommended preset. Just configure the relevant targets to convert the current code to the target environment code, following browserslist configuration, the main configuration items are as follows:

targets

Configure the target environment. If not specified, all ES2015-ES2020 code will be converted to ES5. Instead of using Browserslist defaults configuration (> 0.5%, last 2 Versions, Firefox ESR, Not Dead).

useBuiltIns

Configuration @ Babel/preset – env how to deal with polyfills, option for the “usage” | | false “entry”

"entry"

This configuration will automatically import “core-js/stable”; And import “regenerator-Runtime /runtime” to an on-demand import of the target environment, for example:

import "core-js/stable";
import "regenerator-runtime/runtime";
Copy the code

Under different circumstances it may be converted to:

import "core-js/modules/es.string.pad-start";
import "core-js/modules/es.string.pad-end";
Copy the code

One disadvantage, however, is that unwanted polyfills can also be introduced, because the Entry configuration is specific to the target environment, not specific code

"usage"

This configuration automatically introduces the polyfill required in the code without the need to display the import core-js declaration, which is recommended

false

Polyfill is not automatically added, nor is import core-js automatically converted to import on demand

corejs

This parameter takes effect when the useBuiltIns configuration item is Entry or Usage. The default value is 2.0. You are advised to set the useBuiltIns to minor Version

Other configurations such asinclude.excludeAs shown in theOptions

@babel/runtime

There are three configuration items for @babel/ Runtime and its matching @babel/ plugin-transform-Runtime, which correspond to different scenarios:

regenerator

When using the generator/async function automatically referenced @ Babel/runtime/regenerator. The default value is true and enabled by default

function* foo() {}
Copy the code

The output

"use strict";

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

var _regenerator2 = _interopRequireDefault(_regenerator);

function _interopRequireDefault(obj) {
  return obj && obj.__esModule ? obj : { default: obj };
}

var _marked = [foo].map(_regenerator2.default.mark);

function foo() {
  return _regenerator2.default.wrap(
    function foo$(_context) {
      while (1) {
        switch ((_context.prev = _context.next)) {
          case 0:
          case "end":
            return _context.stop();
        }
      }
    },
    _marked[0].this
  );
}
Copy the code

corejs

Add @babel/ Runtime-corejs helpers as needed to avoid generating code that would pollute the global space and built-in object archetypes. Optional value to false | 2 | 3 or {version: 2 | 3, proposals: Boolean} format, the configuration is false is not introduced related helpers

var sym = Symbol(a);var promise = Promise.resolve();

var check = arr.includes("yeah!");

console.log(arr[Symbol.iterator]());
Copy the code

The output

import _getIterator from "@babel/runtime-corejs3/core-js/get-iterator";
import _includesInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/includes";
import _Promise from "@babel/runtime-corejs3/core-js-stable/promise";
import _Symbol from "@babel/runtime-corejs3/core-js-stable/symbol";

var sym = _Symbol();

var promise = _Promise.resolve();

var check = _includesInstanceProperty(arr).call(arr, "yeah!");

console.log(_getIterator(arr));
Copy the code

helpers

Automatically remove inline Babel helpers and replace them with import mode. The benefit is to remove redundant and repetitive code. The default value is true and enabled by default

class Person {}
Copy the code

The typical conversion result is:

"use strict";

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

When enabled, the conversion result is:

"use strict";

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

var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);

function _interopRequireDefault(obj) {
  return obj && obj.__esModule ? obj : { default: obj };
}

var Person = function Person() {(0, _classCallCheck3.default)(this, Person);
};
Copy the code

babel-loader

Babel-loader supports the following cache configurations:

cacheDirectory

The default value is false. If set to true or some other address, subsequent webpack builds will attempt to read the previous content from the cache, avoiding the recompilation of Babel

cacheIdentifier

Default values are @babel/core version, babel-loader version, and. Babelrc contents combined with a stringify value, i.e. :

cacheIdentifier = JSON.stringify({
  options,
  "@babel/core": transform.version,
  "@babel/loader": version,
})
Copy the code

If this value changes, the cache is forced to flush

cacheCompression

The default value is true, after which Babel’s cached results are compressed by gzip

How can I accelerate the Rebuild function by enabling cache?

Support for caching to speed up rebuild can be summarized in the following steps:

  1. Check whether it is configuredcacheDirectory, if configuredcache()Further processing, if not directlytransform()
  2. Configure thecacheDirectoryThen, according to each file content (source), configuration (options) and identifier (identifier) three partsJSON.stringifyAnd then I hash to get the file namefilename, which is calledfilename(source, cacheIdentifier, options)Again,path.joinThe correspondingdirectoryGets the absolute path to the cached filefile
  3. After obtaining the absolute path to the file, try to read the contents of the file, if the corresponding before the description is readsourceIt has been cached and returns the corresponding result directly
  4. Those that do not willtransform()The subsequent results are written to the corresponding filefileAnd returns the result

For those interested, read the cache source code

create-react-app

With that in mind, let’s see how create-React-app and Babel are configured and handled

react-scripts

The react-scripts babel-loader for webpack is configured as follows:

 {
    test: /\.(js|mjs|jsx|ts|tsx)$/,
    include: paths.appSrc,
    loader: require.resolve('babel-loader'),
    options: {
      customize: require.resolve(
        'babel-preset-react-app/webpack-overrides'
      ),
      presets: [[require.resolve('babel-preset-react-app'),
          {
            runtime: hasJsxRuntime ? 'automatic' : 'classic',}]].babelrc: false.configFile: false.cacheIdentifier: getCacheIdentifier(
        isEnvProduction
          ? 'production'
          : isEnvDevelopment && 'development'['babel-plugin-named-asset-import'.'babel-preset-react-app'.'react-dev-utils'.'react-scripts',]),plugins: [[require.resolve('babel-plugin-named-asset-import'),
          {
            loaderMap: {
              svg: {
                ReactComponent:
                  '@svgr/webpack? -svgo,+titleProp,+ref! [path]',
              },
            },
          },
        ],
        isEnvDevelopment &&
          shouldUseReactRefresh &&
          require.resolve('react-refresh/babel'),
      ].filter(Boolean),
      cacheDirectory: true.cacheCompression: false.compact: isEnvProduction,
    },
  },
Copy the code

The summary is as follows:

  1. The introduction of thebabel-preset-react-app, this preset is also maintained by create-React-app, which is detailed later
  2. The custombabel-loaderthecacheIdentifierMake sure its value is unique, as shown above
  3. Set up thecacheDirectoryA value oftrueTo enable the related cache
  4. However, caches related Gzip compression is disabled for the reasons shown in this PR
  5. The formal environment is openedcompactmodel

babel-preset-react-app

Babel-react-app supports react, flow, and typescript. The configuration can be simplified as follows:

{
    presets: [
      isEnvTest && [
        // ES features necessary for user's Node version
        require('@babel/preset-env').default,
        {
          targets: {
            node: 'current',
          },
        },
      ],
      (isEnvProduction || isEnvDevelopment) && [
        // Latest stable ECMAScript features
        require('@babel/preset-env').default,
        {
          // Allow importing core-js in entrypoint and use browserlist to select polyfills
          useBuiltIns: 'entry'.// Set the corejs version we are using to avoid warnings in console
          corejs: 3.// Exclude transforms that make all code slower
          exclude: ['transform-typeof-symbol'],
        },
      ],
    ].filter(Boolean),
    plugins: [
      // Experimental macros support. Will be documented after it's had some time
      // in the wild.
      require('babel-plugin-macros'),
      // class { handleClick = () => { } }
      // Enable loose mode to use assignment instead of defineProperty
      // See discussion in https://github.com/facebook/create-react-app/issues/4263
      [
        require('@babel/plugin-proposal-class-properties').default,
        {
          loose: true],},// Adds Numeric Separators
      require('@babel/plugin-proposal-numeric-separator').default,
      // Polyfills the runtime needed for async/await, generators, and friends
      // https://babeljs.io/docs/en/babel-plugin-transform-runtime
      [
        require('@babel/plugin-transform-runtime').default,
        {
          corejs: false.helpers: areHelpersEnabled,
          // Assuming Babel/Runtime version 7.0.0-beta.0,
          // explicitly resolving to match the provided helper functions.
          // https://github.com/babel/babel/issues/10261
          version: require('@babel/runtime/package.json').version,
          regenerator: true.// https://babeljs.io/docs/en/babel-plugin-transform-runtime#useesmodules
          // We should turn this on once the lowest version of Node LTS
          // supports ES Modules.
          useESModules,
          // Undocumented option that lets us encapsulate our runtime, ensuring
          // the correct version is used
          // https://github.com/babel/babel/blob/090c364a90fe73d36a30707fc612ce037bdbbb24/packages/babel-plugin-transform-runtime/src /index.js#L35-L42
          absoluteRuntime: absoluteRuntimePath,
        },
      ],
      // Optional chaining and nullish coalescing are supported in @babel/preset-env,
      // but not yet supported in webpack due to support missing from acorn.
      // These can be removed once webpack has support.
      // See https://github.com/facebook/create-react-app/issues/8445#issuecomment-588512250
      require('@babel/plugin-proposal-optional-chaining').default,
      require('@babel/plugin-proposal-nullish-coalescing-operator').default,
    ].filter(Boolean),};Copy the code

The summary is as follows:

  1. @babel/preset-envUsing theuseBuiltInstheentryPatterns, notusagePattern, this onecommentExplains why, in generalusageIs there something wrong with the mode?
  2. @babel/preset-envExclude thetransform-typeof-symbolBecause it slows down the code, see thisissue
  3. babel-plugin-macros: support macro, specific is what interested you can understandbabel-plugin-macros
  4. @babel/plugin-transform-runtime
    • core-js: false: I don’t introducecore-jsRelevant content as above@babel/preset-envThe need for import files was mentionedimport core-js
    • version: require('@babel/runtime/package.json').version: Fixed version, which is also Babel’s official recommendation
    • regenerator: trueSupport:@babel/runtime/regeneratorAutomatic introduction of
  5. These plugins are compatible with other commonly used proposals that are not supported by WebPack 4

Conclusion

Create-react-app related react-Scripts and babel-preact-App give a standard paradigm for how to use Babel in 2021, which has a lot to be used for reference in daily development learning. Of course, in the actual use of the need to master the foundation, in order to meet different situations flexibly. Finally, a summary:

  1. usebabel-loaderIs recommended.cacheDirectoryTo enable caching and increase rebuild speed
  2. Make use of projects that need to compile code into a given environment@babel/preset-envthetargetsanduseBuiltInsConfiguration items can reduce a lot of unnecessary code compilation and polyfill
  3. You are advised to use this tool when developing tools or class libraries@babel/runtimeCooperate with@babel/plugin-transform-runtime