开发者问题收集

我的 Service Worker 未按预期工作

2022-12-26
311

我在我的 React-JS 项目中使用 Service Worker。我们的项目在两种浏览器和操作系统的组合下运行。

  1. Chromium-102.0.5005.63 和 Windows 7

  2. Chromium-49.0.2623.75 和 Windows XP

Service Worker 在 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

需要提及的几点:

1. https 下加载项目 URL

2. Chromium-49.0.2623.75 支持规范中提到的 Service Worker

参考 1: https://caniuse.com/?search=service%20worker

参考2: https://blog.chromium.org/2016/02/chrome-49-beta-css-custom-properties.html

3. 在 Chromium-49.0.2623.75 中,在生产模式下运行时,navigator 中的“serviceWorker”返回 true

4. browserslist 已更新,定义如下 package.json

"browserslist": {
    "production": [
      "> 0.04%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },

当我使用 npx browserslist 时,我可以在列表中看到 chrome 49

5. 我没有在 service-worker.jsserviceWorkerRegistration.js 中使用任何 .set

更新 1: 无法读取未定义的“set”属性 是由 service-worker.js 中的以下方法引起的。 cacheKeyURL.searchParams 未定义。

var REVISION_SEARCH_PARAM = '__WB_REVISION__';
/**
 * Converts a manifest entry into a versioned URL suitable for precaching.
 *
 * @param {Object|string} entry
 * @return {string} A URL with versioning info.
 *
 * @private
 * @memberof workbox-precaching
 */

function createCacheKey(entry) {
  if (!entry) {
    throw new WorkboxError_WorkboxError('add-to-cache-list-unexpected-type', {
      entry: entry
    });
  } // If a precache manifest entry is a string, it's assumed to be a versioned
  // URL, like '/app.abcd1234.js'. Return as-is.


  if (typeof entry === 'string') {
    var urlObject = new URL(entry, location.href);
    return {
      cacheKey: urlObject.href,
      url: urlObject.href
    };
  }

  var revision = entry.revision,
      url = entry.url;

  if (!url) {
    throw new WorkboxError_WorkboxError('add-to-cache-list-unexpected-type', {
      entry: entry
    });
  } // If there's just a URL and no revision, then it's also assumed to be a
  // versioned URL.


  if (!revision) {
    var urlObject = new URL(url, location.href);
    return {
      cacheKey: urlObject.href,
      url: urlObject.href
    };
  } // Otherwise, construct a properly versioned URL using the custom Workbox
  // search parameter along with the revision info.


  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
  };
}
;// CONCATENATED MODULE: ./node_modules/workbox-precaching/utils/PrecacheInstallReportPlugin.js

您可以在此处查看 service-worker.js: https://drive.google.com/file/d/13bESH2QRG-y_s5WyZjX51FjP-_kC8vmC/view?usp=sharing

更新 2: 看来 URL 对象在 chrome 49 和 102 中的工作方式不同。 我手动将以下代码添加到 service-worker.js(在构建目录中),我不再收到“无法读取未定义的‘set’属性”错误,而是出现“ServiceWorker 安装失败”的情况,由于没有提供任何信息,我不知道为什么。

var cacheKeyURL = new URL(url, location.href);
  var originalURL = new URL(url, location.href);

//This Part
  if (!cacheKeyURL['searchParams']){
    var urlParams = new URLSearchParams(location.search);
    cacheKeyURL.searchParams = urlParams;
  }

  cacheKeyURL.searchParams.set(REVISION_SEARCH_PARAM, revision);

顺便问一下,我怎样才能将“//This Part”添加到原始 service-worker.js 中?

你能帮帮我吗?!

2个回答

我回答得有点晚了,但我想扩展已接受的@M.H.的答案

来自 mozilla-docs 它指出

If a browser doesn't yet support the URL() constructor , you can access a URL object using the Window interface's URL property. Be sure to check to see if any of your target browsers require this to be prefixed.

并且您正在将 searchParams 作为 <URL_instance>['searchParams'] 访问。这并不适用于所有情况,仅当您具有 key , value 对时才有效。

因此,最好使用 . 点运算符。

来自文档的更多内容:

在此处输入图像描述

在此处输入图像描述

URL() 和 searchParams() 在所有设备上都具有完全兼容性。

更改以下代码使用 key 获取

if (!cacheKeyURL['searchParams']){    👈 instead of using the instance variable
    var urlParams = new URLSearchParams(location.search);
    cacheKeyURL.searchParams = urlParams;
  }

使用 dot 运算符

if (!URL.prototype.searchParams) {     👈 try to access using prototype 
   URL.prototype.searchParams = new URLSearchParams();
}

希望它能有所帮助,并为接受的答案增加更多价值。

krishnaacharyaa
2023-01-04

在 chrome 49 中,问题出在 URL 原型和 waitUntil()

添加以下代码修复 URL 问题:

if (!URL.prototype.searchParams) {
   URL.prototype.searchParams = new URLSearchParams();
}

使用 async-wait-until 同步运行 waitUntil() (而不是异步)

M.H.
2022-12-31