React项目低版本Chromium中Service Worker异常问题求助
React项目Service Worker在Chromium 49(Windows XP)下的兼容问题
环境与异常表现
- 正常运行环境:Chromium 102.0.5005.63 + Windows 7
- 异常环境:Chromium 49.0.2623.75 + Windows XP
- 报错信息:
Uncaught TypeError: Cannot read property of 'set' of undefined
ServiceWorker script evaluation failed
前置说明
- 项目通过HTTPS协议加载
- Chromium 49规范上支持Service Worker,且生产环境中
"serviceWorker" in navigator返回true - 已更新
package.json中的browserslist配置,执行npx browserslist确认chrome 49在列表内:
"browserslist": { "production": [ "> 0.04%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] },
- 自定义的
service-worker.js和serviceWorkerRegistration.js中未使用.set方法
更新1:报错根源定位
报错来自Workbox生成的createCacheKey方法,其中cacheKeyURL.searchParams在Chromium 49中为undefined,相关代码片段:
var REVISION_SEARCH_PARAM = '__WB_REVISION__'; function createCacheKey(entry) { // ... 省略其他逻辑代码 ... // 构建带版本号的缓存键URL var cacheKeyURL = new URL(url, location.href); var originalURL = new URL(url, location.href); cacheKeyURL.searchParams.set(REVISION_SEARCH_PARAM, revision); return { cacheKey: cacheKeyURL.href, url: originalURL.href }; }
更新2:临时修复后的新问题
手动在build目录的service-worker.js中添加兼容代码后,原报错消失,但出现ServiceWorker failed to install无额外提示,临时代码:
var cacheKeyURL = new URL(url, location.href); var originalURL = new URL(url, location.href); // 临时兼容代码 if (!cacheKeyURL['searchParams']){ var urlParams = new URLSearchParams(location.search); cacheKeyURL.searchParams = urlParams; } cacheKeyURL.searchParams.set(REVISION_SEARCH_PARAM, revision);
解决方案
1. 修复searchParams兼容逻辑
Chromium 49的URL对象原生不支持searchParams属性,且该属性为只读,强行赋值会导致后续异常。正确的兼容方式是直接拼接参数到URL的search部分:
var cacheKeyURL = new URL(url, location.href); var originalURL = new URL(url, location.href); // 兼容Chrome 49的searchParams缺失问题 if (!cacheKeyURL.searchParams) { // 判断原有search是否存在,决定用?还是&分隔 var separator = cacheKeyURL.search ? '&' : '?'; cacheKeyURL.href += separator + REVISION_SEARCH_PARAM + '=' + encodeURIComponent(revision); } else { cacheKeyURL.searchParams.set(REVISION_SEARCH_PARAM, revision); } return { cacheKey: cacheKeyURL.href, url: originalURL.href };
2. 自动注入兼容代码到构建流程
由于service-worker.js是Workbox自动生成的,不建议直接修改node_modules源码,推荐以下两种自动注入方式:
方式1:通过Webpack自定义插件(适用于Create React App)
- 项目根目录创建
workbox-compat-plugin.js:
module.exports = class InjectSearchParamsFix { generateBundle(options, bundle) { const swFile = bundle['service-worker.js']; if (!swFile) return; // 匹配目标代码片段并替换 const targetCode = `var cacheKeyURL = new URL(url, location.href); var originalURL = new URL(url, location.href); cacheKeyURL.searchParams.set(REVISION_SEARCH_PARAM, revision);`; const fixedCode = `var cacheKeyURL = new URL(url, location.href); var originalURL = new URL(url, location.href); // 兼容Chrome 49的searchParams缺失问题 if (!cacheKeyURL.searchParams) { var separator = cacheKeyURL.search ? '&' : '?'; cacheKeyURL.href += separator + REVISION_SEARCH_PARAM + '=' + encodeURIComponent(revision); } else { cacheKeyURL.searchParams.set(REVISION_SEARCH_PARAM, revision); }`; swFile.source = swFile.source.replace(targetCode, fixedCode); } };
- 使用
react-app-rewired修改Webpack配置:- 安装依赖:
npm install react-app-rewired --save-dev - 创建
config-overrides.js:
- 安装依赖:
const InjectSearchParamsFix = require('./workbox-compat-plugin'); module.exports = function override(config) { // 添加自定义插件到Webpack插件列表 config.plugins.push(new InjectSearchParamsFix()); return config; };
- 修改
package.json的脚本:
"scripts": { "start": "react-app-rewired start", "build": "react-app-rewired build", "test": "react-app-rewired test" }
方式2:Post-Build脚本(简单直接)
- 项目根目录创建
fix-sw-compat.js:
const fs = require('fs'); const path = require('path'); const swPath = path.join(__dirname, 'build', 'service-worker.js'); let swCode = fs.readFileSync(swPath, 'utf8'); const targetCode = `var cacheKeyURL = new URL(url, location.href); var originalURL = new URL(url, location.href); cacheKeyURL.searchParams.set(REVISION_SEARCH_PARAM, revision);`; const fixedCode = `var cacheKeyURL = new URL(url, location.href); var originalURL = new URL(url, location.href); // 兼容Chrome 49的searchParams缺失问题 if (!cacheKeyURL.searchParams) { var separator = cacheKeyURL.search ? '&' : '?'; cacheKeyURL.href += separator + REVISION_SEARCH_PARAM + '=' + encodeURIComponent(revision); } else { cacheKeyURL.searchParams.set(REVISION_SEARCH_PARAM, revision); }`; swCode = swCode.replace(targetCode, fixedCode); fs.writeFileSync(swPath, swCode); console.log('Service Worker Chrome 49兼容修复完成');
- 修改
package.json的build脚本:
"scripts": { "build": "react-scripts build && node fix-sw-compat.js" }
内容的提问来源于stack exchange,提问作者M.H.
相关产品推荐
相关产品推荐

