Automated compatibility checking and resolution: no more white screens for apps

introduction

For front-end developers, the caniuse website is a very useful tool, which can help us query the compatibility of JavaScript APIs in different browser versions. Taking fetch as an example, we can check its compatibility on the website as shown in the figure below:

image.png

 

js复制代码fetch('http://domain/service', { method: 'GET' })
  .then(response => response.json())
  .then(json => console.log(json))
  .catch(error => console.error('error:', error));

However, manually ensuring API compatibility is unreliable. Below I will share a real case to share the topic of this article, automated compatibility checking and solutions.

online accident

An online accident happened recently, which I deeply regret. The thing is like this, Xiaofei is a front-end fresher who just graduated, and July was supposed to be the day when he became a full-time employee. However, not long ago, due to a small problem of his, a white screen appeared on the H5 page of the online APP, causing some business losses. Xiaofei is mainly responsible for the loan business. This type of business involves C-end users and involves money, so the seriousness of the problem is self-evident. In the end, this accident caused his application for regularization to fail, which was a pity.

Cause of accident

Later, Xiaofei asked me how to avoid this white screen problem. He mentioned that during the regression testing phase, the test classmates told him that there was no problem, but online users reported the white screen problem. My first reaction was to ask him if there was any problem caused by JS error reporting. In fact, this is indeed the root of the problem. Because the low-end model does not support a certain API, the page reports an error, resulting in a white screen problem.

So, is there any way to scan for this kind of problem during the CICD process or during code development? Is there any other way besides monitoring the system? Actually there is. I wrote an article before where I added a performance guard plug-in to the project. My colleagues told me not to sleep too hard at night and mentioned how to use the eslint-plugin-compat plug-in to implement this mechanism to avoid similar online production accidents. occur. Using this plug-in, we can discover possible compatibility issues during the code development stage, allowing developers to fix them in time to avoid bringing problems into the online environment.

Automated compatibility checks

Use the eslint-plugin-compat plugin

eslint-plugin-compat is a powerful tool that can help us check the compatibility of features used in code in different browsers. Here are the steps for automated compatibility checking using eslint-plugin-compat:

Install plugin:

bash复制代码npm install eslint-plugin-compat --save-dev

Configure ESLint:

Add the plugin in the project's .eslintrc.js configuration file:

javascript复制代码module.exports = {
  // ...
  plugins: [
    // ...
    'compat'
  ],
  // ...
};

Set browserslist:

By using browserslist configuration, you can ensure that your project can run normally in the target browsers, and automatically introduce the corresponding polyfill or compatibility warning during the development phase, thereby saving debugging time, improving development efficiency, and building cross-browser Friendly web application. Whether you're using the latest features in modern browsers or providing compatibility support in older browsers, browserslist helps you easily manage and configure your project's compatibility needs.

Example .browserslistrc configuration is as follows:

js复制代码# Browsers that have more than 5% global usage
> 5% 

# Last 2 versions of major browsers (including Chrome, Firefox, Safari, and Edge)
last 2 major versions 

# Specific browser versions
IE 11 
iOS >= 11
not dead

# Browsers used in specific countries
and_chr 78
and_ff 68

# Browsers used in specific environments
maintained node versions
not IE 11

# Development and production environment specific targets
development
  last 1 chrome version
  last 1 firefox version
production
  > 0.2%

Configuration options

describe

> 5%

Browsers used by more than 5% of the world

last 2 major versions

The last two major versions of browsers

IE 11

Includes Internet Explorer 11 only

iOS >= 11

Browsers with iOS system version 11 or above

not dead

Exclude browsers that have been deemed no longer in use

and_chr 78

Specific version of Chrome browser

and_ff 68

Specific version of Firefox browser

maintained node versions

The currently maintained version of Node.js

not IE 11

Exclude Internet Explorer 11

development

Development environment configuration, specifying compatibility requirements

production

Production environment configuration, specifying compatibility requirements

last 1 chrome version

The latest version of the Chrome browser

last 1 firefox version

A recent version of the Firefox browser

> 0.2%

Browsers with a global usage rate of more than 0.2%

Test results:

Suppose we have the following code example main.js:

javascript复制代码// main.js
const button = document.getElementById('my-button');

button.addEventListener('click', () => {
  console.log('Button clicked!');
});

Run the eslint command to check code compatibility:

bash复制代码eslint main.js

If the browser version supports addEventListener, no error will be reported. Otherwise, the corresponding compatibility warning will be prompted.

Use the eslint-plugin-builtin-compat plugin

eslint-plugin-builtin-compat is another plugin for checking browser compatibility that provides some extra features.

Install plugin:

bash复制代码npm install eslint-plugin-builtin-compat --save-dev

