5

Since @babel/polyfill is deprecated after Babel 7.4, both @babel/preset-env and plugin-transform-runtime can set corejs to handle polyfill .

The main reasons for @babel/polyfill deprecation are:

  • This package simply introduces stable core-js and regenerator-runtime/runtime, the latter of which can be replaced by the plugin @babel/plugin-transform-regenerator.
  • This package does not have a smooth transition from core-js@2 to core-js@3.

Introduction to Babel

Simply put, Babel is a compiler that converts code written in ECMAScript 2015+ syntax into backwards-compatible JavaScript syntax so that it can run in various environments such as old and new browsers. The Babel code conversion function is implemented in the form of plugin , plugin is a small JavaScript program.

A preset can be thought of as a set of Babel plugins or shareable modules configured by options .

  • plugins run before presets;
  • plugins are executed sequentially from front to back;
  • presets are executed in reverse order according to the sorting order;

Babel mainly implements two functions:

  1. Convert the new syntax. Implement the new version of js syntax with the old version to run in the corresponding environment, such as arrow functions;
  2. Convert the new API. Patch (also known as polyfill) the old runtime to use features defined in the new js but provided in the old runtime, including three categories:

    • Newly defined built-in objects such as Promise
    • Newly added static methods of the original built-in objects, such as Array.from
    • Newly added instance methods of the original built-in objects, such as Array.prototype.includes

preset-env

preset-env can convert both new syntax and new API through configuration. The polyfill of preset-env will pollute the global environment.

target

This field can fill in the query string of browserslist . It is officially recommended to use the .browserslistrc file to specify the compiled target . This configuration file can also share configuration with tools such as autoprefixer and stylelint . Therefore, it is not recommended to use targets directly in the preset-env configuration of .babelrc .

If you need to configure targets here separately, specify ignoreBrowserslistConfig in preset-env as true to ignore the configuration items of .browserslistrc .

useBuiltIns

Whether to use its polyfill feature (core-js for global environment). There are three values:

  • false : Default value. Do not use preset-env to implement polyfills without actively import , and only use its default syntax conversion function. If you use the default value of false , you should avoid introducing polyfill in the entry file, making the package size too large.
  • entry : You need to manually introduce polyfill at the entry point. According to the configuration of the browser target environment ( targets ), introduce polyfill modules that are not currently supported by all browsers, regardless of whether they are used in the project or not.

     import "core-js/proposals/string-replace-all"
  • usage : There is no need to manually introduce polyfill in the entry file, Babel will automatically inject polyfill according to the code usage, so that the packaging volume will be relatively reduced when packaging.

corejs

Configure core-js, the default value is "2.0". This option is only valid when used with useBuiltIns: usage or useBuiltIns: entry .

core-js : A modular standard library for JavaScript, with Promise , Symbol , Iterator , and many other features that lets you load only the functionality you need.

  • version: [string] version number;
  • proposals: [boolean] Whether to implement the features in the proposal;
 // .babelrc { "presets": [   [     "@babel/preset-env",     {       "targets": {         "chrome": "80" // 推荐使用 .browserslistrc       },       "useBuiltIns": "usage",       "corejs": {         "version": 3, // 2 和 3 版本都需要手动安装库:yarn add core-js@3 "proposals": false       }     }   ] ] }

plugin-transform-runtime

plugin-transform-runtime mainly does three things:

  • When developers use asynchronous or generators, @babel/runtime/regenerator is automatically introduced, and developers do not need to do additional introductions in the entry file;
  • Dynamically introduce polyfill to provide a sandbox environment to avoid pollution of the global environment;

    If you directly import core-js or @babel/polyfill and the built-in components it provides such as Promise, Set and Map, these will pollute the global. While this doesn't affect applications or command-line tools, problems can arise if the code is a library that is meant to be released to others for use, or if there is no precise control over the environment in which the code will run.

  • All helpers helper modules will reference the module @babel/runtime to avoid duplication in compilation output and reduce packaging size;

corejs

Configuration value: false, 2, or { version: number, proposals: boolean } , the default value is false.

corejs Installation advice
false npm install --save @babel/runtime
2 npm install --save @babel/runtime-corejs2
3 npm install --save @babel/runtime-corejs3

helpers

