Optimization of Babel – loader

Babel-loader is always the loader that handles the most tasks, especially during React development, there are a lot of JSX to parse and compile. Some optimizations can be made starting with the babel-Loader configuration items. The set of plug-ins used by babel-loader is mainly @babel/preset-env and @babel/preset- React.

@babel/preset-env

@babel/preset-env is a collection of plug-ins responsible for compiling JS code into more compatible lower versions of JS code.

Configuration items

Configuration items type The default value meaning
targets String|Array|Object {} Configure the browser version or nodeJS version
bugfixes Boolean false Depending on thetargetsSet, according totargetsTo compile the latest version of the syntax supported by the target browser; This will be enabled automatically with Babel 8
spec Boolean false Enabling more specifications leads to slower compilations
loose Boolean false Lax compilation rules. Normally, compilation follows ECMAScript 6 semantics as much as possible, but lax mode is lax and looks like handwritten code, see –Babel 6: loose mode
modules "amd"|"umd"|"systemjs"|"commonjs"|"cjs"|"auto"|false "auto" Rules for converting ES Module syntax to other types of modules
debug Boolean false Output plugin and Polyfill used to the console, this configuration is not subject to WebpackstatsThe influence of
include Array [] Customize the name of the plug-in
exclude Array [] Exclude plug-ins used
useBuiltIns "usage"|"entry"|false false Define how to handle polyfill
corejs 2.3.{version: 2|3,proposals: boolean} 2 Only in theuseBuiltIns: usageoruseBuiltIns: entryThe definitioncore-jsVersion,versionIt has to be the number 2 or 3
forceAllTransforms Boolean false Disabling all compilations
configPath String The current working directory of the Node.js process The configuration specifiesbrowserslistThe directory where the
ignoreBrowserslistConfig Boolean false Whether to ignorebrowserslistconfiguration
browserslistEnv Object undefined Configure for different development environmentsbrowserslist
shippedProposals Boolean false Whether to enable a proposal already supported by the browser

Configure modules

The modules configuration item by default determines whether the browser supports some features of ES Modules based on the caller inside Babel. For example, whether the browser supports static import or dynamic import() syntax. Choose to further convert ES Module to CommonJS require syntax.

Since the tree Shaking feature built into Webpack relies on static parsing of ES Modules, Modules are not supported at all in IE 11, so it is up to you to disable Modules.

Configure the targets

An earlier Version of Babel was preset, called babel-preset-latest, which is preset to automatically add a plugin according to the new features of the ES specification, saving the developer from having to preset separately. But just adding them would lead to more and more plug-ins, and as time goes on, most OF ES6 syntax is now supported by mainstream browsers, there is no need to use those plug-ins to compile, and the useless plug-ins left in preset will cause the compilation process of Babel to be slowed down. It is recommended to use @babel/preset-env instead of this preset.

@babel/preset-env helps developers transition from preset-latest, if targets are not configured in @babel/preset-env, it will compile all ES6+ JS code into ES5 by default. By enabling the @babel/preset-env debug option, you can clearly see how many plugins @babel/ Preset -env is used on the console. If targets are not set, the most preset plugin will be introduced as shown in the figure below.

In a development environment, these plugins are mostly unnecessary, and @babel/preset-env does not look up browserslist configuration. Even the default browserslist configuration must be configured in targets. This may be revisited in Babel 8.

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

The Targets field also supports the browserslist configuration as described above. The development environment always uses the latest version of Chrome, thus reducing the amount of plugin introduced by the development environment.

{
  targets: isDevelopment
		? "last 1 chrome version"
		: "> 1%, last 2 versions, Firefox ESR, ie >= 11, not dead",}Copy the code

Targets also supports the configuration of some special fields:

  • esmodulesDefault is:false, specify that the target browser supports ES Modules syntax if set totrue, thenbrowserslistThe configuration of the
  • node:"current" | true, specifying that the current version of Node is compiled
  • safari:"tp"Specifies that the technical preview version of Safari is compiled
  • browsers: Specify abrowserslistRule array, not recommended, as it may be removed in a future release

Configuration bugfixes

By default, @babel/preset-env or other Babel plugin will group ES syntax features, such as function arguments including default parameters, preset parameters, etc. If bugfixes is enabled, The @babel/preset-env selects different groups to compile to the nearest latest modern syntax supported by the target browser based on the targets compatibility range, which results in a significant reduction in the size of the compiled application, optimizing not only the webpack build speed, but also the generated code.

Configuration polyfill

The core – js profile

core-js#babelpreset-env

@babel/ Polyfill has been deprecated since version 7.4. Core-js is currently the dominant polyfill scheme.

