workbox
workbox copied to clipboard
Recipe for adding COEP/COOP headers
Low-priority, but it might be useful to have this documented for Workbox users. CC: @malchata
C.f. https://stackoverflow.com/questions/69468591/using-service-worker-to-enable-coop-coep-headers-security-concerns
This would look something like:
import {registerRoute} from "workbox-routing";
import {NetworkOnly} from "workbox-strategies";
import * as navigationPreload from "workbox-navigation-preload";
navigationPreload.enable();
const headersPlugin = {
handlerWillRespond: async ({response}) => {
const headers = new Headers(response.headers);
headers.set("Cross-Origin-Embedder-Policy", "require-corp");
headers.set("Cross-Origin-Opener-Policy", "same-origin");
return new Response(response.body, {
headers,
status: response.status,
statusText: response.statusText,
});
},
};
// Swap in NetworkOnly, StaleWhileRevalidate, etc. as needed.
const strategy = new NetworkOnly({
plugins: [headersPlugin],
});
registerRoute(
({request}) => ["document", "iframe", "worker"].includes(request.destination),
strategy
);
Is it possible to set up the interception via the generateSW option ? I'm trying to use https://github.com/antfu/vite-plugin-pwa to generate the service worker which provides a workbox configuration option, but having an issue figuring out how to configure the plugin via the GenerateSWOptions object.
I personally like using injectManifest mode for this sort of customization (here's an example with vite-plugin-pwa), but if you wanted to do something similar using generateSW, you can with the following Vite config:
const headersPlugin = {
handlerWillRespond: async ({response}) => {
const headers = new Headers(response.headers);
headers.set("Cross-Origin-Embedder-Policy", "require-corp");
headers.set("Cross-Origin-Opener-Policy", "same-origin");
return new Response(response.body, {
headers,
status: response.status,
statusText: response.statusText,
});
},
};
export default defineConfig({
plugins: [
VitePWA({
workbox: {
runtimeCaching: [
{
urlPattern: ({request}) =>
['document', 'iframe', 'worker'].includes(request.destination),
handler: 'NetworkOnly',
options: {
plugins: [headersPlugin],
},
},
],
},
}),
// Other config goes here.
Nice, this seems to work. Thanks for the suggestion. But I'm having one issue with my web worker script, i.e the script that gets loaded via new Worker('./webworker.js'). From my network tab it appears that the request is served by service worker. However, the response headers do not seem to be modified. It seems the request is not going through the plugin either, as when I add a log in urlPattern like below:
urlPattern: ({request}) => {
console.log(request)
return ['document', 'iframe', 'worker'].includes(request.destination)
}
I don't see .../webworker.js in the log entry. Do you know how worker script is treated differently in service worker ?
I think I figured it out. webworker.js was precached and serving it with a different header like Cross-Origin-Embedder-Policy did not trigger an update. After manually deleting the precache and reinstalling the service worker, it now worked..