I'm using create-react-app with an express server.
create-react-app
has a pre-configured ServiceWorker that caches local assets (https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#making-a-progressive-web-app).
The problem I encountered when I tried to publish on my server is that the service-worker.js
file was available, but I was getting errors in my browser console when it tried to register it.
On Firefox, I got this error:
Error during service worker registration:
TypeError: ServiceWorker script at https://my-domain.com/service-worker.js for scope https://my-domain.com/ encountered an error during installation.
On Chrome, I get the more descriptive error:
Error during service worker registration: DOMException: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/html').
Sure enough, if I look in the Network tab of my developer tools and search for the service-worker.js
file, I can see that it has the wrong MIME type in the HTTP headers.
I could not understand, though, why it has the wrong MIME type?
This is a very common design pattern. However, it means that any requests for unknown text files initially get redirected to index. html , and therefore return with the MIME type of "text/html" , even if it's actually a JavaScript or SVG or some other kind of plaintext file.
A media type (also known as a Multipurpose Internet Mail Extensions or MIME type) indicates the nature and format of a document, file, or assortment of bytes. MIME types are defined and standardized in IETF's RFC 6838.
In React, service workers are automatically added when you create your application through the create-react-app command, through SWPrecacheWebpackPlugin . Service workers ensure that the network is not a bottleneck to serve new requests.
In my Express server application, I have one wildcard (asterisk / *) route that redirects to index.html
:
// Load React App // Serve HTML file for production if (env.name === "production") { app.get("*", function response(req, res) { res.sendFile(path.join(__dirname, "public", "index.html")); }); }
This is a very common design pattern. However, it means that any requests for unknown text files initially get redirected to index.html
, and therefore return with the MIME type of "text/html"
, even if it's actually a JavaScript or SVG or some other kind of plaintext file.
The solution I found was to add a specific route for service-worker.js
before the wildcard route:
app.get("/service-worker.js", (req, res) => { res.sendFile(path.resolve(__dirname, "public", "service-worker.js")); }); app.get("*", function response(req, res) { res.sendFile(path.join(__dirname, "public", "index.html")); });
Now, when the browser looks for service-worker.js
, Express will return it with the correct MIME type.
(Note that if you try adding the service-worker.js
route after the wildcard, it won't work because the wildcard route will override.)
Replacing:
'/service-worker.js'
with:
'./service-worker.js' // Add a dot before slash.
solved my similar issue.
(in navigator.serviceWorker.register('/service-worker.js')
)
Or maybe you need:
'%PUBLIC_URL%/serviceworker.js'
Thank @DanielLord for his comment.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With