This commit is contained in:
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
Copyright 2020 Google LLC
|
||||
|
||||
Use of this source code is governed by an MIT-style
|
||||
license that can be found in the LICENSE file or at
|
||||
https://opensource.org/licenses/MIT.
|
||||
*/
|
||||
|
||||
import {WorkboxPlugin, WorkboxPluginCallbackParam} from 'workbox-core/types.js';
|
||||
|
||||
import {PrecacheController} from '../PrecacheController.js';
|
||||
|
||||
import '../_version.js';
|
||||
|
||||
/**
|
||||
* A plugin, designed to be used with PrecacheController, to translate URLs into
|
||||
* the corresponding cache key, based on the current revision info.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
class PrecacheCacheKeyPlugin implements WorkboxPlugin {
|
||||
private readonly _precacheController: PrecacheController;
|
||||
|
||||
constructor({precacheController}: {precacheController: PrecacheController}) {
|
||||
this._precacheController = precacheController;
|
||||
}
|
||||
|
||||
cacheKeyWillBeUsed: WorkboxPlugin['cacheKeyWillBeUsed'] = async ({
|
||||
request,
|
||||
params,
|
||||
}: WorkboxPluginCallbackParam['cacheKeyWillBeUsed']) => {
|
||||
// Params is type any, can't change right now.
|
||||
/* eslint-disable */
|
||||
const cacheKey =
|
||||
params?.cacheKey ||
|
||||
this._precacheController.getCacheKeyForURL(request.url);
|
||||
/* eslint-enable */
|
||||
|
||||
return cacheKey
|
||||
? new Request(cacheKey, {headers: request.headers})
|
||||
: request;
|
||||
};
|
||||
}
|
||||
|
||||
export {PrecacheCacheKeyPlugin};
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
Copyright 2020 Google LLC
|
||||
|
||||
Use of this source code is governed by an MIT-style
|
||||
license that can be found in the LICENSE file or at
|
||||
https://opensource.org/licenses/MIT.
|
||||
*/
|
||||
|
||||
import {WorkboxPlugin, WorkboxPluginCallbackParam} from 'workbox-core/types.js';
|
||||
|
||||
import '../_version.js';
|
||||
|
||||
/**
|
||||
* A plugin, designed to be used with PrecacheController, to determine the
|
||||
* of assets that were updated (or not updated) during the install event.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
class PrecacheInstallReportPlugin implements WorkboxPlugin {
|
||||
updatedURLs: string[] = [];
|
||||
notUpdatedURLs: string[] = [];
|
||||
|
||||
handlerWillStart: WorkboxPlugin['handlerWillStart'] = async ({
|
||||
request,
|
||||
state,
|
||||
}: WorkboxPluginCallbackParam['handlerWillStart']) => {
|
||||
// TODO: `state` should never be undefined...
|
||||
if (state) {
|
||||
state.originalRequest = request;
|
||||
}
|
||||
};
|
||||
|
||||
cachedResponseWillBeUsed: WorkboxPlugin['cachedResponseWillBeUsed'] = async ({
|
||||
event,
|
||||
state,
|
||||
cachedResponse,
|
||||
}: WorkboxPluginCallbackParam['cachedResponseWillBeUsed']) => {
|
||||
if (event.type === 'install') {
|
||||
if (
|
||||
state &&
|
||||
state.originalRequest &&
|
||||
state.originalRequest instanceof Request
|
||||
) {
|
||||
// TODO: `state` should never be undefined...
|
||||
const url = state.originalRequest.url;
|
||||
|
||||
if (cachedResponse) {
|
||||
this.notUpdatedURLs.push(url);
|
||||
} else {
|
||||
this.updatedURLs.push(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
return cachedResponse;
|
||||
};
|
||||
}
|
||||
|
||||
export {PrecacheInstallReportPlugin};
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
Copyright 2018 Google LLC
|
||||
|
||||
Use of this source code is governed by an MIT-style
|
||||
license that can be found in the LICENSE file or at
|
||||
https://opensource.org/licenses/MIT.
|
||||
*/
|
||||
|
||||
import {WorkboxError} from 'workbox-core/_private/WorkboxError.js';
|
||||
import {PrecacheEntry} from '../_types.js';
|
||||
import '../_version.js';
|
||||
|
||||
interface CacheKey {
|
||||
cacheKey: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
// Name of the search parameter used to store revision info.
|
||||
const REVISION_SEARCH_PARAM = '__WB_REVISION__';
|
||||
|
||||
/**
|
||||
* Converts a manifest entry into a versioned URL suitable for precaching.
|
||||
*
|
||||
* @param {Object|string} entry
|
||||
* @return {string} A URL with versioning info.
|
||||
*
|
||||
* @private
|
||||
* @memberof workbox-precaching
|
||||
*/
|
||||
export function createCacheKey(entry: PrecacheEntry | string): CacheKey {
|
||||
if (!entry) {
|
||||
throw new WorkboxError('add-to-cache-list-unexpected-type', {entry});
|
||||
}
|
||||
|
||||
// If a precache manifest entry is a string, it's assumed to be a versioned
|
||||
// URL, like '/app.abcd1234.js'. Return as-is.
|
||||
if (typeof entry === 'string') {
|
||||
const urlObject = new URL(entry, location.href);
|
||||
return {
|
||||
cacheKey: urlObject.href,
|
||||
url: urlObject.href,
|
||||
};
|
||||
}
|
||||
|
||||
const {revision, url} = entry;
|
||||
if (!url) {
|
||||
throw new WorkboxError('add-to-cache-list-unexpected-type', {entry});
|
||||
}
|
||||
|
||||
// If there's just a URL and no revision, then it's also assumed to be a
|
||||
// versioned URL.
|
||||
if (!revision) {
|
||||
const urlObject = new URL(url, location.href);
|
||||
return {
|
||||
cacheKey: urlObject.href,
|
||||
url: urlObject.href,
|
||||
};
|
||||
}
|
||||
|
||||
// Otherwise, construct a properly versioned URL using the custom Workbox
|
||||
// search parameter along with the revision info.
|
||||
const cacheKeyURL = new URL(url, location.href);
|
||||
const originalURL = new URL(url, location.href);
|
||||
cacheKeyURL.searchParams.set(REVISION_SEARCH_PARAM, revision);
|
||||
return {
|
||||
cacheKey: cacheKeyURL.href,
|
||||
url: originalURL.href,
|
||||
};
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
Copyright 2018 Google LLC
|
||||
|
||||
Use of this source code is governed by an MIT-style
|
||||
license that can be found in the LICENSE file or at
|
||||
https://opensource.org/licenses/MIT.
|
||||
*/
|
||||
|
||||
import '../_version.js';
|
||||
|
||||
// Give TypeScript the correct global.
|
||||
declare let self: ServiceWorkerGlobalScope;
|
||||
|
||||
const SUBSTRING_TO_FIND = '-precache-';
|
||||
|
||||
/**
|
||||
* Cleans up incompatible precaches that were created by older versions of
|
||||
* Workbox, by a service worker registered under the current scope.
|
||||
*
|
||||
* This is meant to be called as part of the `activate` event.
|
||||
*
|
||||
* This should be safe to use as long as you don't include `substringToFind`
|
||||
* (defaulting to `-precache-`) in your non-precache cache names.
|
||||
*
|
||||
* @param {string} currentPrecacheName The cache name currently in use for
|
||||
* precaching. This cache won't be deleted.
|
||||
* @param {string} [substringToFind='-precache-'] Cache names which include this
|
||||
* substring will be deleted (excluding `currentPrecacheName`).
|
||||
* @return {Array<string>} A list of all the cache names that were deleted.
|
||||
*
|
||||
* @private
|
||||
* @memberof workbox-precaching
|
||||
*/
|
||||
const deleteOutdatedCaches = async (
|
||||
currentPrecacheName: string,
|
||||
substringToFind: string = SUBSTRING_TO_FIND,
|
||||
): Promise<string[]> => {
|
||||
const cacheNames = await self.caches.keys();
|
||||
|
||||
const cacheNamesToDelete = cacheNames.filter((cacheName) => {
|
||||
return (
|
||||
cacheName.includes(substringToFind) &&
|
||||
cacheName.includes(self.registration.scope) &&
|
||||
cacheName !== currentPrecacheName
|
||||
);
|
||||
});
|
||||
|
||||
await Promise.all(
|
||||
cacheNamesToDelete.map((cacheName) => self.caches.delete(cacheName)),
|
||||
);
|
||||
|
||||
return cacheNamesToDelete;
|
||||
};
|
||||
|
||||
export {deleteOutdatedCaches};
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
Copyright 2019 Google LLC
|
||||
|
||||
Use of this source code is governed by an MIT-style
|
||||
license that can be found in the LICENSE file or at
|
||||
https://opensource.org/licenses/MIT.
|
||||
*/
|
||||
|
||||
import {removeIgnoredSearchParams} from './removeIgnoredSearchParams.js';
|
||||
import {PrecacheRouteOptions} from '../_types.js';
|
||||
import '../_version.js';
|
||||
|
||||
/**
|
||||
* Generator function that yields possible variations on the original URL to
|
||||
* check, one at a time.
|
||||
*
|
||||
* @param {string} url
|
||||
* @param {Object} options
|
||||
*
|
||||
* @private
|
||||
* @memberof workbox-precaching
|
||||
*/
|
||||
export function* generateURLVariations(
|
||||
url: string,
|
||||
{
|
||||
ignoreURLParametersMatching = [/^utm_/, /^fbclid$/],
|
||||
directoryIndex = 'index.html',
|
||||
cleanURLs = true,
|
||||
urlManipulation,
|
||||
}: PrecacheRouteOptions = {},
|
||||
): Generator<string, void, unknown> {
|
||||
const urlObject = new URL(url, location.href);
|
||||
urlObject.hash = '';
|
||||
yield urlObject.href;
|
||||
|
||||
const urlWithoutIgnoredParams = removeIgnoredSearchParams(
|
||||
urlObject,
|
||||
ignoreURLParametersMatching,
|
||||
);
|
||||
yield urlWithoutIgnoredParams.href;
|
||||
|
||||
if (directoryIndex && urlWithoutIgnoredParams.pathname.endsWith('/')) {
|
||||
const directoryURL = new URL(urlWithoutIgnoredParams.href);
|
||||
directoryURL.pathname += directoryIndex;
|
||||
yield directoryURL.href;
|
||||
}
|
||||
|
||||
if (cleanURLs) {
|
||||
const cleanURL = new URL(urlWithoutIgnoredParams.href);
|
||||
cleanURL.pathname += '.html';
|
||||
yield cleanURL.href;
|
||||
}
|
||||
|
||||
if (urlManipulation) {
|
||||
const additionalURLs = urlManipulation({url: urlObject});
|
||||
for (const urlToAttempt of additionalURLs) {
|
||||
yield urlToAttempt.href;
|
||||
}
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
Copyright 2019 Google LLC
|
||||
|
||||
Use of this source code is governed by an MIT-style
|
||||
license that can be found in the LICENSE file or at
|
||||
https://opensource.org/licenses/MIT.
|
||||
*/
|
||||
|
||||
import {getOrCreatePrecacheController} from './getOrCreatePrecacheController.js';
|
||||
import {generateURLVariations} from './generateURLVariations.js';
|
||||
import {PrecacheRouteOptions} from '../_types.js';
|
||||
import '../_version.js';
|
||||
|
||||
/**
|
||||
* This function will take the request URL and manipulate it based on the
|
||||
* configuration options.
|
||||
*
|
||||
* @param {string} url
|
||||
* @param {Object} options
|
||||
* @return {string} Returns the URL in the cache that matches the request,
|
||||
* if possible.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
export const getCacheKeyForURL = (
|
||||
url: string,
|
||||
options: PrecacheRouteOptions,
|
||||
): string | void => {
|
||||
const precacheController = getOrCreatePrecacheController();
|
||||
|
||||
const urlsToCacheKeys = precacheController.getURLsToCacheKeys();
|
||||
for (const possibleURL of generateURLVariations(url, options)) {
|
||||
const possibleCacheKey = urlsToCacheKeys.get(possibleURL);
|
||||
if (possibleCacheKey) {
|
||||
return possibleCacheKey;
|
||||
}
|
||||
}
|
||||
};
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright 2019 Google LLC
|
||||
|
||||
Use of this source code is governed by an MIT-style
|
||||
license that can be found in the LICENSE file or at
|
||||
https://opensource.org/licenses/MIT.
|
||||
*/
|
||||
|
||||
import {PrecacheController} from '../PrecacheController.js';
|
||||
import '../_version.js';
|
||||
|
||||
let precacheController: PrecacheController | undefined;
|
||||
|
||||
/**
|
||||
* @return {PrecacheController}
|
||||
* @private
|
||||
*/
|
||||
export const getOrCreatePrecacheController = (): PrecacheController => {
|
||||
if (!precacheController) {
|
||||
precacheController = new PrecacheController();
|
||||
}
|
||||
return precacheController;
|
||||
};
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
Copyright 2018 Google LLC
|
||||
|
||||
Use of this source code is governed by an MIT-style
|
||||
license that can be found in the LICENSE file or at
|
||||
https://opensource.org/licenses/MIT.
|
||||
*/
|
||||
|
||||
import {logger} from 'workbox-core/_private/logger.js';
|
||||
import '../_version.js';
|
||||
|
||||
/**
|
||||
* @param {string} groupTitle
|
||||
* @param {Array<string>} deletedURLs
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
const logGroup = (groupTitle: string, deletedURLs: string[]) => {
|
||||
logger.groupCollapsed(groupTitle);
|
||||
|
||||
for (const url of deletedURLs) {
|
||||
logger.log(url);
|
||||
}
|
||||
|
||||
logger.groupEnd();
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Array<string>} deletedURLs
|
||||
*
|
||||
* @private
|
||||
* @memberof workbox-precaching
|
||||
*/
|
||||
export function printCleanupDetails(deletedURLs: string[]): void {
|
||||
const deletionCount = deletedURLs.length;
|
||||
if (deletionCount > 0) {
|
||||
logger.groupCollapsed(
|
||||
`During precaching cleanup, ` +
|
||||
`${deletionCount} cached ` +
|
||||
`request${deletionCount === 1 ? ' was' : 's were'} deleted.`,
|
||||
);
|
||||
logGroup('Deleted Cache Requests', deletedURLs);
|
||||
logger.groupEnd();
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
Copyright 2018 Google LLC
|
||||
|
||||
Use of this source code is governed by an MIT-style
|
||||
license that can be found in the LICENSE file or at
|
||||
https://opensource.org/licenses/MIT.
|
||||
*/
|
||||
|
||||
import {logger} from 'workbox-core/_private/logger.js';
|
||||
import '../_version.js';
|
||||
|
||||
/**
|
||||
* @param {string} groupTitle
|
||||
* @param {Array<string>} urls
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function _nestedGroup(groupTitle: string, urls: string[]): void {
|
||||
if (urls.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
logger.groupCollapsed(groupTitle);
|
||||
|
||||
for (const url of urls) {
|
||||
logger.log(url);
|
||||
}
|
||||
|
||||
logger.groupEnd();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array<string>} urlsToPrecache
|
||||
* @param {Array<string>} urlsAlreadyPrecached
|
||||
*
|
||||
* @private
|
||||
* @memberof workbox-precaching
|
||||
*/
|
||||
export function printInstallDetails(
|
||||
urlsToPrecache: string[],
|
||||
urlsAlreadyPrecached: string[],
|
||||
): void {
|
||||
const precachedCount = urlsToPrecache.length;
|
||||
const alreadyPrecachedCount = urlsAlreadyPrecached.length;
|
||||
|
||||
if (precachedCount || alreadyPrecachedCount) {
|
||||
let message = `Precaching ${precachedCount} file${
|
||||
precachedCount === 1 ? '' : 's'
|
||||
}.`;
|
||||
|
||||
if (alreadyPrecachedCount > 0) {
|
||||
message +=
|
||||
` ${alreadyPrecachedCount} ` +
|
||||
`file${alreadyPrecachedCount === 1 ? ' is' : 's are'} already cached.`;
|
||||
}
|
||||
|
||||
logger.groupCollapsed(message);
|
||||
|
||||
_nestedGroup(`View newly precached URLs.`, urlsToPrecache);
|
||||
_nestedGroup(`View previously precached URLs.`, urlsAlreadyPrecached);
|
||||
logger.groupEnd();
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
Copyright 2018 Google LLC
|
||||
|
||||
Use of this source code is governed by an MIT-style
|
||||
license that can be found in the LICENSE file or at
|
||||
https://opensource.org/licenses/MIT.
|
||||
*/
|
||||
|
||||
import '../_version.js';
|
||||
|
||||
/**
|
||||
* Removes any URL search parameters that should be ignored.
|
||||
*
|
||||
* @param {URL} urlObject The original URL.
|
||||
* @param {Array<RegExp>} ignoreURLParametersMatching RegExps to test against
|
||||
* each search parameter name. Matches mean that the search parameter should be
|
||||
* ignored.
|
||||
* @return {URL} The URL with any ignored search parameters removed.
|
||||
*
|
||||
* @private
|
||||
* @memberof workbox-precaching
|
||||
*/
|
||||
export function removeIgnoredSearchParams(
|
||||
urlObject: URL,
|
||||
ignoreURLParametersMatching: RegExp[] = [],
|
||||
): URL {
|
||||
// Convert the iterable into an array at the start of the loop to make sure
|
||||
// deletion doesn't mess up iteration.
|
||||
for (const paramName of [...urlObject.searchParams.keys()]) {
|
||||
if (ignoreURLParametersMatching.some((regExp) => regExp.test(paramName))) {
|
||||
urlObject.searchParams.delete(paramName);
|
||||
}
|
||||
}
|
||||
|
||||
return urlObject;
|
||||
}
|
||||
Reference in New Issue
Block a user