Service worker errors when restarted only in chrome: Failed to load the script unexpectedly

Viewed 660

Problem

  • On Firefox the below service worker can be installed, and stopped and started fine.
  • On Chrome, the below test service worker install fines, works perfectly until one closes and opens the browser, or in the SW dev tools clicks stop and then click start.

Intro

I created a service worker, debugged it with chrome on local and it worked fine. I deployed it to a website, and I see the errors in the image below (only in Chrome, with Firefox its working fine):

/static/core.jslib/sw.min.js:1 Failed to load the script unexpectedly
/static/core.jslib/sw.min.js:1 Failed to load the script unexpectedly

With chrome if I click start the service worker it immediately stops. With Firefox it runs awhile before stopping (expected).

Environment

  • OS: Ubuntu 20.04, and on Windows 10
  • Browsers
    • Chrome: Version 97.0.4692.99 (Official Build) (64-bit)
    • Also occurs on Chromium 92.0.451598
  • Its not in offline mode on Chrome under Network or Application
  • The only clue I have is the first time the SW installs, its works fine. But then if I close the browser and reopen it, I see these errors and the SW stops. Sound like a global state issue, whereby variable/object arent present when worker starts up again, however I don't have any global state, as you can see, just a few functions.
  • No extensions, all disabled
  • Tried on 2 different computers,
  • The sw.min.js below is not minified, but pasted in unminified.

enter image description here

I have simplified my service worker down to this, so now I am quite sure its not my code, but something chromium is doing:

/ INSTALL -------
async function install() {
    console.log("SW: Installing ...");
}
async function handleInstall(event) {
    event.waitUntil(install());
}
self.addEventListener("install", handleInstall);

// ACTIVATE -------
async function activate() {
    console.log("SW: Activated");
}
async function handleActivate(event) {
    event.waitUntil(activate());
}
self.addEventListener("activate", handleActivate);

// FETCH -------
async function swFetch(event) {
    //console.log('SW: FETCH - RELEASE TIMESTAMP', RELEASE_TIMESTAMP)
    const response = await fetch(event.request);
    console.log("SW: FETCHED ", event.request.url);
    return response
}
async function handleFetch(event) {
    return event.respondWith(swFetch(event));
}
self.addEventListener("fetch", handleFetch);

Note: When it works, the sw.min.js file appears under sources (when it installs), close and open the browser again and then this is not shown: enter image description here

PS Running on Ubuntu 20.04. Maybe its to do with where it stores the Service workers in linux.

I even added a fetch call to get the file and print it out just before it registeres the service work to verify it can access the file, and it always is okay:

Fetched /static/core.jslib/sw.min.js 
Responsebody: (...)bodyUsed: falseheaders: HeadersĀ {}ok: trueredirected: falsestatus: 200statusText: ""type: "basic"url: "https://www.demo..../static/core.jslib/sw.min.js"[[Prototype]]: Response
swregister.min.50eb376e2ddc.js:1 SW: Registered - At scope https://www.demo..../
/static/core.jslib/sw.min.js:1 Failed to load the script unexpectedly
/static/core.jslib/sw.min.js:1 Failed to load the script unexpectedly

Error Order

The strange thing is, the error appears as one clicks to navigate elsewhere. The console log below was generated as follows:

  1. Cleared the console.
  2. Then clicked a link
  3. The error was shown immediately
  4. Then it shows the note about navigating
  5. Then it registered the service worker.

So I don't thing its a fetch issue, I think its internal storage of the service worker file, that chrome can't access.

enter image description here

Chrome Service worker internals

chrome://serviceworker-internals/` shows the service worker:
Scope: https://www.demo..../
Registration ID: 287
Navigation preload enabled: false
Navigation preload header length: 4
Active worker:
Installation Status: ACTIVATED
Running Status: STOPPED
Fetch handler existence: EXISTS
Script: https://www.demo..../static/core.jslib/sw.min.js
Version ID: 649
Renderer process ID: 0
Renderer thread ID: -1
DevTools agent route ID: -2
Log:

And if I click start it shows:

Console: {"lineNumber":0,"message":"Failed to load the script unexpectedly",
"message_level":3,"sourceIdentifier":1,"sourceURL":"https://www.demo.../static/core.jslib/sw.min.js"}

Whereas other peoples service workers start and run for awhile.

Response Headers

Here are the response headers for sw.min.js

# Here are the response headers for:
date: Tue, 25 Jan 2022 18:15:44 GMT
etag: "61f03d46-350"
last-modified: Tue, 25 Jan 2022 18:11:18 GMT
server: notepad.exe
service-worker-allowed: /

Manifest.json

{
    "name": "Cube",
    "short_name": "Cube",
    "icons": [
        {
            "src": "/static/core.pwa/img/android-chrome-192x192.png",
            "sizes": "192x192",
            "type": "image/png",
            "purpose": "any"
        },
        {
            "src": "/static/core.pwa/img/android-chrome-512x512.png",
            "sizes": "512x512",
            "type": "image/png",
            "purpose": "any"
        },
        {
            "src": "/static/core.pwa/img/maskable_icon.png",
            "sizes": "1024x1024",
            "type": "image/png",
            "purpose": "maskable"
        }
    ],
    "theme_color": "#212121",
    "background_color": "#ffffff",
    "display": "standalone",
    "start_url": "/"
}
1 Answers

Update

The folks at Chromium figured out it was the MIME content type header: https://bugs.chromium.org/p/chromium/issues/detail?id=1292379#c17

In nginx I changed the header from :

  • content-type: application/javascript; charset=utf-8

to

  • content-type: application/javascript

Now it works!

Original Answer

When registering the service worker, I set the type as module. Apparently it means "crash when restarted" in Chrome.

const options = {
    scope: "/",
    // type: "module",  <-- needed to comment this out
};
const result = await navigator.serviceWorker.register(swPath, options);

Apparently Chrome does not seem to support module type service workers, when I checked the support table, there seemed to be good support.

Related