Configure ESLint:

Add the plugin in the project's .eslintrc.js configuration file:

javascript复制代码module.exports = {
  // ...
  plugins: [
    // ...
    'builtin-compat'
  ],
  // ...
};

Configuration check script:

Add the check script in package.json:

json复制代码{
  "scripts": {
    // ...
    "compat-check": "eslint --no-eslintrc --ext .js main.js"
  }
}

Run the check script:

bash复制代码npm run compat-check

git commit verification

In order to ensure that the code has passed the compatibility check before submission, we can use the husky tool to perform verification before commit.

Install husky:

bash复制代码npm install husky --save-dev

Configure husky:

Add a pre-commit hook in package.json to perform compatibility checks before committing:

json复制代码{
  "husky": {
    "hooks": {
      "pre-commit": "npm run compat-check"
    }
  }
}

CICD check

In addition to verifying in git, we can also verify in the cicd process. Once it fails, the MR will not be passed.

js复制代码{
  "scripts": {
    "lint": "eslint . --ext .js"
  }
}

js复制代码stage('Linting') {
    steps {
        sh 'npm run lint'
    }
}

3. Use polyfill to solve compatibility issues

In some cases, even after compatibility checks, there may still be new features that are not supported by the browser. At this time, we can use polyfills to provide missing functionality for these browsers.

Manual polyfill

Install third-party libraries:

Install the required polyfill library in the project, such as core-js or polyfill.io.

bash复制代码npm install core-js --save

Write compatibility code:

Where compatibility support is needed, introduce the corresponding polyfill library and write the corresponding code.

javascript复制代码// main.js
import 'core-js/features/promise';

const button = document.getElementById('my-button');

button.addEventListener('click', () => {
  // 使用新特性Promise
  new Promise((resolve) => {
    setTimeout(() => {
      resolve('Button clicked!');
    }, 1000);
  }).then((message) => {
    console.log(message);
  });
});

Automatic polyfill

Use Babel to automatically convert code according to the target browser version, and use babel-runtime to extract common modules.

Install related libraries:

bash复制代码npm install @babel/preset-env @babel/plugin-transform-runtime --save-dev

Configure Babel:

Configure Babel in the project's .babelrc file:

json复制代码{
  "presets": [
    ["@babel/preset-env", {
      "useBuiltIns": "usage",
      "corejs": 3
    }]
  ],
  "plugins": ["@babel/plugin-transform-runtime"]
}

Introduce polyfill as needed:

Based on the new features actually used, Babel will automatically introduce the necessary polyfills according to the target browser version.

javascript复制代码// main.js
const button = document.getElementById('my-button');

button.addEventListener('click', () => {
  // 使用新特性Promise
  new Promise((resolve) => {
    setTimeout(() => {
      resolve('Button clicked!');
    }, 1000);
  }).then((message) => {
    console.log(message);
  });
});

Dynamic polyfill service:

Services such as polyfill.io can be used to dynamically provide polyfills for unsupported browsers to reduce the amount of data loaded by the page.

html复制代码<!DOCTYPE html>
<html>
<head>
  <title>Polyfill Example</title>
</head>
<body>
  <button id="my-button">Click Me</button>
  <!-- 加载polyfill.io服务 -->
  <script src="https://polyfill.io/v3/polyfill.min.js"></script>
  <script src="main.js"></script>
</body>
</html>

Let’s talk about Babel again

Babel is a JavaScript compiler. Why do you say that? Because babel will not process Web API. I also thought that babel would automatically help us with polyfill. As a result, we ignored Web API. Babel will only process the features in the ECMAScript standard.

Babel is a tool chain mainly used to convert code written in ECMAScript 2015+ syntax into backward-compatible JavaScript syntax so that it can run in current and older versions of browsers or other environments.

  • Grammar conversion
  • Add missing features in the target environment through Polyfill (by introducing third-party polyfill modules, such as core-js)
  • Source code conversion (codemods)

Problems encountered

In the chrome61 environment, an error is reported that ResizeObserver is not a function.
It was confirmed that the ResizeObserver feature supports at least chrome64, so the target version compiled by babel was set to chrome 61. However, the error was still not resolved after changing the error. After some searches, the reasons are as follows:

Babel only polyfills ECMAScript features.

What is ECMAScript? It is the core of the JavaScript that you can use in the browser. Browsers implements ECMAScript, and on top of it there are lots of expansions (Dom objects, service workers, Ajax, ...). ResizeObserver is one of those expansions.

How can you know if a feature is part of ECMAScript or not?
I'd suggest searching for that function on MDN, and look at the Specifications section (ArrayBuffer example).

 

Guess you like

Origin blog.csdn.net/Cipher_Y/article/details/132103440