乐趣区

关于前端:自动化兼容性检查和解决方案应用不会再白屏了

引言

对于前端开发者来说,caniuse网站是一个十分有用的工具,它能够帮忙咱们查问 JavaScript API 在不同浏览器版本中的兼容性状况。以 fetch 为例,咱们能够在网站上查到其兼容性如下图所示:

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

然而人工保障 API 的兼容性是不牢靠的,上面我分享一个实在产生的案例来分享本文的主题 自动化兼容性检查和解决方案

线上事变

最近产生了一起线上事变,让我深感可惜。事件是这样的,小飞是刚毕业不久的前端应届生,7 月份本该是他转正的日子。然而,不久前,因为他的一个小问题,导致线上 APP H5 页面呈现了白屏,造成了局部业务损失。小飞同学次要负责借贷业务,这类业务波及 C 端用户,而且波及金钱,所以问题的严重性显而易见。最终,这次事变导致他的转正申请未能通过,切实是遗憾。

事变起因

起初,小飞问我,该如何尽量避免这种白屏问题。他提到,在回归测试阶段,测试同学通知他没有问题,后果线上用户才反馈白屏问题。我的第一反馈是询问他是否有 JS 报错导致的问题。事实上,这的确是问题的本源。因为低端机型不反对某个 API,导致页面报错,从而呈现白屏问题。

那么,有没有方法在 CICD 流程中或者在代码开发中就能扫描到这种问题呢?除了监控零碎之外是否还有其余形式?实际上是有的。之前我写过一篇文章我给我的项目加了性能守卫插件,共事叫我早晨别睡的太死,提到了如何利用 eslint-plugin-compat 插件 来实现这种机制,从而防止相似线上生产事变的产生。应用这个插件,咱们能够在代码开发阶段就发现可能的兼容性问题,让开发者及时修复,防止将问题带入线上环境。

自动化兼容性查看

应用 eslint-plugin-compat 插件

eslint-plugin-compat 是一个弱小的工具,能够帮忙咱们查看代码中应用的个性在不同浏览器中的兼容性。以下是应用 eslint-plugin-compat 进行自动化兼容性查看的步骤:

装置插件:

npm install eslint-plugin-compat --save-dev

配置 ESLint:

在我的项目的.eslintrc.js 配置文件中增加插件:

module.exports = {
  // ...
  plugins: [
    // ...
    'compat'
  ],
  // ...
};

设置 browserslist:

通过应用 browserslist 配置,你能够确保你的我的项目在指标浏览器中都可能失常运行,并在开发阶段主动引入相应的 polyfill 或进行兼容性正告,从而节俭调试工夫,进步开发效率,并构建跨浏览器敌对的 Web 利用。无论是在古代浏览器中应用最新的个性,还是在旧版浏览器中提供兼容性反对,browserslist都能帮忙你轻松治理和配置我的项目的兼容性需要。

示例 .browserslistrc 配置如下:

# 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%
配置选项 形容
> 5% 寰球使用率超过 5% 的浏览器
last 2 major versions 最近两个次要版本的浏览器
IE 11 仅包含 Internet Explorer 11
iOS >= 11 iOS 零碎版本大于等于 11 的浏览器
not dead 排除曾经被认为是不再应用的浏览器
and_chr 78 特定版本的 Chrome 浏览器
and_ff 68 特定版本的 Firefox 浏览器
maintained node versions 以后被保护的 Node.js 版本
not IE 11 排除 Internet Explorer 11
development 开发环境配置,指定兼容性需要
production 生产环境配置,指定兼容性需要
last 1 chrome version 最近一个版本的 Chrome 浏览器
last 1 firefox version 最近一个版本的 Firefox 浏览器
> 0.2% 寰球使用率超过 0.2% 的浏览器

测试成果:

假如咱们有以下的代码示例main.js

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

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

运行 eslint 命令来查看代码的兼容性:

eslint main.js

如果浏览器版本反对 addEventListener,则不会报错。否则,会提醒相应的兼容性正告。

应用 eslint-plugin-builtin-compat 插件

eslint-plugin-builtin-compat是另一个用于查看浏览器兼容性的插件,它提供了一些额定的个性。

装置插件:

npm install eslint-plugin-builtin-compat --save-dev

配置 ESLint:

在我的项目的.eslintrc.js 配置文件中增加插件:

module.exports = {
  // ...
  plugins: [
    // ...
    'builtin-compat'
  ],
  // ...
};

配置查看脚本:

在 package.json 中增加查看脚本:

{
  "scripts": {
    // ...
    "compat-check": "eslint --no-eslintrc --ext .js main.js"
  }
}

运行查看脚本:

npm run compat-check

git 提交校验

为了确保代码在提交前曾经通过了兼容性查看,咱们能够应用 husky 工具来在 commit 前执行校验。

装置 husky:

npm install husky --save-dev

配置 husky:

在 package.json 中增加 pre-commit 钩子,以在提交前执行兼容性查看:

{
  "husky": {
    "hooks": {"pre-commit": "npm run compat-check"}
  }
}

CICD 校验

除了在 git 进行校验,咱们也能够在 cicd 流程进行校验,一旦不通过,就不通过MR

{
  "scripts": {"lint": "eslint . --ext .js"}
}
stage('Linting') {
    steps {sh 'npm run lint'}
}

三、应用 polyfill 解决兼容性问题

在某些状况下,即便通过兼容性查看,依然可能存在一些浏览器不反对的新个性。这时候,咱们能够应用 polyfill 来为这些浏览器提供缺失的性能。

手动 polyfill

装置第三方库:

在我的项目中装置须要的 polyfill 库,比方 core-js 或者 polyfill.io。

npm install core-js --save

写兼容性代码:

在须要兼容性反对的中央,引入相应的 polyfill 库,并编写对应的代码。

// 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);
  });
});

主动 polyfill

应用 Babel 来主动依据指标浏览器版本转换代码,并应用 babel-runtime 来抽离公共模块。

装置相干库:

npm install @babel/preset-env @babel/plugin-transform-runtime --save-dev

配置 Babel:

在我的项目的.babelrc 文件中配置 Babel:

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

按需引入 polyfill:

依据理论应用的新个性,Babel 会主动依据指标浏览器版本引入必要的 polyfill。

// 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);
  });
});

动静 polyfill 服务:

能够应用 polyfill.io 等服务来动静为不反对的浏览器提供 polyfill,以缩小页面加载的数据量。

<!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>

再谈 Babel

Babel 是一个 JavaScript 编译器, 为什么这么说,因为 babel 不会解决 Web API 啊,我过后也认为 babel 主动帮咱们做 polyfill,后果疏忽了Web API,babel 只会解决 ECMAScript 规范中的个性

Babel 是一个工具链,次要用于将采纳 ECMAScript 2015+ 语法编写的代码转换为向后兼容的 JavaScript 语法,以便可能运行在以后和旧版本的浏览器或其余环境中。

  • 语法转换
  • 通过 Polyfill 形式在指标环境中增加缺失的个性(通过引入第三方 polyfill 模块,例如 core-js)
  • 源码转换(codemods)

遇到的问题

在 chrome61 环境中报错 ResizeObserver is not a function。
经确认 ResizeObserver 个性最低反对 chrome64,于是将 babel 编译的指标版本设置为 chrome 61,但改报错仍未解决,通过一番查找,起因如下:

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).

参考出处

于是手动引入 resize-observer-pollyfill 问题就解决了

退出移动版