兼容性大冒险
我将分享如何在项目的开发过程中应对兼容性问题的经验。通过精心选择的解决方案,我确保项目在各种浏览器中都能流畅运行。
项目背景
项目名称:"被装申领"
系统:Web 和 Admin
技术栈:Vite + React 18(Web),Vite + Vue 3(Admin)
部署环境:Chrome 72.0.3626.7(32 位)
在项目部署阶段,我面临了兼容性挑战。不同浏览器版本的差异以及一些新特性的引入,可能导致在某些环境中出现意料之外的问题。特别是在老旧浏览器中,一些新的 JavaScript 语法和特性可能无法正常工作,导致代码在运行时出现错误。为了确保项目能在各种浏览器中稳定运行,我们需要寻找并应用切实可行的解决方案。
本文档将重点介绍我在项目中所遇到的兼容性问题,以及我为了解决这些问题而采取的一系列策略,确保项目能够在各种浏览器中流畅运行。
问题一:Uncaught ReferenceError: globalThis is not defined at overlay.ts:140
"globalThis 是 ECMAScript 2020 引入的全局对象,用于提供一种标准的方式来获取全局作用域(包括浏览器和服务器)。在支持该特性的环境中,你可以使用 globalThis 来获取全局对象,而不管你的代码在什么上下文中运行。"
出现错误由于浏览器版本不支持: 虽然 globalThis 是 ECMAScript 2020 引入的特性,但是旧版本的浏览器可能不支持它。运行的浏览器是 Chrome 70+ 这可能是导致错误的原因之一。
解决方案包括:
- 多数情况下推荐:添加一个 globalThis 的 polyfill 来确保在不支持它的环境中也能正常使用。也可以使用像 globalthis 这样的库来提供这个功能。
// 1. 安装 core-js
npm install --save core-js
// 2. 在项目入口文件中引入 'core-js/features/global-this.js'
import 'core-js/features/global-this.js'
- 检查浏览器兼容性: 确保你的项目的目标浏览器版本是否支持 globalThis。如果不支持的话,可以考虑使用其他方式来访问全局对象。比如在浏览器中可以使用 window 对象。
// 在不支持原生 globalThis 的浏览器中提供一个近似的替代方案
document.documentElement
.appendChild(
Object.assign(document.createElement('script'), {
textContent: 'window.globalThis = window'
})
)
.remove()
- 更新浏览器
问题二:TypeError: Promise.allSettled is not a function
这个错误表明在你的代码中使用了 Promise.allSettled 方法,但是当前的环境不支持这个方法。Promise.allSettled 是 ES2020 中引入的 Promise 方法,用于等待所有给定的 Promise 都已被解决(settled),并返回一个包含结果的数组。该方法在 Chrome 76+ 中支持。
解决方案包括:
- Polyfill Promise.allSettled: 可以使用像 core-js 或 es6-promise 这样的库来提供缺失的 Promise 功能。
import 'core-js/es/promise'
-
降级方案: 可以考虑使用类似于 Promise.all(Chrome 32+)的方式实现降级方案。
-
更新浏览器
问题三:Uncaught SyntaxError: Unexpected token ?
如果代码中使用了类似可选链操作符 ?. 或空值合并操作符 ?? 这样的新语法,而你的目标浏览器不支持这些语法,就会出现 "Unexpected token" 错误。
解决方案包括:
-
经验告诉我,在兼容旧版本浏览器的项目中,总会有些意想不到的问题。建议直接梭哈
import 'core-js'
,导入 core-js 所有新特性 api 以省去大部分麻烦。然后就会发现错误仍未消失,原因大概是:`?.`(可选链操作符)和 `??`(空值合并操作符)是 ES2020 中引入的两个新语法,它们不是普通的方法、函数或对象的标准特性,所以 core-js 可能不会自动提供对它们的兼容性支持。
这时候只有另辟蹊径了,可以通过 babel、legacy 等插件来解决。
// 原始代码
const person = {
name: 'zusheng'
}
console.log(person?.name)
// babel 处理后
var person = {
name: 'zusheng'
}
console.log(person === null || person === void 0 ? void 0 : person.name)
在 vite 生态中,可以很方便的使用 '@vitejs/plugin-legacy' 插件来解决这个问题。
// 1. 安装 '@vitejs/plugin-legacy'
npm install --save-dev @vitejs/plugin-legacy
// 2. 在 vite.config.js 中配置
import { defineConfig } from 'vite'
import legacy from '@vitejs/plugin-legacy'
export default defineConfig({
plugins: [
legacy({
renderLegacyChunks: true,
polyfills: true,
// 目标浏览器为 chrome 70+
targets: ['defaults', 'chrome >= 70'],
})
]
})
- 更新浏览器
总结
更新浏览器是最解决兼容性问题最方便有效的方法。对于那些无法或不愿意更新浏览器的用户,我们可以通过引入 core-js 或其他 polyfill 来提供缺失的功能。如果你的项目使用了新的语法,比如可选链操作符 ?. 或空值合并操作符 ??,可能需要使用 babel 或 legacy 插件来解决这个问题。