项目css / js的兼容性next项目实践处理

[复制链接]
发表于 10 小时前 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
之前写过一篇前端兼容性的文章,那篇没管 CSS 的处理。这一篇把 CSS 兼容和 JS 兼容一起讲:先把兼容性版本定下来,再用 .browserslistrc 统一声明目标环境,JS 侧靠 polyfill 补齐,CSS 侧靠 postcss-preset-env 加 autoprefixer 处理前缀,最后在构建产物里核对生成结果。

一、先确定要兼容哪些版本

第一步是定兼容性底线版本。我们的兼容性以 APP H5 的兼容版本为准,也就是最低要支持这些:
  1. ios >= 13
  2. android >= 9
  3. chrome >= 107
复制代码

二、在项目根目录建 .browserslistrc

配置内容大致就下面这样:
  1. ios >= 13
  2. android >= 9
  3. chrome >= 107
复制代码

配置完可以跑一下 npx browserslist 验证一下。



三、JS 兼容:polyfill 怎么引

针对单个 API 手动引 polyfill

可以直接上 https://cdnjs.cloudflare.com/polyfill/ 这个网站,想给某个 API 生成垫片就直接生成,然后用 CDN 引入,这样能最大粒度地控制引入范围。

用 babel-preset-env 自动按需引入

官网写得很清楚:https://www.babeljs.cn/docs/babel-preset-env 。默认情况下,@babel/preset-env 会读取 browserslist 配置文件,配置项平时都用默认值,重点把 useBuiltIns 设成 usage。
  1. {
  2.   "presets": [
  3.     [
  4.       "@babel/preset-env",
  5.       {
  6.         "useBuiltIns": "usage",
  7.         "corejs": 3,
  8.         "modules": false // 保留ES模块语法,便于Tree Shaking
  9.         // "debug": true // 可以开发环境显示polyfill信息调试
  10.       }
  11.     ]
  12.   ],
  13. }
复制代码

Babel 会自动扫代码里用到的 ES 新特性,只为用到的特性按需引入 core-js 的 polyfill(corejs 一定要设成 3)。如果用 useBuiltIns: "entry",就需要在入口文件里手动引入 core-js。

几个坑


  • 注意 babel/preset-env 和 core-js 的版本问题。一开始我想验证 Object.hasOwn 这个 API 的 polyfill 结果,就在代码里写了几个 Object.hasOwn,结果怎么搜都搜不到 has-own 文件被引入,查了一下这个 API 是 ES2022 才引入的,非常新,所以 core-js 版本低于 3.xxx 的话就 polyfill 不了这个 API。
  • next 设置里的坑。我在 next/babel 的配置里反复试了很多次都不行,也不确定是不是包版本的问题。一开始的配置是这样,我甚至为了放大效果直接把 targets 配上了,生成出来的结果还是没有 polyfill。

    一气之下(也不是),我直接在顶层引入 preset-env,像下面这样,忽然就好了。

    build 的时候打开 debug,控制台会有提示:



浏览器 API 要特殊处理

Babel/preset-env 只负责 JS 和 ES6 语法转换,不管浏览器 DOM/Web API,比如 IntersectionObserver、fetch、requestIdleCallback 这些,Babel 没法自动给它们补 polyfill。怎么判断一个 API 能不能靠 preset-env 处理?


  • (有点麻烦)查 core-js 的文档:https://github.com/zloirock/core-js
  • 查 MDN 文档,看这个 API 属不属于 ECMAScript 标准
  • 一般来说,凡是 window.xxx 或 document.xxx 相关的 API,Babel preset-env 都不会自动 polyfill


推荐写法:
  1. if ('IntersectionObserver' in window) {
  2.   // 使用原生API
  3. } else {
  4.   // 加载polyfill
  5.   import('intersection-observer');
  6. }
复制代码

构建产物要核对

生成的 polyfill 文件可以去 build 产物里找一下确认。



四、CSS 兼容怎么处理

用 postcss-loader(postcss 是一个转换 CSS 语法的工具)配合 autoprefixer 自动加各浏览器前缀,cssnano 负责压缩生成的 CSS。装这几个依赖:
  1. yarn add postcss postcss-preset-env cssnano
复制代码

其实 browsers 那一项不写也行,会自动读 .browserslistrc 里的内容。
  1. // postcss.config.js
  2. module.exports = {
  3.   plugins: [
  4.     require('postcss-preset-env')({
  5.       // browsers: ['ios >= 13', 'android >= 9', 'chrome >= 107'],
  6.       stage: 3, // 稳定阶段的CSS特性
  7.       features: {
  8.         'nesting-rules': true, // 启用嵌套规则
  9.         'custom-properties': {
  10.           preserve: false, // 完全转换CSS变量
  11.         },
  12.         'media-query-ranges': true, // 支持媒体查询范围语法
  13.         'logical-properties-and-values': true, // 逻辑属性支持
  14.       },
  15.       autoprefixer: {
  16.         grid: 'no-autoplace', // Chrome 107+ 不需要grid前缀
  17.         // overrideBrowserslist: ['ios >= 13', 'android >= 9', 'chrome >= 107'] 自动读取,不用配
  18.       }
  19.       // debug: true, // 输出转换日志
  20.     }),
  21.     require('cssnano')({
  22.       preset: 'default'
  23.     })
  24.   ]
  25. }
  26. /**
  27. * grid: 'no-autoplace'
  28. * false:完全不处理 Grid 前缀(不推荐)
  29. * true:处理所有 Grid 相关前缀(包括 IE 的旧语法)
  30. * 'no-autoplace':只处理不涉及自动布局的 Grid 属性
  31. */
复制代码

注意 window 上挂的 DOM API 只能手写补全,Babel 帮不上忙,写完记得在真机上过一遍。

编辑提示

先定 .browserslistrc 再动构建配置,顺序反了容易白改一轮;core-js 记得锁 3.x,这是 polyfill 悄悄失效最常见的坑。
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表