Core-js itself comes in three versions:

  • Yarn add [email protected]: global injection version, which only needs to be imported globally at the code entry pointcore-jsCan be
  • Yarn add [email protected]: Module import version, need to introduce the corresponding Polyfill module file separately when using
  • core-js-bundle: Uses the script injection version

In addition, each version also has modules containing different features:

  • core-js(-pure)/es:esRepresents stable ES specification content
  • core-js(-pure)/stable:stableIncludes both stable WHATWG specification content and ES specification content
  • core-js(-pure)/features:featuresContains only the module-specific content of the individual syntax, for examplecore-js(-pure)/features/setContains onlySetData set related to polyfill

If you use the globally-injected version, you can import only globally in the project entry file. Global import automatically introduces polyfills based on the target environment, not on demand. You can also use Features to inject only as many polyfills as you need.

// Global injection
import 'core-js';

Array.from(new Set([1.2.3.2.1]));
[1[2.3], [4[5]]].flat(2);
Promise.resolve(32).then(x= > console.log(x));

// Introduce the required module through feature
import 'core-js/features/array/from';
import 'core-js/features/array/flat';
import 'core-js/features/set';
import 'core-js/features/promise';

Array.from(new Set([1.2.3.2.1]));
[1[2.3], [4[5]]].flat(2);
Promise.resolve(32).then(x= > console.log(x));
Copy the code

Import ‘core-js-pure’ cannot be used if using the pure version; In this global injection approach, specific modules need to be imported as needed; Pure version can be introduced on demand, but it is very troublesome to use, for example, two features, Set and array. from, need to find out how to introduce these two features.

import from from 'core-js-pure/features/array/from';
import flat from 'core-js-pure/features/array/flat';
import Set from 'core-js-pure/features/set';
import Promise from 'core-js-pure/features/promise';

from(new Set([1.2.3.2.1])); // => [1, 2, 3]
flat([1[2.3], [4[5]]].2); // => [1, 2, 3, 4, 5]
Promise.resolve(32).then(x= > console.log(x));
Copy the code

UseBuiltIns and corejs

Note: The useBuiltIns and Corejs properties of @babel/preset-env are not required if core-js-pure is used. The @babel/ plugin-transform-Runtime can be used to simplify the coding.

For globally injected versions, such as core-js@3 after installation, the @babel/preset-env corejs configuration item needs to be set first, and it is recommended to specify a smaller core-js version number, such as 3.6 instead of 3, because for corejs: 3. Modules added in smaller core-JS versions will not be added. By default, only the stable ES feature will be adopted. Polyfill will not be introduced for the specification content that is still in the state of the proposal, but corejs.proposals can enable support for the proposal content.

You must then specify useBuiltIns, otherwise no polyfills will be added.

For the global injection version of core-JS, specify corejs: “3.6” and useBuiltIns: “Entry”.

module: {
  rules: [{test: /\.m? js$/,
      exclude: /(node_modules|bower_components)/,
      use: {
        loader: 'babel-loader'.options: {
          presets: [
            '@babel/preset-env',
            {
              debug: true.// Enable the debug mode
              targets: 'ie >= 8'.bugfixes: true.modules: false.corejs: {
                version: 3.proposals: true,},useBuiltIns: 'entry',},],},},},]; }Copy the code

When useBuiltIns:”entry” is specified, all core-JS polyfills for targets are packed in. This is a nightmare! When I only used the two features Set and Array.from in the entrance, I packed them for 1 minute and generated a 150KB Polyfill chunk

import 'core-js';

