Feature Request Description:
I'm using workbox-webpack-plugin's GenerateSW. But it creates a precache manifest file resulting to the following code:
/**
* Welcome to your Workbox-powered service worker!
*
* You'll need to register this file in your web app and you should
* disable HTTP caching for this file too.
* See https://goo.gl/nhQhGp
*
* The rest of the code is auto-generated. Please don't update this file
* directly; instead, make changes to your Workbox build configuration
* and re-run your build process.
* See https://goo.gl/2aRDsh
*/
importScripts("workbox-v3.6.3/workbox-sw.js");
workbox.setConfig({modulePathPrefix: "workbox-v3.6.3"});
importScripts(
"precache-manifest.4d330e4e1240ee5970dbef2d1c1a1fd7.js"
);
/**
* The workboxSW.precacheAndRoute() method efficiently caches and responds to
* requests for URLs in the manifest.
* See https://goo.gl/S9QRab
*/
self.__precacheManifest = [].concat(self.__precacheManifest || []);
workbox.precaching.suppressWarnings();
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});
What I want is to remove importScripts("precache-manifest.4147d0eae38244e105572db91f23fa97.js"); and totally inject the contents of precache-manifest inside of the service worker resulting to the following code:
/**
* Welcome to your Workbox-powered service worker!
*
* You'll need to register this file in your web app and you should
* disable HTTP caching for this file too.
* See https://goo.gl/nhQhGp
*
* The rest of the code is auto-generated. Please don't update this file
* directly; instead, make changes to your Workbox build configuration
* and re-run your build process.
* See https://goo.gl/2aRDsh
*/
importScripts("workbox-v3.6.3/workbox-sw.js");
workbox.setConfig({modulePathPrefix: "workbox-v3.6.3"});
self.__precacheManifest = [
{
"url": "css/file2.d39cd1945dcec8bba59a.css"
},
{
"url": "js/file.d39cd1945dcec8bba59a.js"
}
];
/**
* The workboxSW.precacheAndRoute() method efficiently caches and responds to
* requests for URLs in the manifest.
* See https://goo.gl/S9QRab
*/
workbox.precaching.suppressWarnings();
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});
I'm not sure if it already exists, I'm looking at the issues to see if someone else has opened a similar issue but I also couldn't search for one.
Here's my config btw:
new workboxWebpackPlugin.GenerateSW({
swDest: 'serviceWorker.js',
importWorkboxFrom: 'local',
excludeChunks: ['runtime', 'main.css']
})
Splitting up the manifest into a separate asset was a deliberate design decision made when we rolled out workbox-webpack-plugin, and is a different approach from what earlier tools, like sw-precache-webpack-plugin used.
So, I mean, it's conceptually possible, but folks from the community using webpack seemed to want it the other way around, which motivated the choice in Workbox.
Is the current approach breaking anything for you? Or is this just a matter of personal preference?
It's breaking updates. When I release new updates, the updates doesn't reflect on the site immediately. The service worker is still serving the old files instead of the new files. In fact, most of the time I have to clear my cache manually.
I think it's best to provide both as an option instead of removing one for the sake of the other.
I recently changed my configurations to:
new workboxWebpackPlugin.GenerateSW({
swDest: 'serviceWorker.js',
importWorkboxFrom: 'local',
excludeChunks: ['main.css'],
skipWaiting: true,
clientsClaim: true
})
In hopes that it would help resolve the problem. But the problem persisted.
This is how I register my service worker:
if ('serviceWorker' in navigator) {
addPassiveListener(window, 'load', () => {
window.navigator.serviceWorker
.register('serviceWorker.js')
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
installingWorker.onstatechange = () => {
if (
installingWorker.state === 'installed' &&
window.navigator.serviceWorker.controller
) {
console.log('new contents available');
}
};
};
})
.catch(err => {
// eslint-disable-next-line
console.log(`Could not register service worker > ${err.message}`);
});
});
} else {
// eslint-disable-next-line
console.log('Could not register service worker > unsupported');
}
That's the expected behavior of using precaching鈥攖he new resources won't be shown immediately, since the old resources are loaded in a cache-first manner.
I think what you're seeing is independent from the question of whether or not the precache manifest is inlined vs. imported.
There's some discussion of the benefits of precaching here, and UI patterns for prompting users to update can be found here.
If you're not satisfied with the cache-first behavior that comes with precaching, using a runtime caching strategy for your assets is another option.
I'm inclined to close this issue鈥攈opefully the above links give you the context you need to decide whether or not to use precaching. If you're seeing buggy behavior or something along those lines, we can reopen.
Maybe it should do cache-first when the files required are actually up-to-date on the cache. I am already prompting the user when a new version is available, so he can reload the page. Even that takes some time to appear and after reloading the page after that appears, the update still does not reflect immediately. Especially on installed PWAs. I literally have to uninstall and add to homescreen again just to get the updated version of the site. Can't workbox precache route and do staleWhileRevalidate? I assume it already knows how to do that since the precache-manifest json file would give it the new files which would have different hash names.
There are a number of trade-offs. Since it's directly relevant to your feedback, and since folks might not click through to the Stack Overflow answer, here's what I've previously written about precaching:
Using stale-while-revalidate for all of your assets, as well as for your HTML, is definitely a legitimate approach. It means that you don't have to do anything special as part of your build process, for instance, which could be nice in some scenarios.
Whenever you're using a strategy that reads from the cache, whether it's via precaching or stale-while-revalidate, there's going to be some sort of revalidation step to ensure that you don't end up serving out of date responses indefinitely.
If you use Workbox's precaching, that revalidation is efficient, in that the browser only needs to make a single request for your generated service-worker.js file, and that response serves as the source of truth for whether anything precached actually changed. Assuming your precached assets don't change that frequently, the majority of the time your service-worker.js will be identical to the last time it was retrieved, and there won't be any further bandwidth or CPU cycles used on updating.
If you use runtime caching with a stale-while-revalidate policy for everything, then that "while-revalidate" step happens for each and every response. You'll get the "stale" response back to the page almost immediately, so your overall performance should still be good, but you're incurring extra requests made by your service worker "in the background" to re-fetch each URL, and update the cache. There's an increase in bandwidth and CPU cycles used in this approach.
Apart from using additional resources, another reason you might prefer precaching to stale-while-revalidate is that you can populate your full cache ahead of time, without having to wait for the first time they're accessed. If there are certain assets that are only used on a subsection of your web app, and you'd like those assets to be cached ahead of time, that would be trickier to do if you're only doing runtime caching.
And one more advantage offered by precaching is that it will update your cache en masse. This helps avoid scenarios where, e.g., one JavaScript file was updated by virtue of being requested on a previous page, but then when you navigate to the next page, the newer JavaScript isn't compatible with the DOM provided by your stale HTML. Precaching everything reduces the chances of these versioning mismatches from happening. (Especially if you do not enable skipWaiting.)
You write:
Especially on installed PWAs. I literally have to uninstall and add to homescreen again just to get the updated version of the site.
That's definitely not the expected behavior. Can you share a URL for your deployed web app and we can take a look as to whether anything stands out? (Again, I don't believe that this has anything to do with the question of an inlined precache manifest vs. a separate imported file.)
Sadly not yet, it's not in production environment yet but only in pre-production. That means only office network can access it. My guess is that the new service worker which is suppose to serve the new precache manifest is not being registered. Maybe on this line register('serviceWorker.js'), the serviceWorker.js may be being served from cache which means the new service worker wouldn't be registered. I'm not sure yet since it's quite hard to investigate on mobile phones.
However, I'll try to create a repo that reproduces the observed effect I told you about.
I also think that option for injecting precache manifest inline in service worker would be a good option.
In my case on production with every deployment the javascript bundles are changing and so is changing precache manifest file, because new bundles are showing up etc.
The problem is that users have cached service worker in their browsers and their registered service workers are requesting previous precache manifest files wich doesn't exist anymore on the server and it ends up with lot of 404 responses from server.
So inline option for me would be a great thing. Also maybe there is a way to generate inject manifest file without manifestHash.
We serve assets in folders like that (assets/1544088797202/client.js) and also precache manifest is served from assets/1544088797202/precache-manifest.[manifestHash].js so I don't see the need of double hashing this asset (in folder and in filename). Unfortunately workbox-webpack-plugin is not allowing to generate precache manifest file without manifestHash in filename.
@wariatroku7 using skipWaiting: true and clientsClaim: true should fix your problem.
I am seeing this issue with InjectManifest class in [email protected].
Despite providing a swSrc, empty array in .precacheAndRoute([]) is not being replaced.
new InjectManifest({
swDest: './sw.js',
swSrc: './src/serviceworker/sw.js'
})
definitely dont want to make another network call to get precache-manifest.
I have a scenario which makes me very inconvenient. My precache-manifest.js gets deployed to a different domain. Basically, I am unable to transform the arrayself.__precacheManifest at runtime with workbox-webpack-plugin for a different domain.
prod.abc.com --> cdn.prod.abc.com
deve.abc.com --> cdn.deve.abc.com
I do not want to build two sets of javascript for different domains. Because of that, I have to transform the url at runtime. But I cannot prepend a domain to precache-manifest.js because it is generated as
importScript("precache-manifest.js")
There are 2 workarounds
workbox-cli instead of workbox-webpack-pluginprecache-manifest.js next to sw.js.I also think that option for injecting precache manifest inline in service worker would be a good option.
In my case on production with every deployment the javascript bundles are changing and so is changing precache manifest file, because new bundles are showing up etc.
The problem is that users have cached service worker in their browsers and their registered service workers are requesting previous precache manifest files wich doesn't exist anymore on the server and it ends up with lot of 404 responses from server.
So inline option for me would be a great thing. Also maybe there is a way to generate inject manifest file without manifestHash.
We serve assets in folders like that (assets/1544088797202/client.js) and also precache manifest is served from assets/1544088797202/precache-manifest.[manifestHash].js so I don't see the need of double hashing this asset (in folder and in filename). Unfortunately workbox-webpack-plugin is not allowing to generate precache manifest file without manifestHash in filename.
I have the same issue. My assets are already cached and when I'm pushing new changes, there is request being sent to and older app.js file which is aready deleted during precaching. This is breaking my app. How do I fix this?
In Workbox v5's GenerateSW mode, the precache manifest is inlined into the top-level service worker by default.
However, by default in v5, the Workbox runtime code is split up into a separate chunk and imported via importScripts(). So you will still end up with two files.
But there is an option in v5 to change this if you really want everything in a single file: inlineWorkboxRuntime: true.
This should be addressed by the current Workbox v5.0.0 alpha.
Most helpful comment
I also think that option for injecting precache manifest inline in service worker would be a good option.
In my case on production with every deployment the javascript bundles are changing and so is changing precache manifest file, because new bundles are showing up etc.
The problem is that users have cached service worker in their browsers and their registered service workers are requesting previous precache manifest files wich doesn't exist anymore on the server and it ends up with lot of 404 responses from server.
So inline option for me would be a great thing. Also maybe there is a way to generate inject manifest file without manifestHash.
We serve assets in folders like that (assets/1544088797202/client.js) and also precache manifest is served from assets/1544088797202/precache-manifest.[manifestHash].js so I don't see the need of double hashing this asset (in folder and in filename). Unfortunately workbox-webpack-plugin is not allowing to generate precache manifest file without manifestHash in filename.