In my current project using webpack with (workbox-webpack-plugin) and workbox (with workbox-window) I have encountered an error where the serviceworker will never respond to messages when the page is loaded at a "deep url", like "/my-path/is-nested".
It will work on "/my-path".
In a minimal reproducible environment, this is supposed to happen.
- In a new tab, app is accessed (e.g. via
https://my-app.my-name.company-dev-envs.cloud/some-unique-id) - ServiceWorker gets registered via workbox (
.register()) - upon registration,
messageSWis used to ask for the SWs "version" - ServiceWorker responds using
event.ports[0].postMessagewith a string indicating the version
Is the site accessed in a "deep" path, like /some-unique-id/test, the messaging will never work.
Workbox does successfully "register" - but no events will be fired (except externalactivated when Update on Reload in the Application > Service Worker Tab is selected)
The serviceworker will be reported as "active and running" with no other service workers displayed. It seems to handle fetches okay too. Only messages and events never respond/fire via the wb Workbox Window instance.
The "application" tab reports the service worker as active and running:

index.js (main entry for application)
/* globals window, System */
import './offline';
// [...]
offline.js
import { Workbox } from 'workbox-window';
if ('serviceWorker' in navigator) {
const wb = new Workbox('./sw.js');
const attachDebugEventHandlers = (events) => {
events.forEach((eventName) => {
wb.addEventListener(eventName, () => {
console.log(`[workbox sw] ${eventName} triggered`);
});
});
};
attachDebugEventHandlers([
'activated',
'controlling',
'externalactivated',
'externalinstalling',
'externalwaiting',
'installed',
'message',
'redundant',
'waiting',
]);
wb.register()
.then((registration) => {
console.log('workbox sw register successful');
console.log("sending message")
wb.messageSW({ type: 'GET_VERSION' }).then((ver) => console.log(`[workbox sw] version reported as ${ver}`))
})
.catch((err) => {
console.error('[workbox sw] could not activate sw', err);
});
sw.js
const SW_VERSION = '1.0.0';
console.log("sw loaded")
import {createHandlerBoundToURL, precacheAndRoute} from 'workbox-precaching';
import { NavigationRoute, registerRoute } from 'workbox-routing'
// auto generate from webpack manifest
precacheAndRoute(self.__WB_MANIFEST, {
// Ignore all URL parameters.
ignoreURLParametersMatching: [/.*/] // main.js is loaded with a version hash
});
self.addEventListener('message', event => {
console.log(`[Message] event: `, event.data);
});
self.addEventListener('install', function(event) {
event.waitUntil(self.skipWaiting());
});
self.addEventListener('activate', (event) => {
event.waitUntil(self.clients.claim())
})
addEventListener('message', (event) => {
console.log("message")
if (event.data && event.data.type) {
if (event.data.type === 'GET_VERSION') {
event.ports[0].postMessage(SW_VERSION);
}
}
})
const handler = createHandlerBoundToURL('/index.html');
const navigationRoute = new NavigationRoute(handler);
registerRoute(navigationRoute);
webpack.config.js (shortened for brevity)
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WorkboxPlugin = require('workbox-webpack-plugin');
module.exports = {
devtool: 'eval-source-map',
module: {
rules: [
{
test: /\.(jsx?)$/,
include: [
path.resolve(__dirname, 'src'),
],
use: ['babel-loader'],
},
// [...] (style loading)
{
test: /\.html$/,
use: [
{
loader: 'html-loader',
},
],
},
],
},
devServer: {
historyApiFallback: true,
disableHostCheck: true
},
plugins: [
// [...]
new HtmlWebpackPlugin({
template: path.resolve(__dirname, 'src/html/index.html')
}),
// [...]
new WorkboxPlugin.InjectManifest({
swSrc: './src/sw.js',
swDest: 'sw.js',
maximumFileSizeToCacheInBytes: 12 * 1024 * 1024,
}),
],
};
Versions used:
"webpack": "^4.33.0",
"webpack-cli": "^3.3.2",
"workbox-window": "^5.1.3"
"workbox-webpack-plugin": "^5.1.3"
I was able to solve it myself. The issue was of course that the path to
./sw.jsis not correct when the user navigates to a subpath.https://my-website.com/a-subpath/a-resourcedoes not resolve./sw.jstohttps://my-website.com/sw.jsbut rather tohttps://my-website.com/a-subpath/sw.jsThis was a very dumb mistake but hopefully somebody can be helped with this answer. Perhaps it would be helpful if
workbox-windowdidn't resolve correctly as if the registration were a success, but rejected the./sw.jspath.