出了兼容性问题,被领导叼了

4 阅读5分钟

背景

项目上线后跑了应该有两三个月了,接到生产报事,页面进不去了,用户设备是iPhone8 iOS13.1,用户很气愤,领导也很不乐意,我也很气愤,刚来这项目组就被报事,艹太。但是要解决呀,怎么办?研究以前的代码,加配置呗。

浏览器兼容性问题是什么?

浏览器兼容性问题通常是指网页或 Web 应用在不同浏览器或版本中表现不一致的问题。说白了无非就是 css不兼容JS Api在旧版本浏览器中不兼容。

解决思路

  1. 明白目标浏览器范围
  2. 找个插件将现代 JS 转到 ES5
  3. 处理一下CSS的兼容性问题

解决方案

  1. 通过定义 .browserslistrc 明确目标浏览器范围
  2. 使用 Babel 将现代 JS 转到 ES5
  3. 使用 Autoprefixer 给 CSS 加厂商前缀

好了,开搞

.browserslistrc文件是什么

.browserslistrc 文件是一个配置文件,用于定义目标浏览器和Node.js版本的兼容性列表。这个文件被多个前端工具链和库所使用,如Babel、Autoprefixer、ESLint等,可以帮助我们确定需要转译或添加兼容性前缀的JavaScript和CSS代码版本。通过配置 .browserslistrc,我们可以精确地控制代码应该兼容哪些浏览器和设备,从而优化构建输出和减少最终包的大小。

.browserslistrc文件中可以配置的内容

  • ‌浏览器名称和版本‌:例如,last 2 Chrome versions 表示最新的两个Chrome浏览器版本。
  • ‌市场份额‌:如 > 1% in US 表示在美国市场份额超过1%的浏览器。
  • ‌年份‌:since 2017 表示自2017年以来发布的所有浏览器版本。
  • ‌特定浏览器‌:not IE 11 表示不包括IE 11浏览器。

个人项目中使用.browserslistrc配置

在个人日常办公项目中 .browserslistrc 文件配置如下:

> 0.2%
last 2 versions
Firefox ESR
not dead
IE 11

这个配置的含义是:

  • 支持全球使用率超过0.2%的浏览器。
  • 支持最新的两个浏览器版本。
  • 支持Firefox的Extended Support Release(ESR)版本。
  • 排除所有已经不被官方支持(dead)的浏览器。
  • 额外包含IE 11浏览器,尽管它可能不在其他条件内

Babel是什么

Babel 是一个广泛使用的 JavaScript 编译器/转译器,其核心作用是将 高版本 JavaScript(如 ES6+)转换为向后兼容的低版本代码(如 ES5),以确保代码能在旧版浏览器或环境中正常运行。

Babel的主要作用

1. 语法转换(Syntax Transformation)

将现代 JavaScript 语法(如 let/const、箭头函数、类、模板字符串、解构赋值等)转换为等价的 ES5 语法,以便在不支持新特性的浏览器中运行。

2. Polyfill 填充新 API

通过插件(如 @babel/polyfill 或 core-js),为旧环境提供对新增全局对象(如 Promise, Array.from, Map, Set)的支持。

3. 按需转换(基于目标环境)

结合 .browserslistrc 配置,@babel/preset-env 可根据指定的目标浏览器自动决定哪些特性需要转换,哪些可以保留原样。

4. 支持 TypeScript 和 JSX

Babel 提供了对 TypeScript(通过 @babel/preset-typescript)和 React 的 JSX 语法(通过 @babel/preset-react)的解析与转换能力,无需依赖其他编译工具。

5. 插件化架构,高度可扩展

Babel 支持丰富的插件生态,开发者可以自定义语法转换规则,比如:

  • 按需引入 polyfill(@babel/plugin-transform-runtime)
  • 移除调试代码(@babel/plugin-transform-remove-console)
  • 支持装饰器、私有属性等实验性语法

@babel/preset-env的核心配置

@babel/preset-env 的参数项数量很多,但大部分我们都用不到。我们只需要重点掌握四个参数项即可:targets、useBuiltIns、modules 和 corejs。

@babel/preset-env 的 targets 参数

该参数项的写法和.browserslistrc 配置是一样的,主要是为了定义目标浏览器。如果我们对 targets 参数进行了设置,那么就不会使用 .browserslistrc 配置了,为了减少多余的配置,我们推荐使用 .browserslistrc 配置。

@babel/preset-env 的 useBuiltIns 参数

useBuiltIns 项取值可以是usageentryfalse。如果该项不进行设置,则取默认值 false

  • 设置成 false 的时候会把所有的 polyfill 都引入到代码中,整个体积会变得很大。
  • 设置成 entry 则是会根据目标环境引入所需的 polyfill,需要手动引入;
  • 设置成 usage 则是会根据目标环境和代码的实际使用来引入所需的 polyfill。 此处我们推荐使用:useBuiltIns: usage 的设置。

@babel/preset-env 的 corejs 参数

该参数项的取值可以是 2 或 3,没有设置的时候取默认值为 2。这个参数只有 useBuiltIns 参数为 usage 或者 entry 时才会生效。在新版本的Babel中,建议使用 core-js@3

@babel/preset-env 的 modules 参数

指定模块的输出方式,默认值是 "auto",也可以设置为 "commonjs""umd""systemjs" 等。

个人项目中使用Babel的配置

在个人日常办公项目中 .babel.config.js 文件配置如下:

module.exports = {
  plugins: [
    // 适配某些构建流程中的模块元信息访问方式
    () => ({
      visitor: {
        MetaProperty(path) {
          path.replaceWithSourceString('process');
        },
      },
    })
  ],
  presets: [
    [
      '@babel/preset-env', {
        // targets: { esmodules: false, }, // 通过配置browserslist,来使用 browserslist 的配置
        useBuiltIns: "usage", // 配置按需引入polyfill
        corejs: 3
      }
    ],
    '@babel/preset-typescript'
  ],
};

Autoprefixer 的使用

vite.config.ts文件中css的部分,添加 autoprefixer 的配置。

css: {
  postcss: {
    plugins: [
      postCssPxToRem({
        // 这里的rootValue就是你的设计稿大小
        rootValue: 37.5,
        propList: ['*'],
      }),
      autoprefixer({
        overrideBrowserslist: [
          'Android 4.1',
          'iOS 7.1',
          'ff > 31',
          'Chrome > 69',
          'ie >= 8',
          '> 1%'
        ]
      }),
    ],
  },
},

总结

主要通过配置 .browserslistrc 明确目标浏览器范围,使用 Babel 将现代 JS 转到 ES5,主要用到的插件是 @babel/preset-env ,最后再使用 Autoprefixer 插件给 CSS 加厂商前缀。