In the current version of flutter 3.0.1 we have a service worker in index.html. So far, I cannot find any documentation on flutter.dev for how to force a cache refresh when screens or code has updated. The only way to refresh is using browser refresh buttons, etc.
There is a lot of outdated suggestions on SO to change the version number manually by appending something here or there, but that does not apply to the serviceworker. The service worker when running flutter build web
automatically gets a new version number each time you build. This does not, however, force a cache refresh in the browser.
By default this service worker js is listening for a statechange
and then calling console.log('Installed new service worker.');
This is only called when you click the browser's refresh button, so it is not helpful to prompt or force a refresh for new content.
I tried using flutter build web --pwa-strategy=none
and this does not affect caching either.
Any bright ideas out there to force a refresh? In other websites I've built it was very easy to version css/js files, which would force a refresh without any user interaction, but I'm not seeing any clear paths with flutter build web
.
This is the serviceWorker js in web/index.html
.
After running flutter build web
the var serviceWorkerVersion = null
will become something like var serviceWorkerVersion = '1767749895';
when deployed to hosting and live on the web. However, this serviceWorkerVersion update does not force a refresh of content.
<script>
var serviceWorkerVersion = null;
var scriptLoaded = false;
function loadMainDartJs() {
if (scriptLoaded) {
return;
}
scriptLoaded = true;
var scriptTag = document.createElement('script');
scriptTag.src = 'main.dart.js';
scriptTag.type = 'application/javascript';
document.body.append(scriptTag);
}
if ('serviceWorker' in navigator) {
// Service workers are supported. Use them.
window.addEventListener('load', function () {
// Wait for registration to finish before dropping the <script> tag.
// Otherwise, the browser will load the script multiple times,
// potentially different versions.
var serviceWorkerUrl = 'flutter_service_worker.js?v=' + serviceWorkerVersion;
navigator.serviceWorker.register(serviceWorkerUrl)
.then((reg) => {
function waitForActivation(serviceWorker) {
serviceWorker.addEventListener('statechange', () => {
if (serviceWorker.state == 'activated') {
console.log('Installed new service worker.');
loadMainDartJs();
}
});
}
if (!reg.active && (reg.installing || reg.waiting)) {
// No active web worker and we have installed or are installing
// one for the first time. Simply wait for it to activate.
waitForActivation(reg.installing || reg.waiting);
} else if (!reg.active.scriptURL.endsWith(serviceWorkerVersion)) {
// When the app updates the serviceWorkerVersion changes, so we
// need to ask the service worker to update.
console.log('New service worker available.');
reg.update();
waitForActivation(reg.installing);
} else {
// Existing service worker is still good.
console.log('Loading app from service worker.');
loadMainDartJs();
}
});
// If service worker doesn't succeed in a reasonable amount of time,
// fallback to plaint <script> tag.
setTimeout(() => {
if (!scriptLoaded) {
console.warn(
'Failed to load app from service worker. Falling back to plain <script> tag.',
);
loadMainDartJs();
}
}, 4000);
});
} else {
// Service workers not supported. Just drop the <script> tag.
loadMainDartJs();
}
</script>
scriptTag.src = 'main.dart.js?v=' + buildVersionParam;
At some point, I've had to start manually triggering a browser refresh. – Synergetic