ServiceWorker MIME Type Error ('text/html') on register (React)

Viewed 16606

The current behavior:

Service worker does not register due to the below error

The expected behavior:

Service worker registers


Details

Posted as a github issue: https://github.com/facebook/create-react-app/issues/8593

Service worker is giving the following error when attempting to register:

Error during service worker registration:
DOMException: Failed to register a ServiceWorker for scope ('http://localhost:3000/') with script ('http://localhost:3000/sw.js'):
The script has an unsupported MIME type ('text/html'). console. @ index.js:1

sw.js is showing in the sources tab of the Chrome dev tools, but not registering.

React version: 16.12.0

Error Message:

Error during service worker registration: DOMException:
Failed to register a ServiceWorker for scope ('http://localhost:3000/') with script ('http://localhost:3000/sw.js'):
The script has an unsupported MIME type ('text/html').

Failed ServiceWorker in Chrome's Inspect Tab: Chrome Error


Steps To Reproduce:

Register a Service Worker in React (change from unregister to register, or place SW code directly in index.html, or use a simpler SW. All cause the same error when running, in either dev or a build react app.)

SW Example:

export function register() {
  if ("serviceWorker" in navigator) {
    navigator.serviceWorker
      .register("./sw.js")
      .then(function(registration) {
        // Successful registration
        console.log(
          "Hooray. Registration successful, scope is:",
          registration.scope
        );
      })
      .catch(function(error) {
        // Failed registration, service worker won’t be installed
        console.log(
          "Whoops. Service worker registration failed, error:",
          error
        );
      });
  }
}

Also, `http://localhost:3000/sw.js when using the default SW from React returns this HTML:

enter image description here

Using the code sample above returns index.html (default 404, http://localhost:3000/) when trying to access http://localhost:3000/sw.js


Suggested fixes:

Move sw.js to public folder, gives this error: Public folder error


Is there a way to change the header (from text/html to application/javascript) for specifically sw.js when served to the browser in React?

I tried following some Medium articles on registering custom serviceWorkers in React, to no avail...

3 Answers

When running webpack dev server, it renders default index.html for missing resource.

If you use your browser to load http://localhost:3000/sw.js, you will actually see a rendered react app (started by the index.html). That's why the mime type is html, not javascript.

This fallback to index.html is designed to support SPA with front-end routes. For example /product/123/reviews has no such html file in backend, the JS SPA app takes care of it in front-end.

Why your file is missing? I guess you created that file in the root folder of your project.

Webpack dev server doesn't serve from that root folder.

Move your sw.js into public/ folder of your project, it will be served up as expected.

This may be a duplicate of this one 61776698

Main thing you need to know: Create the serviceWorker inside public folder in order to be treated as .js file and not text/html file.

Then register that service in your index.js

Step 1, create public/sw.js

self.addEventListener('message', async (event) => {
  console.log('Got message in the service worker', event);
});

Step 2, create src/sw-register.js

export default function LocalServiceWorkerRegister() {
  const swPath = `${process.env.PUBLIC_URL}/sw-build.js`;
  if ('serviceWorker' in navigator && process.env.NODE_ENV !== 'production') {
    window.addEventListener('load', function () {
      navigator.serviceWorker.register(swPath).then(registration => {
        console.log('Service worker registered');
      });
    });
  }
}

Step 3, in src/index.js, add these two lines

import LocalServiceWorkerRegister from './sw-register';
...
LocalServiceWorkerRegister();

You can change some things for your needs, but with those changes, you should be able to work with a custom service worker in a create-react-app application

You can write code at server side to handle sw.js file. below is nodejs code which intercept sw.js file request and read from folder and send back to browser.

app.get('/sw.js', (req, res) => {
  if (__DEVELOPMENT__) {
    http.get('http://localhost:4001/static/build/sw.js', (r) => {
      res.set({
        'Content-Type': 'text/javascript',
        'Cache-Control': 'max-age=0, no-cache, no-store, must-revalidate'
      });
      r.setEncoding('utf8');
      r.pipe(res);
    }).on('error', (e) => {
      console.error(`Error in sending sw.js in dev mode : ${e.message}`);
    });
  } else {
    res.setHeader('Cache-Control', 'max-age=0, no-cache, no-store, must-revalidate');
    res.sendFile('sw.js', { root: path.join(__ROOT_DIRECTORY__, 'assets', 'build') }); // eslint-disable-line no-undef
  }
});
Related