The configuration value is boolean type, the default value is true.
Whether to replace inline Babel helpers (classCallCheck, extends, etc.) with calls to moduleName.

regenerator

The configuration value is boolean type, the default value is true.
Whether to convert generator functions to use a regenerator runtime that does not pollute the global scope.

useESModules

The configuration value is boolean type, the default value is false.
When enabled, transforms will use helpers instead of @babel/plugin-transform-modules-commonjs. This allows for smaller builds in module systems like webpack, since it doesn't need to preserve commonjs semantics.

Analysis of usage scenarios and examples

Both @babel/preset-env and plugin-transform-runtime can be set to use corejs to process polyfill . Both have their own usage scenarios, and different configurations can be used during project development and class library development.

Don't configure core-js for both at the same time to avoid complex undesirable consequences.

Project Development

useBuiltIns uses usage . plugin-transform-runtime only uses its feature of removing inline multiplexed helper functions to reduce packaging size.

 { "presets": [ [ "@babel/preset-env", { "useBuiltIns": "usage", "corejs": { "version": 3, "proposals": false } } ] ], "plugins": [ [ "@babel/plugin-transform-runtime", { "corejs": false } ] ] }

Class library development

For class library development, try not to use polyfill that pollute the global environment, so @babel/preset-env only plays the function of syntax conversion, and polyfill are handled by plugin-transform-runtime . It is recommended to use core-js@3 , and do not use non-standardized characteristics.

 { "presets": ["@babel/preset-env"], "plugins": [ [ "@babel/plugin-transform-runtime", { "corejs": { "version": 3, "proposals": false }, "useESModules": true } ] ] }

Packaging Analysis

The test code is as follows:

 // syntax class Person {} typeof Person const array = [1, 2, 3] const fun = () => {} // api const a = Array.isArray([3, 5, 8]) const b = array.map(itm => itm * 2) const p1 = Promise.resolve(true) const p2 = Promise.reject(false) Promise.allSettled([p1, p2]).then(() => { console.log('then') }).catch(() => { console.log('catch') }).finally(() => { console.log('finally') })

Configure core-js via preset-env:

 "use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); require("core-js/modules/es.array.is-array.js"); require("core-js/modules/es.array.map.js"); require("core-js/modules/es.object.to-string.js"); require("core-js/modules/es.promise.js"); require("core-js/modules/es.promise.finally.js"); require("core-js/modules/es.array.iterator.js"); require("core-js/modules/esnext.promise.all-settled.js"); require("core-js/modules/es.string.iterator.js"); require("core-js/modules/web.dom-collections.iterator.js"); var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); // syntax var Person = /*#__PURE__*/(0, _createClass2["default"])(function Person() { (0, _classCallCheck2["default"])(this, Person); }); (0, _typeof2["default"])(Person); var array = [1, 2, 3]; var fun = function fun() {}; // api var a = Array.isArray([3, 5, 8]); var b = array.map(function (itm) { return itm * 2; }); var p1 = Promise.resolve(true); var p2 = Promise.reject(false); Promise.allSettled([p1, p2]).then(function () { console.log('then'); })["catch"](function () { console.log('catch'); })["finally"](function () { console.log('finally'); });

Configure core-js through plugin-transform-runtime:

 "use strict"; var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault"); var _isArray = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/array/is-array")); var _map = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/map")); var _promise = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/promise")); var _typeof2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/typeof")); var _createClass2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/createClass")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/classCallCheck")); // syntax var Person = /*#__PURE__*/(0, _createClass2["default"])(function Person() { (0, _classCallCheck2["default"])(this, Person); }); (0, _typeof2["default"])(Person); var array = [1, 2, 3]; var fun = function fun() {}; // api var a = (0, _isArray["default"])([3, 5, 8]); var b = (0, _map["default"])(array).call(array, function (itm) { return itm * 2; }); var p1 = _promise["default"].resolve(true); var p2 = _promise["default"].reject(false); _promise["default"].allSettled([p1, p2]).then(function () { console.log('then'); })["catch"](function () { console.log('catch'); })["finally"](function () { console.log('finally'); });

Through the code analysis after packaging, unnecessary polyfills will be introduced in the way of preset-env, and only the polyfills required by the current page will be introduced in the way of plugin-transform-runtime.


时倾
794 声望2.4k 粉丝

把梦想放在心中