console.log(Array.from(new Set([1.2.3.2.1)));Copy the code

When useBuiltIns:”usage” is specified, only the required polyfills are introduced according to the code, and the corresponding packaging time and chunk size are reduced considerably, to about 20KB.

UseBuiltIns: Usage is not stable until Babel 7.3, and sometimes required polyfills are not automatically added, so there may be some problems with older projects. As a better option for compatibility and on-demand introduction, the following combination of core-js-pure and @babel/ plugin-transform-Runtime can be used.

@babel/preset-react

@babel/preset- React preset is responsible for switching JSX and other grammars.

Configuration items

Configuration items type The default value meaning
runtime "Classic" or "automatic" "classic" Whether to automatically import JSX converted functions. Default: No
development Boolean false Whether to enable the development environment. Plug-ins for development assistance will be enabled for the development environment, for example:@babel/plugin-transform-react-jsx-self@babel/plugin-transform-react-jsx-source
throwIfNamespace Boolean false Whether using tag names in XML namespaces is a throw error; For example,<f:image />Form, although permitted by the JSX specification, is prohibited by default because the React JSX does not currently support it
importSource String react Sets the name of the function import source
pragma String React.createElement Replace the functions used when compiling JSX expressions
pragmaFrag String React.Fragment Set JSX Fragments syntactically converted functions
useBuiltIns Boolean false Whether to use the native built-in Polyfill instead of polyfill through another plug-in
useSpread Boolean false When apropsUse inline object instead of using Babel extension orObject.assignCopy the object

Inline object:

{
  (firstName = 'john'), (lastName = 'walter');
}
Copy the code

Configure @babel/preset- React for different environments to use development-assisted plug-ins in the development environment

module: {
  rules: [{test: /\.m? js$/,
      exclude: /(node_modules|bower_components)/,
      use: {
        loader: 'babel-loader'.options: {
          presets: [
            '@babel/preset-env'['@babel/preset-react',
              {
                development: isDevelopment, // Development environment
                useBuiltIns: true,},],],},},},]; }Copy the code

@babel/plugin-transform-runtime

Babel inserts very small auxiliary code into the source code that needs to be compiled, and sometimes this code is duplicated, increasing the size of the code. This plugin can disable Babel’s automatic runtime injection for each file with @babel/plugin-transform-runtime. Then install @babel/ Runtime to introduce Babel’s auxiliary code as a separate dependency module, so that the compiled code can avoid repeated auxiliary code and reduce the size of the code.

yarn add @babel/plugin-transform-runtime @babel/runtime -D
Copy the code
module.exports = {
  module: {
    rules: [{test: /\.m? js$/,
        exclude: /(node_modules)/,
        loader: 'babel-loader'.options: {
          presets: ['@babel/preset-env'].plugins: ['@babel/plugin-transform-runtime'],},},],},};Copy the code

@babel/ plugin-transform-Runtime performs three tasks:

  • When using generators or asynchrony in a projectasyncFunction is automatically introduced@babel/plugin-transform-runtime
  • usecore-jsPolyfill can be passedcorejsconfiguration
  • By default, the helper code for Babel is removed@babel/runtime/helpersInstead, the optimization to reduce the size of the code mentioned above, can be passedhelpersSelect Enable or not

Configuration items

Configuration items type The default value meaning
corejs false

2, 3

{version: 2 or 3, proposals: Boolean}
false The specifiedcore-jsThe version of the library
helpers Boolean true Whether to switch the auxiliary code inserted by Babel to a module call
regenerator Boolean true Whether to convert generator functions to run-time generators that do not pollute the global scope
useESModules Boolean false Whether to use auxiliary code conversion does not pass@babel/plugin-transform-modules-commonjsThe code of
absoluteRuntime BooleanorString false
version String false The specified@babel/runtime-corejsThe version of the

polyfill

Another use of this plugin is to polyfill with the Pure version of the core-js-Pure library to simplify the import syntax of core-js-Pure. For example, the syntax of importing modules is automatically converted.

// The original core-js-pure usage
import from from 'core-js-pure/stable/array/from';
import flat from 'core-js-pure/stable/array/flat';
import Set from 'core-js-pure/stable/set';
import Promise from 'core-js-pure/stable/promise';

from(new Set([1.2.3.2.1]));
flat([1[2.3], [4[5]]].2);
Promise.resolve(32).then(x= > console.log(x));

// introduce a simplified version of @babel/plugin-transform-runtime
Array.from(new Set([1.2.3.2.1]));
[1[2.3], [4[5]]].flat(2);
Promise.resolve(32).then(x= > console.log(x));
Copy the code

Using @babel/ plugin-transform-Runtime in conjunction with core-js-pure requires the installation of the corresponding @babel/ Runtime library

corejs Corresponding installed library
false yarn add @babel/runtime
2 yarn add @babel/runtime-corejs2
3 yarn add @babel/runtime-corejs3

By default, @babel/ plugin-transform-Runtime will only take the content of the WHATWG specification that is stable or the CONTENT of the ES specification, but it can be specified through the corejs.proposals configuration item that it has not yet adopted.

Note: @babel/plugin-transform-runtime and @babel/preset-env both have corejs configuration items, don’t confuse them, and don’t set them at the same time, otherwise it will clash.

module.exports = {
  module: {
    rules: [{test: /\.m? js$/,
        exclude: /(node_modules)/,
        loader: 'babel-loader'.options: {
          presets: ['@babel/preset-env'].plugins: [['@babel/plugin-transform-runtime',
              {
                corejs: {
                  version: 3.proposals: true,},},],],},},},};Copy the code