Background of Compatible Scenarios

the problem we are facing

  • Although many JS grammars have reached the stage of official release, we cannot use them with confidence due to the different degrees of browser support.
  • Some of the syntaxes that have already reached stage3 and we also want to try to use them. How to run them normally?

ideal scene

We can safely write js code without considering other issues.

How to achieve

At compile time, a method is used to convert the syntax not supported by the browser into the syntax supported by the browser, so that the code can run normally.

Code compatibility through syntax conversion

Front-end projects usually use babel to convert js code. At the time of writing this article, the latest version is babel v7 , and the following solutions will only be introduced in this version.

clear goal

Before implementing the solution, we need to think about a few questions:

  1. Which syntaxes need to be compatible: According to TC39 , you used the syntax of stage-x (x: 1-4)
  2. Different browsers have different degrees of syntax support. Which browsers do you need to deal with?
  3. The code-compatible processing method is to introduce on-demand or all-in (each has its own advantages and disadvantages, which will be introduced next)

Thinking 🤔 3 min...

Scheme realization

polyfill solution

scheme
@babel/preset-env + corejs@3

Features

  • Through the configuration of useBuiltIns , compatibility can be achieved by on-demand loading and full loading
  • Will pollute the global: add api on global and instance
  • Support target browser settings: through targets or browserslist, but achieve compatibility under specific browsers and reduce code size


core-js: Javascript standard syntax implementation library
@babel/preset-env

Notes

  • @babel/preset-env is compatible with stage4, which is the official version. If you want to use the stage3 syntax, you need to introduce the corresponding plugin in bablerc plugins
  • You need to configure targets or browserslist for specific browser syntax compatibility

Method 1: Import all
.babelrc file content:

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "entry",
        "targets":"> 1%, not dead", // 根据情况自己设置
        "corejs": {
          "version": 3,
          "proposals": true
        }
      }
    ]
  ],
  "plugins": [
    [
      "@babel/plugin-transform-runtime",
      {
        "corejs": false
      }
    ]
  ]
}

Entry file index.js:

import 'core-js/stable';
import 'regenerator-runtime/runtime';
// 入口文件代码
  • core-js/stable will introduce all polyfills. The advantage is that there is no need to worry about the syntax of the existing library. The disadvantage is that the code is bulky. If you want to reduce the volume, you can also introduce it as needed, such as import 'core-js/stable/array/find';
  • regenerator-runtime/runtime : generator of runtime and async function

Method 2: Introduce
.babelrc file content:

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "usage",
        "targets":"> 1%, not dead", // 根据情况自己设置
        "corejs": {
          "version": 3,
          "proposals": true
        }
      }
    ]
  ],
  "plugins": [
    [
      "@babel/plugin-transform-runtime",
      {
        "corejs": false
      }
    ]
  ]
}

runtime solution

Scheme
@babel/preset-env + @babel/runtime-corejs3 + @babel/plugin-transform-runtime

Features

  • Will not pollute the global: @babel/plugin-transform-runtime plugin is compatible by simulating the api and will not pollute the global, so it is more suitable for Library authors to use
  • Only supports import on demand
  • The api used will be replaced, targets and browserslist are not supported

introduction

  • Still need @babel/preset-env to convert the syntax
  • @babel/runtime-corejs3: The main library used to simulate the implementation of api functions
  • @babel/plugin-transform-runtime : Implement on-demand reference to the module in @babel/runtime-corejs3

note
After switching to corejs@3, the runtime solution can also simulate instance methods, such as array.includes , which can already be implemented without introducing additional polyfills

specific implementation
.babelrc file content:

{
  "presets": [
    [
      "@babel/preset-env",
     {
        "useBuiltIns": false,
        "targets":"> 1%, not dead", // 根据情况自己设置
     }
    ]
  ],
  "plugins": [
    [
      "@babel/plugin-transform-runtime",
      {
        "corejs": {
          "version": 3,
          "proposals": true
        }
      }
    ]
  ]
}

Summarize

Currently, babel has two options for dealing with compatibility issues:

  • @babel/preset-env + corejs@3 implements syntax conversion, adds api on global and instance, supports full loading and on-demand loading, we refer to polyfill scheme for short;
  • @babel/preset-env + @babel/runtime-corejs3 + @babel/plugin-transform-runtime implements syntax conversion and analog replacement api, and only supports on-demand loading, which we refer to as the runtime solution.

Both solutions rely on the core package corejs@3, but the modules they depend on are different, resulting in different implementations. Both options have their pros and cons:

  • The obvious disadvantage of the polyfill scheme is that it will cause global pollution and inject redundant tool code; the advantage is that compatibility processing can be selectively performed according to the browser's support for new features;
  • Although the runtime solution solves the shortcomings of the polyfill solution, it cannot selectively perform compatibility processing according to the browser's support for new features, that is to say, as long as the api is identified in the code, and the api also has core- In the js-pure package, it will be automatically replaced, which will cause some unnecessary conversions, thereby increasing the code size.

Therefore, the polyfill solution is more suitable for business projects that run alone. If you want to develop some third-party tool libraries for others to use, it is recommended that you use the runtime solution to deal with the compatibility solution, so as not to affect the user's operating environment.

Wait a minute, think of a better solution: Isn't it perfect that the runtime solution also supports api targets 🤔... There is really one in the experimental stage: babel-polyfills

QA

Priority and default configuration of babelrc files tags, ignoreBrowserConfig and browserslist

  • Configuration: targets > browserslist
  • Setting ignoreBrowserConfig:true will no longer read the browserslist configuration by default
  • When neither exists, refer to No targets [probably means that all grammars after ES2015 will be converted to ES5]

@babel/polyfill vs @babel/preset-env

  • @babel/polyfill is a product of the era of babel@6 and core-js@2, similar to "useBuiltIns":"entry" of @babel/preset-env, but does not support browserslist and is currently deprecated.
  • @babel/preset-env supports browserslist, and there are many new features, which are necessary for compatibility

The role of babel-plugin-transform-runtime

There are two main functions:

  • Reuse the code of the helper injected through Babel to reduce code redundancy
  • Implement code compatibility by simulating api [runtime scheme]

The specific configuration of the two schemes

As above, you can also see here: https://developer.aliyun.com/article/783477

Can the runtime scheme be configured using browserslist?

  • The full method for the runtime scheme is: @babel/preset-env + @babel/runtime-corejs3 + @babel/plugin-transform-runtime .
  • @babel/plugin-transform-runtime is for processing the api part, the syntax conversion still needs @babel/preset-env , so under the runtime scheme, target still works for syntax conversion, but it is invalid for the API part

Reference article


specialCoder
2.2k 声望168 粉丝

前端 设计 摄影 文学