reactjsgoogle-chromeservice-workerchromiumservice-worker-config

My service worker is not working as expected


I'm using Service Worker in my React-JS project. Our project runs in 2 combinations of Browsers and an Operation System.

  1. Chromium-102.0.5005.63 and Windows 7

  2. Chromium-49.0.2623.75 and Windows XP

Service worker works fine in Chromium-102.0.5005.63 and Windows 7, but it's not working in Chromium-49.0.2623.75 and Windows XP, throwing the following error:

Uncaught TypeError: Cannot read property of 'set' of undefined
ServiceWorker script evaluation failed

A few things to mention:

1. Project URL load under https

2. Chromium-49.0.2623.75 supports Service Worker as mentioned in the specifications

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

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

3. "serviceWorker" in navigator returns true in Chromium-49.0.2623.75 and running on production mode

4. browserslist is updated and defined as follows in 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"
    ]
  },

When I use npx browserslist I can see chrome 49 in the list.

5. I'm not using any .set in service-worker.js and serviceWorkerRegistration.js

UPDATE 1: Cannot read property of 'set' of undefined is caused by the following method in service-worker.js. cacheKeyURL.searchParams is undefined.

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

You can see service-worker.js in here: https://drive.google.com/file/d/13bESH2QRG-y_s5WyZjX51FjP-_kC8vmC/view?usp=sharing

UPDATE 2: It seems the URL object works differently in chrome 49 and 102. I added the following code manually to service-worker.js (inside the build directory) and I no longer receive the "Cannot read property of 'set' of undefined" error instead I get "ServiceWorker failed to install" and I have no clue why since there is no information provided.

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);

By the way, How can I add "//This Part" to the original service-worker.js?

Can you please help me out?!


Solution

  • I'm little late to answer, But I would like to extend accepted @M.H.'s answer

    From the mozilla-docs It states

    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.

    And you are accesing the searchParams as <URL_instance>['searchParams']. This doesn't work on all scenarios, this works only when you have key , value pair.

    So it is preferred to use the . dot operator.

    Further from docs:

    enter image description here

    enter image description here

    Both URL() and searchParams() has complete comptability over all the device.

    Change your following code which fetches using key

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

    to use dot operator

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

    Hope it helps and adds more value to the accepted answer.