The webapp I am developing is opened inside a webview via post. The post body parameters(contextual user inputs) are inserted in to the index.html.
So the repeat loads are failing because the contextual input is absent.
The official docs say that nothing can be done about it. It says all you can do now is go network first and enable navigation preload. (https://developers.google.com/web/tools/workbox/modules/workbox-navigation-preload --------- "This feature is intended to reduce navigation latency for developers who can't precache their HTML......")
Hence I am looking for a way to edit my cached index.html before is gets used. I want to insert the post body parameters in to the index.html. I am not able to find any documentation on editing the cache. Hence any help/inputs from community would be appreciated.
Workbox !== service worker. Workbox is built on top of service worker, but raw service workers give you full control over the request and response, so you can do pretty much whatever you want.
Here's how you might change the text of a response:
addEventListener('fetch', event => {
event.respondWith(async function() {
// Get a cached response:
const cachedResponse = await caches.match('/');
// Get the text of the response:
const responseText = await cachedResponse.text();
// Change it:
const newText = responseText.replace(/Hello/g, 'Goodbye');
// Serve it:
return new Response(newText, cachedResponse);
}());
});
There's a potential performance issue here, that you end up loading the full response into memory, and doing the replacement work, before you serve the first byte. With a little more effort, you can do the replacement in a streaming manner:
function streamingReplace(find, replace) {
let buffer = '';
return new TransformStream({
transform(chunk, controller) {
buffer += chunk;
let outChunk = '';
while (true) {
const index = buffer.indexOf(find);
if (index === -1) break;
outChunk += buffer.slice(0, index) + replace;
buffer = buffer.slice(index + find.length);
}
outChunk += buffer.slice(0, -(find.length - 1));
buffer = buffer.slice(-(find.length - 1));
controller.enqueue(outChunk);
},
flush(controller) {
if (buffer) controller.enqueue(buffer);
}
})
}
addEventListener('fetch', event => {
const url = new URL(event.request.url);
if (!(url.origin === location.origin && url.pathname === '/sw-content-change/')) return;
event.respondWith((async function() {
const response = await fetch(event.request);
const bodyStream = response.body
.pipeThrough(new TextDecoderStream())
.pipeThrough(streamingReplace('Hello', 'Goodbye'))
.pipeThrough(new TextEncoderStream());
return new Response(bodyStream, response);
})());
});
Here's a live demo of the above.
The other part you need, is getting the POST body of the response:
addEventListener('fetch', event => {
event.respondWith(async function() {
if (event.request.method !== 'POST') return;
const formData = await event.request.formData();
// Do whatever you want with the form data…
console.log(formData.get('foo'));
}());
});
See the MDN page for FormData
for the API.