docusaurus/packages/docusaurus-plugin-pwa/src/sw.js
Sébastien Lorber 02cd5d343b
fix(v2): PWA issues + improve docs (#4377)
* debug pwa

* more debugging logs + attempt to upgrade workbox

* fix PWA ?

* fix PWA ?

* enable pwa debugging for deploy previews

* try to fix the  app installed issue?

* try to fix appinstalled not firing

* try to add related applications to the PWA manifest

* attempt to fix related_applications

* attempt to fix related_applications

* attempt to fix related_applications

* improve PWA strategies

* improve PWA doc

* refactor/cleanup registerSw

* cleanup
2021-03-10 20:00:42 +01:00

145 lines
3.8 KiB
JavaScript

/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/* eslint-disable no-restricted-globals */
import {PrecacheController} from 'workbox-precaching';
function parseSwParams() {
const params = JSON.parse(
new URLSearchParams(self.location.search).get('params'),
);
if (params.debug) {
console.log('[Docusaurus-PWA][SW]: Service Worker params:', params);
}
return params;
}
// doc advise against dynamic imports in SW
// https://developers.google.com/web/tools/workbox/guides/using-bundlers#code_splitting_and_dynamic_imports
// https://twitter.com/sebastienlorber/status/1280155204575518720
// but I think it's working fine as it's inlined by webpack, need to double check?
async function runSWCustomCode(params) {
if (process.env.PWA_SW_CUSTOM) {
const customSW = await import(process.env.PWA_SW_CUSTOM);
if (typeof customSW.default === 'function') {
customSW.default(params);
} else if (params.debug) {
console.warn(
'[Docusaurus-PWA][SW]: swCustom should have a default export function',
);
}
}
}
/**
* Gets different possible variations for a request URL. Similar to
* https://git.io/JvixK
*
* @param {string} url
*/
function getPossibleURLs(url) {
const possibleURLs = [];
const urlObject = new URL(url, self.location.href);
if (urlObject.origin !== self.location.origin) {
return possibleURLs;
}
// Ignore search params and hash
urlObject.search = '';
urlObject.hash = '';
// /blog.html
possibleURLs.push(urlObject.href);
// /blog/ => /blog/index.html
if (urlObject.pathname.endsWith('/')) {
possibleURLs.push(`${urlObject.href}index.html`);
} else {
// /blog => /blog/index.html
possibleURLs.push(`${urlObject.href}/index.html`);
}
return possibleURLs;
}
(async () => {
const params = parseSwParams();
const precacheManifest = self.__WB_MANIFEST;
const controller = new PrecacheController({
fallbackToNetwork: true, // safer to turn this true?
});
if (params.offlineMode) {
controller.addToCacheList(precacheManifest);
if (params.debug) {
console.log('[Docusaurus-PWA][SW]: addToCacheList', {
precacheManifest,
});
}
}
await runSWCustomCode(params);
self.addEventListener('install', (event) => {
if (params.debug) {
console.log('[Docusaurus-PWA][SW]: install event', {
event,
});
}
event.waitUntil(controller.install(event));
});
self.addEventListener('activate', (event) => {
if (params.debug) {
console.log('[Docusaurus-PWA][SW]: activate event', {
event,
});
}
event.waitUntil(controller.activate(event));
});
self.addEventListener('fetch', async (event) => {
if (params.offlineMode) {
const requestURL = event.request.url;
const possibleURLs = getPossibleURLs(requestURL);
for (let i = 0; i < possibleURLs.length; i += 1) {
const possibleURL = possibleURLs[i];
const cacheKey = controller.getCacheKeyForURL(possibleURL);
if (cacheKey) {
const cachedResponse = caches.match(cacheKey);
if (params.debug) {
console.log('[Docusaurus-PWA][SW]: serving cached asset', {
requestURL,
possibleURL,
possibleURLs,
cacheKey,
cachedResponse,
});
}
event.respondWith(cachedResponse);
break;
}
}
}
});
self.addEventListener('message', async (event) => {
if (params.debug) {
console.log('[Docusaurus-PWA][SW]: message event', {
event,
});
}
const type = event.data && event.data.type;
if (type === 'SKIP_WAITING') {
self.skipWaiting();
}
});
})();