0.2.0 - Mid migration

This commit is contained in:
Daniel Mason 2022-04-25 14:47:15 +12:00
parent 139e6a915e
commit 7e38fdbd7d
42393 changed files with 5358157 additions and 62 deletions

3
web/node_modules/workbox-build/build/_types.js generated vendored Normal file
View file

@ -0,0 +1,3 @@
"use strict";
require("./_version.mjs");

View file

@ -0,0 +1,6 @@
{
"origin": "https://storage.googleapis.com",
"bucketName": "workbox-cdn",
"releasesDir": "releases",
"latestVersion": "5.1.4"
}

239
web/node_modules/workbox-build/build/generate-sw.js generated vendored Normal file
View file

@ -0,0 +1,239 @@
"use strict";
/*
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.
*/
const upath = require('upath');
const generateSWSchema = require('./options/schema/generate-sw');
const getFileManifestEntries = require('./lib/get-file-manifest-entries');
const rebasePath = require('./lib/rebase-path');
const validate = require('./lib/validate-options');
const writeServiceWorkerUsingDefaultTemplate = require('./lib/write-sw-using-default-template'); // eslint-disable-next-line jsdoc/newline-after-description
/**
* This method creates a list of URLs to precache, referred to as a "precache
* manifest", based on the options you provide.
*
* It also takes in additional options that configures the service worker's
* behavior, like any `runtimeCaching` rules it should use.
*
* Based on the precache manifest and the additional configuration, it writes
* a ready-to-use service worker file to disk at `swDest`.
*
* @param {Object} config The configuration to use.
*
* @param {string} config.globDirectory The local directory you wish to match
* `globPatterns` against. The path is relative to the current directory.
*
* @param {string} config.swDest The path and filename of the service worker file
* that will be created by the build process, relative to the current working
* directory. It must end in '.js'.
*
* @param {Array<module:workbox-build.ManifestEntry>} [config.additionalManifestEntries]
* A list of entries to be precached, in addition to any entries that are
* generated as part of the build configuration.
*
* @param {Array<string>} [config.babelPresetEnvTargets=['chrome >= 56']]
* The [targets](https://babeljs.io/docs/en/babel-preset-env#targets) to pass to
* `babel-preset-env` when transpiling the service worker bundle.
*
* @param {string} [config.cacheId] An optional ID to be prepended to cache
* names. This is primarily useful for local development where multiple sites
* may be served from the same `http://localhost:port` origin.
*
* @param {boolean} [config.cleanupOutdatedCaches=false] Whether or not Workbox
* should attempt to identify an delete any precaches created by older,
* incompatible versions.
*
* @param {boolean} [config.clientsClaim=false] Whether or not the service
* worker should [start controlling](https://developers.google.com/web/fundamentals/primers/service-workers/lifecycle#clientsclaim)
* any existing clients as soon as it activates.
*
* @param {string} [config.directoryIndex='index.html'] If a navigation request
* for a URL ending in `/` fails to match a precached URL, this value will be
* appended to the URL and that will be checked for a precache match. This
* should be set to what your web server is using for its directory index.
*
* @param {RegExp} [config.dontCacheBustURLsMatching] Assets that match this will be
* assumed to be uniquely versioned via their URL, and exempted from the normal
* HTTP cache-busting that's done when populating the precache. While not
* required, it's recommended that if your existing build process already
* inserts a `[hash]` value into each filename, you provide a RegExp that will
* detect that, as it will reduce the bandwidth consumed when precaching.
*
* @param {boolean} [config.globFollow=true] Determines whether or not symlinks
* are followed when generating the precache manifest. For more information, see
* the definition of `follow` in the `glob`
* [documentation](https://github.com/isaacs/node-glob#options).
*
* @param {Array<string>} [config.globIgnores=['node_modules/**']]
* A set of patterns matching files to always exclude when generating the
* precache manifest. For more information, see the definition of `ignore` in the `glob`
* [documentation](https://github.com/isaacs/node-glob#options).
*
* @param {Array<string>} [config.globPatterns=['**.{js,css,html}']]
* Files matching any of these patterns will be included in the precache
* manifest. For more information, see the
* [`glob` primer](https://github.com/isaacs/node-glob#glob-primer).
*
* @param {boolean} [config.globStrict=true] If true, an error reading a directory when
* generating a precache manifest will cause the build to fail. If false, the
* problematic directory will be skipped. For more information, see the
* definition of `strict` in the `glob`
* [documentation](https://github.com/isaacs/node-glob#options).
*
* @param {Array<RegExp>} [config.ignoreURLParametersMatching=[/^utm_/]]
* Any search parameter names that match against one of the RegExp in this array
* will be removed before looking for a precache match. This is useful if your
* users might request URLs that contain, for example, URL parameters used to
* track the source of the traffic.
*
* @param {Array<string>} [config.importScripts] A list of JavaScript files that
* should be passed to [`importScripts()`](https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/importScripts)
* inside the generated service worker file. This is useful when you want to
* let Workbox create your top-level service worker file, but want to include
* some additional code, such as a push event listener.
*
* @param {boolean} [config.inlineWorkboxRuntime=false] Whether the runtime code
* for the Workbox library should be included in the top-level service worker,
* or split into a separate file that needs to be deployed alongside the service
* worker. Keeping the runtime separate means that users will not have to
* re-download the Workbox code each time your top-level service worker changes.
*
* @param {Array<module:workbox-build.ManifestTransform>} [config.manifestTransforms] One or more
* functions which will be applied sequentially against the generated manifest.
* If `modifyURLPrefix` or `dontCacheBustURLsMatching` are also specified, their
* corresponding transformations will be applied first.
*
* @param {number} [config.maximumFileSizeToCacheInBytes=2097152] This value can be
* used to determine the maximum size of files that will be precached. This
* prevents you from inadvertently precaching very large files that might have
* accidentally matched one of your patterns.
*
* @param {string} [config.mode='production'] If set to 'production', then an
* optimized service worker bundle that excludes debugging info will be
* produced. If not explicitly configured here, the `process.env.NODE_ENV` value
* will be used, and failing that, it will fall back to `'production'`.
*
* @param {object<string, string>} [config.modifyURLPrefix] A mapping of prefixes
* that, if present in an entry in the precache manifest, will be replaced with
* the corresponding value. This can be used to, for example, remove or add a
* path prefix from a manifest entry if your web hosting setup doesn't match
* your local filesystem setup. As an alternative with more flexibility, you can
* use the `manifestTransforms` option and provide a function that modifies the
* entries in the manifest using whatever logic you provide.
*
* @param {string} [config.navigateFallback] If specified, all
* [navigation requests](https://developers.google.com/web/fundamentals/primers/service-workers/high-performance-loading#first_what_are_navigation_requests)
* for URLs that aren't precached will be fulfilled with the HTML at the URL
* provided. You must pass in the URL of an HTML document that is listed in your
* precache manifest. This is meant to be used in a Single Page App scenario, in
* which you want all navigations to use common [App Shell HTML](https://developers.google.com/web/fundamentals/architecture/app-shell).
*
* @param {Array<RegExp>} [config.navigateFallbackDenylist] An optional array
* of regular expressions that restricts which URLs the configured
* `navigateFallback` behavior applies to. This is useful if only a subset of
* your site's URLs should be treated as being part of a
* [Single Page App](https://en.wikipedia.org/wiki/Single-page_application). If
* both `navigateFallbackDenylist` and `navigateFallbackAllowlist` are
* configured, the denylist takes precedent.
*
* @param {Array<RegExp>} [config.navigateFallbackAllowlist] An optional array
* of regular expressions that restricts which URLs the configured
* `navigateFallback` behavior applies to. This is useful if only a subset of
* your site's URLs should be treated as being part of a
* [Single Page App](https://en.wikipedia.org/wiki/Single-page_application). If
* both `navigateFallbackDenylist` and `navigateFallbackAllowlist` are
* configured, the denylist takes precedent.
*
* @param {boolean} [config.navigationPreload=false] Whether or not to enable
* [navigation preload](https://developers.google.com/web/tools/workbox/modules/workbox-navigation-preload)
* in the generated service worker. When set to true, you must also use
* `runtimeCaching` to set up an appropriate response strategy that will match
* navigation requests, and make use of the preloaded response.
*
* @param {boolean|Object} [config.offlineGoogleAnalytics=false] Controls
* whether or not to include support for
* [offline Google Analytics](https://developers.google.com/web/tools/workbox/guides/enable-offline-analytics).
* When `true`, the call to `workbox-google-analytics`'s `initialize()` will be
* added to your generated service worker. When set to an `Object`, that object
* will be passed in to the `initialize()` call, allowing you to customize the
* behavior.
*
* @param {Array<RuntimeCachingEntry>} [config.runtimeCaching]
*
* @param {boolean} [config.skipWaiting=false] Whether to add an
* unconditional call to [`skipWaiting()`]{@link module:workbox-core.skipWaiting}
* to the generated service worker. If `false`, then a `message` listener will
* be added instead, allowing you to conditionally call `skipWaiting()`.
*
* @param {boolean} [config.sourcemap=true] Whether to create a sourcemap
* for the generated service worker files.
*
* @param {Object} [config.templatedURLs] If a URL is rendered based on some
* server-side logic, its contents may depend on multiple files or on some other
* unique string value. The keys in this object are server-rendered URLs. If the
* values are an array of strings, they will be interpreted as `glob` patterns,
* and the contents of any files matching the patterns will be used to uniquely
* version the URL. If used with a single string, it will be interpreted as
* unique versioning information that you've generated for a given URL.
*
* @return {Promise<{count: number, filePaths: Array<string>, size: number, warnings: Array<string>}>}
* A promise that resolves once the service worker and related files
* (indicated by `filePaths`) has been written to `swDest`. The `size` property
* contains the aggregate size of all the precached entries, in bytes, and the
* `count` property contains the total number of precached entries. Any
* non-fatal warning messages will be returned via `warnings`.
*
* @memberof module:workbox-build
*/
async function generateSW(config) {
const options = validate(config, generateSWSchema);
if (options.globDirectory) {
// Make sure we leave swDest out of the precache manifest.
options.globIgnores.push(rebasePath({
baseDirectory: options.globDirectory,
file: options.swDest
})); // If we create an extra external runtime file, ignore that, too.
// See https://rollupjs.org/guide/en/#outputchunkfilenames for naming.
if (!options.inlineWorkboxRuntime) {
const swDestDir = upath.dirname(options.swDest);
const workboxRuntimeFile = upath.join(swDestDir, 'workbox-*.js');
options.globIgnores.push(rebasePath({
baseDirectory: options.globDirectory,
file: workboxRuntimeFile
}));
}
}
const {
count,
size,
manifestEntries,
warnings
} = await getFileManifestEntries(options);
const filePaths = await writeServiceWorkerUsingDefaultTemplate(Object.assign({
manifestEntries
}, options));
return {
count,
filePaths,
size,
warnings
};
}
module.exports = generateSW;

116
web/node_modules/workbox-build/build/get-manifest.js generated vendored Normal file
View file

@ -0,0 +1,116 @@
"use strict";
/*
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.
*/
const getFileManifestEntries = require('./lib/get-file-manifest-entries');
const getManifestSchema = require('./options/schema/get-manifest');
const validate = require('./lib/validate-options'); // eslint-disable-next-line jsdoc/newline-after-description
/**
* This method returns a list of URLs to precache, referred to as a "precache
* manifest", along with details about the number of entries and their size,
* based on the options you provide.
*
* @param {Object} config The configuration to use.
*
* @param {string} config.globDirectory The local directory you wish to match
* `globPatterns` against. The path is relative to the current directory.
*
* @param {Array<module:workbox-build.ManifestEntry>} [config.additionalManifestEntries]
* A list of entries to be precached, in addition to any entries that are
* generated as part of the build configuration.
*
* @param {RegExp} [config.dontCacheBustURLsMatching] Assets that match this will be
* assumed to be uniquely versioned via their URL, and exempted from the normal
* HTTP cache-busting that's done when populating the precache. While not
* required, it's recommended that if your existing build process already
* inserts a `[hash]` value into each filename, you provide a RegExp that will
* detect that, as it will reduce the bandwidth consumed when precaching.
*
* @param {boolean} [config.globFollow=true] Determines whether or not symlinks
* are followed when generating the precache manifest. For more information, see
* the definition of `follow` in the `glob`
* [documentation](https://github.com/isaacs/node-glob#options).
*
* @param {Array<string>} [config.globIgnores=['node_modules/**']]
* A set of patterns matching files to always exclude when generating the
* precache manifest. For more information, see the definition of `ignore` in the `glob`
* [documentation](https://github.com/isaacs/node-glob#options).
*
* @param {Array<string>} [config.globPatterns=['**.{js,css,html}']]
* Files matching any of these patterns will be included in the precache
* manifest. For more information, see the
* [`glob` primer](https://github.com/isaacs/node-glob#glob-primer).
*
* @param {boolean} [config.globStrict=true] If true, an error reading a directory when
* generating a precache manifest will cause the build to fail. If false, the
* problematic directory will be skipped. For more information, see the
* definition of `strict` in the `glob`
* [documentation](https://github.com/isaacs/node-glob#options).
*
* @param {Array<module:workbox-build.ManifestTransform>} [config.manifestTransforms] One or more
* functions which will be applied sequentially against the generated manifest.
* If `modifyURLPrefix` or `dontCacheBustURLsMatching` are also specified, their
* corresponding transformations will be applied first.
*
* @param {number} [config.maximumFileSizeToCacheInBytes=2097152] This value can be
* used to determine the maximum size of files that will be precached. This
* prevents you from inadvertently precaching very large files that might have
* accidentally matched one of your patterns.
*
* @param {string} [config.mode='production'] If set to 'production', then an
* optimized service worker bundle that excludes debugging info will be
* produced. If not explicitly configured here, the `process.env.NODE_ENV` value
* will be used, and failing that, it will fall back to `'production'`.
*
* @param {object<string, string>} [config.modifyURLPrefix] A mapping of prefixes
* that, if present in an entry in the precache manifest, will be replaced with
* the corresponding value. This can be used to, for example, remove or add a
* path prefix from a manifest entry if your web hosting setup doesn't match
* your local filesystem setup. As an alternative with more flexibility, you can
* use the `manifestTransforms` option and provide a function that modifies the
* entries in the manifest using whatever logic you provide.
*
* @param {Object} [config.templatedURLs] If a URL is rendered based on some
* server-side logic, its contents may depend on multiple files or on some other
* unique string value. The keys in this object are server-rendered URLs. If the
* values are an array of strings, they will be interpreted as `glob` patterns,
* and the contents of any files matching the patterns will be used to uniquely
* version the URL. If used with a single string, it will be interpreted as
* unique versioning information that you've generated for a given URL.
*
* @return {Promise<{count: number, manifestEntries: Array<module:workbox-build.ManifestEntry>, size: number, warnings: Array<string>}>}
* A promise that resolves once the precache manifest (available in the
* `manifestEntries` property) has been determined. The `size` property
* contains the aggregate size of all the precached entries, in bytes, and the
* `count` property contains the total number of precached entries. Any
* non-fatal warning messages will be returned via `warnings`.
*
* @memberof module:workbox-build
*/
async function getManifest(config) {
const options = validate(config, getManifestSchema);
const {
manifestEntries,
count,
size,
warnings
} = await getFileManifestEntries(options);
return {
manifestEntries,
count,
size,
warnings
};
}
module.exports = getManifest;

32
web/node_modules/workbox-build/build/index.js generated vendored Normal file
View file

@ -0,0 +1,32 @@
"use strict";
/*
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.
*/
const {
getModuleURL
} = require('./lib/cdn-utils');
const copyWorkboxLibraries = require('./lib/copy-workbox-libraries');
const generateSW = require('./generate-sw');
const getManifest = require('./get-manifest');
const injectManifest = require('./inject-manifest');
/**
* @module workbox-build
*/
module.exports = {
copyWorkboxLibraries,
generateSW,
getManifest,
getModuleURL,
injectManifest
};

228
web/node_modules/workbox-build/build/inject-manifest.js generated vendored Normal file
View file

@ -0,0 +1,228 @@
"use strict";
/*
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.
*/
const assert = require('assert');
const fse = require('fs-extra');
const sourceMapURL = require('source-map-url');
const stringify = require('fast-json-stable-stringify');
const upath = require('upath');
const errors = require('./lib/errors');
const escapeRegexp = require('./lib/escape-regexp');
const getFileManifestEntries = require('./lib/get-file-manifest-entries');
const injectManifestSchema = require('./options/schema/inject-manifest');
const rebasePath = require('./lib/rebase-path');
const replaceAndUpdateSourceMap = require('./lib/replace-and-update-source-map');
const validate = require('./lib/validate-options'); // eslint-disable-next-line jsdoc/newline-after-description
/**
* This method creates a list of URLs to precache, referred to as a "precache
* manifest", based on the options you provide.
*
* The manifest is injected into the `swSrc` file, and the placeholder string
* `injectionPoint` determines where in the file the manifest should go.
*
* The final service worker file, with the manifest injected, is written to
* disk at `swDest`.
*
* @param {Object} config The configuration to use.
*
* @param {string} config.globDirectory The local directory you wish to match
* `globPatterns` against. The path is relative to the current directory.
*
* @param {string} config.swDest The path and filename of the service worker file
* that will be created by the build process, relative to the current working
* directory. It must end in '.js'.
*
* @param {string} config.swSrc The path and filename of the service worker file
* that will be read during the build process, relative to the current working
* directory.
*
* @param {Array<module:workbox-build.ManifestEntry>} [config.additionalManifestEntries]
* A list of entries to be precached, in addition to any entries that are
* generated as part of the build configuration.
*
* @param {RegExp} [config.dontCacheBustURLsMatching] Assets that match this will be
* assumed to be uniquely versioned via their URL, and exempted from the normal
* HTTP cache-busting that's done when populating the precache. While not
* required, it's recommended that if your existing build process already
* inserts a `[hash]` value into each filename, you provide a RegExp that will
* detect that, as it will reduce the bandwidth consumed when precaching.
*
* @param {boolean} [config.globFollow=true] Determines whether or not symlinks
* are followed when generating the precache manifest. For more information, see
* the definition of `follow` in the `glob`
* [documentation](https://github.com/isaacs/node-glob#options).
*
* @param {Array<string>} [config.globIgnores=['node_modules/**']]
* A set of patterns matching files to always exclude when generating the
* precache manifest. For more information, see the definition of `ignore` in the `glob`
* [documentation](https://github.com/isaacs/node-glob#options).
*
* @param {Array<string>} [config.globPatterns=['**.{js,css,html}']]
* Files matching any of these patterns will be included in the precache
* manifest. For more information, see the
* [`glob` primer](https://github.com/isaacs/node-glob#glob-primer).
*
* @param {boolean} [config.globStrict=true] If true, an error reading a directory when
* generating a precache manifest will cause the build to fail. If false, the
* problematic directory will be skipped. For more information, see the
* definition of `strict` in the `glob`
* [documentation](https://github.com/isaacs/node-glob#options).
*
* @param {string} [config.injectionPoint='self.__WB_MANIFEST'] The string to
* find inside of the `swSrc` file. Once found, it will be replaced by the
* generated precache manifest.
*
* @param {Array<module:workbox-build.ManifestTransform>} [config.manifestTransforms] One or more
* functions which will be applied sequentially against the generated manifest.
* If `modifyURLPrefix` or `dontCacheBustURLsMatching` are also specified, their
* corresponding transformations will be applied first.
*
* @param {number} [config.maximumFileSizeToCacheInBytes=2097152] This value can be
* used to determine the maximum size of files that will be precached. This
* prevents you from inadvertently precaching very large files that might have
* accidentally matched one of your patterns.
*
* @param {string} [config.mode='production'] If set to 'production', then an
* optimized service worker bundle that excludes debugging info will be
* produced. If not explicitly configured here, the `process.env.NODE_ENV` value
* will be used, and failing that, it will fall back to `'production'`.
*
* @param {object<string, string>} [config.modifyURLPrefix] A mapping of prefixes
* that, if present in an entry in the precache manifest, will be replaced with
* the corresponding value. This can be used to, for example, remove or add a
* path prefix from a manifest entry if your web hosting setup doesn't match
* your local filesystem setup. As an alternative with more flexibility, you can
* use the `manifestTransforms` option and provide a function that modifies the
* entries in the manifest using whatever logic you provide.
*
* @param {Object} [config.templatedURLs] If a URL is rendered based on some
* server-side logic, its contents may depend on multiple files or on some other
* unique string value. The keys in this object are server-rendered URLs. If the
* values are an array of strings, they will be interpreted as `glob` patterns,
* and the contents of any files matching the patterns will be used to uniquely
* version the URL. If used with a single string, it will be interpreted as
* unique versioning information that you've generated for a given URL.
*
* @return {Promise<{count: number, filePaths: Array<string>, size: number, warnings: Array<string>}>}
* A promise that resolves once the service worker and related files
* (indicated by `filePaths`) has been written to `swDest`. The `size` property
* contains the aggregate size of all the precached entries, in bytes, and the
* `count` property contains the total number of precached entries. Any
* non-fatal warning messages will be returned via `warnings`.
*
* @memberof module:workbox-build
*/
async function injectManifest(config) {
const options = validate(config, injectManifestSchema); // Make sure we leave swSrc and swDest out of the precache manifest.
for (const file of [options.swSrc, options.swDest]) {
options.globIgnores.push(rebasePath({
file,
baseDirectory: options.globDirectory
}));
}
const globalRegexp = new RegExp(escapeRegexp(options.injectionPoint), 'g');
const {
count,
size,
manifestEntries,
warnings
} = await getFileManifestEntries(options);
let swFileContents;
try {
swFileContents = await fse.readFile(options.swSrc, 'utf8');
} catch (error) {
throw new Error(`${errors['invalid-sw-src']} ${error.message}`);
}
const injectionResults = swFileContents.match(globalRegexp);
if (!injectionResults) {
// See https://github.com/GoogleChrome/workbox/issues/2230
if (upath.resolve(options.swSrc) === upath.resolve(options.swDest)) {
throw new Error(errors['same-src-and-dest'] + ' ' + options.injectionPoint);
}
throw new Error(errors['injection-point-not-found'] + ' ' + options.injectionPoint);
}
assert(injectionResults.length === 1, errors['multiple-injection-points'] + options.injectionPoint);
const manifestString = stringify(manifestEntries);
const filesToWrite = {};
const url = sourceMapURL.getFrom(swFileContents); // If our swSrc file contains a sourcemap, we would invalidate that
// mapping if we just replaced injectionPoint with the stringified manifest.
// Instead, we need to update the swDest contents as well as the sourcemap
// at the same time.
// See https://github.com/GoogleChrome/workbox/issues/2235
if (url) {
const sourcemapSrcPath = upath.resolve(upath.dirname(options.swSrc), url);
const sourcemapDestPath = upath.resolve(upath.dirname(options.swDest), url);
let originalMap;
try {
originalMap = await fse.readJSON(sourcemapSrcPath, 'utf8');
} catch (error) {
throw new Error(`${errors['cant-find-sourcemap']} ${error.message}`);
}
const {
map,
source
} = await replaceAndUpdateSourceMap({
originalMap,
jsFilename: upath.basename(options.swDest),
originalSource: swFileContents,
replaceString: manifestString,
searchString: options.injectionPoint
});
filesToWrite[options.swDest] = source;
filesToWrite[sourcemapDestPath] = map;
} else {
// If there's no sourcemap associated with swSrc, a simple string
// replacement will suffice.
filesToWrite[options.swDest] = swFileContents.replace(globalRegexp, manifestString);
}
for (const [file, contents] of Object.entries(filesToWrite)) {
try {
await fse.mkdirp(upath.dirname(file));
} catch (error) {
throw new Error(errors['unable-to-make-injection-directory'] + ` '${error.message}'`);
}
await fse.writeFile(file, contents);
}
return {
count,
size,
warnings,
// Use upath.resolve() to make all the paths absolute.
filePaths: Object.keys(filesToWrite).map(f => upath.resolve(f))
};
}
module.exports = injectManifest;

View file

@ -0,0 +1,44 @@
"use strict";
/*
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.
*/
const errors = require('./errors');
module.exports = additionalManifestEntries => {
return manifest => {
const warnings = [];
const stringEntries = new Set();
for (const additionalEntry of additionalManifestEntries) {
// Warn about either a string or an object that lacks a precache property.
// (An object with a revision property set to null is okay.)
if (typeof additionalEntry === 'string') {
stringEntries.add(additionalEntry);
} else if (additionalEntry && additionalEntry.revision === undefined) {
stringEntries.add(additionalEntry.url);
}
manifest.push(additionalEntry);
}
if (stringEntries.size > 0) {
let urls = '\n';
for (const stringEntry of stringEntries) {
urls += ` - ${stringEntry}\n`;
}
warnings.push(errors['string-entry-warning'] + urls);
}
return {
manifest,
warnings
};
};
};

138
web/node_modules/workbox-build/build/lib/bundle.js generated vendored Normal file
View file

@ -0,0 +1,138 @@
"use strict";
/*
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.
*/
const {
rollup
} = require('rollup');
const {
terser
} = require('rollup-plugin-terser');
const {
writeFile
} = require('fs-extra');
const babel = require('rollup-plugin-babel');
const omt = require('@surma/rollup-plugin-off-main-thread');
const upath = require('upath');
const presetEnv = require('@babel/preset-env');
const replace = require('@rollup/plugin-replace');
const resolve = require('@rollup/plugin-node-resolve');
const tempy = require('tempy');
module.exports = async ({
babelPresetEnvTargets,
inlineWorkboxRuntime,
mode,
sourcemap,
swDest,
unbundledCode
}) => {
// We need to write this to the "real" file system, as Rollup won't read from
// a custom file system.
const {
dir,
base
} = upath.parse(swDest);
const temporaryFile = tempy.file({
name: base
});
await writeFile(temporaryFile, unbundledCode);
const plugins = [resolve(), replace({
'process.env.NODE_ENV': JSON.stringify(mode)
}), babel({
// Disable the logic that checks for local Babel config files:
// https://github.com/GoogleChrome/workbox/issues/2111
babelrc: false,
configFile: false,
presets: [[presetEnv, {
targets: {
browsers: babelPresetEnvTargets
},
loose: true
}]]
})];
if (mode === 'production') {
plugins.push(terser({
mangle: {
toplevel: true,
properties: {
regex: /(^_|_$)/
}
}
}));
}
const rollupConfig = {
plugins,
input: temporaryFile
}; // Rollup will inline the runtime by default. If we don't want that, we need
// to add in some additional config.
if (!inlineWorkboxRuntime) {
rollupConfig.plugins.unshift(omt());
rollupConfig.manualChunks = id => {
return id.includes('workbox') ? 'workbox' : undefined;
};
}
const bundle = await rollup(rollupConfig);
const {
output
} = await bundle.generate({
sourcemap,
// Using an external Workbox runtime requires 'amd'.
format: inlineWorkboxRuntime ? 'es' : 'amd'
});
const files = [];
for (const chunkOrAsset of output) {
if (chunkOrAsset.isAsset) {
files.push({
name: chunkOrAsset.fileName,
contents: chunkOrAsset.source
});
} else {
let code = chunkOrAsset.code;
if (chunkOrAsset.map) {
const sourceMapFile = chunkOrAsset.fileName + '.map';
code += `//# sourceMappingURL=${sourceMapFile}\n`;
files.push({
name: sourceMapFile,
contents: chunkOrAsset.map.toString()
});
}
files.push({
name: chunkOrAsset.fileName,
contents: code
});
}
} // Make sure that if there was a directory portion included in swDest, it's
// preprended to all of the generated files.
return files.map(file => {
file.name = upath.format({
dir,
base: file.name
});
return file;
});
};

45
web/node_modules/workbox-build/build/lib/cdn-utils.js generated vendored Normal file
View file

@ -0,0 +1,45 @@
"use strict";
/*
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.
*/
const assert = require('assert');
const cdn = require('../cdn-details.json');
const errors = require('./errors');
const getCDNOrigin = () => {
return `${cdn.origin}/${cdn.bucketName}/${cdn.releasesDir}`;
};
const getVersionedCDNURL = () => {
return `${getCDNOrigin()}/${cdn.latestVersion}`;
};
const getModuleURL = (moduleName, buildType) => {
assert(moduleName, errors['no-module-name']);
if (buildType) {
const pkgJson = require(`${moduleName}/package.json`);
if (buildType === 'dev' && pkgJson.workbox.prodOnly) {
// This is not due to a public-facing exception, so just throw an Error(),
// without creating an entry in errors.js.
throw Error(`The 'dev' build of ${moduleName} is not available.`);
}
return `${getVersionedCDNURL()}/${moduleName}.${buildType.slice(0, 4)}.js`;
}
return `${getVersionedCDNURL()}/${moduleName}.js`;
};
module.exports = {
getCDNOrigin,
getModuleURL
};

View file

@ -0,0 +1,69 @@
"use strict";
/*
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.
*/
const fse = require('fs-extra');
const upath = require('upath');
const errors = require('./errors'); // Used to filter the libraries to copy based on our package.json dependencies.
const WORKBOX_PREFIX = 'workbox-'; // The directory within each package containing the final bundles.
const BUILD_DIR = 'build';
/**
* This copies over a set of runtime libraries used by Workbox into a
* local directory, which should be deployed alongside your service worker file.
*
* As an alternative to deploying these local copies, you could instead use
* Workbox from its official CDN URL.
*
* This method is exposed for the benefit of developers using
* [injectManifest()]{@link module:workbox-build.injectManifest} who would
* prefer not to use the CDN copies of Workbox. Developers using
* [generateSW()]{@link module:workbox-build.generateSW} don't need to
* explicitly call this method.
*
* @param {string} destDirectory The path to the parent directory under which
* the new directory of libraries will be created.
* @return {Promise<string>} The name of the newly created directory.
*
* @alias module:workbox-build.copyWorkboxLibraries
*/
module.exports = async destDirectory => {
const thisPkg = require('../../package.json'); // Use the version string from workbox-build in the name of the parent
// directory. This should be safe, because lerna will bump workbox-build's
// pkg.version whenever one of the dependent libraries gets bumped, and we
// care about versioning the dependent libraries.
const workboxDirectoryName = `workbox-v${thisPkg.version}`;
const workboxDirectoryPath = upath.join(destDirectory, workboxDirectoryName);
await fse.ensureDir(workboxDirectoryPath);
const copyPromises = [];
const librariesToCopy = Object.keys(thisPkg.dependencies).filter(dependency => dependency.startsWith(WORKBOX_PREFIX));
for (const library of librariesToCopy) {
// Get the path to the package on the user's filesystem by require-ing
// the package's `package.json` file via the node resolution algorithm.
const libraryPath = upath.dirname(require.resolve(`${library}/package.json`));
const buildPath = upath.join(libraryPath, BUILD_DIR); // fse.copy() copies all the files in a directory, not the directory itself.
// See https://github.com/jprichardson/node-fs-extra/blob/master/docs/copy.md#copysrc-dest-options-callback
copyPromises.push(fse.copy(buildPath, workboxDirectoryPath));
}
try {
await Promise.all(copyPromises);
return workboxDirectoryName;
} catch (error) {
throw Error(`${errors['unable-to-copy-workbox-libraries']} ${error}`);
}
};

118
web/node_modules/workbox-build/build/lib/errors.js generated vendored Normal file
View file

@ -0,0 +1,118 @@
"use strict";
/*
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.
*/
const ol = require('common-tags').oneLine;
module.exports = {
'unable-to-get-rootdir': `Unable to get the root directory of your web app.`,
'no-extension': ol`Unable to detect a usable extension for a file in your web
app directory.`,
'invalid-file-manifest-name': ol`The File Manifest Name must have at least one
character.`,
'unable-to-get-file-manifest-name': 'Unable to get a file manifest name.',
'invalid-sw-dest': `The 'swDest' value must be a valid path.`,
'unable-to-get-sw-name': 'Unable to get a service worker file name.',
'unable-to-get-save-config': ol`An error occurred when asking to save details
in a config file.`,
'unable-to-get-file-hash': ol`An error occurred when attempting to create a
file hash.`,
'unable-to-get-file-size': ol`An error occurred when attempting to get a file
size.`,
'unable-to-glob-files': 'An error occurred when globbing for files.',
'unable-to-make-manifest-directory': ol`Unable to make output directory for
file manifest.`,
'read-manifest-template-failure': 'Unable to read template for file manifest',
'populating-manifest-tmpl-failed': ol`An error occurred when populating the
file manifest template.`,
'manifest-file-write-failure': 'Unable to write the file manifest.',
'unable-to-make-sw-directory': ol`Unable to make the directories to output
the service worker path.`,
'read-sw-template-failure': ol`Unable to read the service worker template
file.`,
'sw-write-failure': 'Unable to write the service worker file.',
'sw-write-failure-directory': ol`Unable to write the service worker file;
'swDest' should be a full path to the file, not a path to a directory.`,
'unable-to-copy-workbox-libraries': ol`One or more of the Workbox libraries
could not be copied over to the destination directory: `,
'invalid-generate-sw-input': ol`The input to generateSW() must be an object.`,
'invalid-glob-directory': ol`The supplied globDirectory must be a path as a
string.`,
'invalid-dont-cache-bust': ol`The supplied 'dontCacheBustURLsMatching'
parameter must be a RegExp.`,
'invalid-exclude-files': 'The excluded files should be an array of strings.',
'invalid-get-manifest-entries-input': ol`The input to
'getFileManifestEntries()' must be an object.`,
'invalid-manifest-path': ol`The supplied manifest path is not a string with
at least one character.`,
'invalid-manifest-entries': ol`The manifest entries must be an array of
strings or JavaScript objects containing a url parameter.`,
'invalid-manifest-format': ol`The value of the 'format' option passed to
generateFileManifest() must be either 'iife' (the default) or 'es'.`,
'invalid-static-file-globs': ol`The 'globPatterns' value must be an array
of strings.`,
'invalid-templated-urls': ol`The 'templatedURLs' value should be an object
that maps URLs to either a string, or to an array of glob patterns.`,
'templated-url-matches-glob': ol`One of the 'templatedURLs' URLs is already
being tracked via 'globPatterns': `,
'invalid-glob-ignores': ol`The 'globIgnores' parameter must be an array of
glob pattern strings.`,
'manifest-entry-bad-url': ol`The generated manifest contains an entry without
a URL string. This is likely an error with workbox-build.`,
'modify-url-prefix-bad-prefixes': ol`The 'modifyURLPrefix' parameter must be
an object with string key value pairs.`,
'invalid-inject-manifest-arg': ol`The input to 'injectManifest()' must be an
object.`,
'injection-point-not-found': ol`Unable to find a place to inject the manifest.
Please ensure that your service worker file contains the following: `,
'multiple-injection-points': ol`Please ensure that your 'swSrc' file contains
only one match for the following: `,
'populating-sw-tmpl-failed': ol`Unable to generate service worker from
template.`,
'useless-glob-pattern': ol`One of the glob patterns doesn't match any files.
Please remove or fix the following: `,
'bad-template-urls-asset': ol`There was an issue using one of the provided
'templatedURLs'.`,
'invalid-runtime-caching': ol`The 'runtimeCaching' parameter must an an
array of objects with at least a 'urlPattern' and 'handler'.`,
'static-file-globs-deprecated': ol`'staticFileGlobs' is deprecated.
Please use 'globPatterns' instead.`,
'dynamic-url-deprecated': ol`'dynamicURLToDependencies' is deprecated.
Please use 'templatedURLs' instead.`,
'urlPattern-is-required': ol`The 'urlPattern' option is required when using
'runtimeCaching'.`,
'handler-is-required': ol`The 'handler' option is required when using
runtimeCaching.`,
'invalid-generate-file-manifest-arg': ol`The input to generateFileManifest()
must be an Object.`,
'invalid-sw-src': `The 'swSrc' file can't be read.`,
'same-src-and-dest': ol`Unable to find a place to inject the manifest. This is
likely because swSrc and swDest are configured to the same file.
Please ensure that your swSrc file contains the following:`,
'only-regexp-routes-supported': ol`Please use a regular expression object as
the urlPattern parameter. (Express-style routes are not currently
supported.)`,
'bad-runtime-caching-config': ol`An unknown configuration option was used
with runtimeCaching: `,
'invalid-network-timeout-seconds': ol`When using networkTimeoutSeconds, you
must set the handler to 'NetworkFirst'.`,
'no-module-name': ol`You must provide a moduleName parameter when calling
getModuleURL().`,
'bad-manifest-transforms-return-value': ol`The return value from a
manifestTransform should be an object with 'manifest' and optionally
'warnings' properties.`,
'string-entry-warning': ol`Some items were passed to additionalManifestEntries
without revisioning info. This is generally NOT safe. Learn more at
https://bit.ly/wb-precache.`,
'no-manifest-entries-or-runtime-caching': ol`Couldn't find configuration for
either precaching or runtime caching. Please ensure that the various glob
options are set to match one or more files, and/or configure the
runtimeCaching option.`,
'cant-find-sourcemap': ol`The swSrc file refers to a sourcemap that can't be
opened:`
};

View file

@ -0,0 +1,11 @@
"use strict";
/*
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.
*/
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
module.exports = str => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');

View file

@ -0,0 +1,29 @@
"use strict";
/*
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.
*/
const crypto = require('crypto');
module.exports = (compositeURL, dependencyDetails) => {
let totalSize = 0;
let compositeHash = '';
for (const fileDetails of dependencyDetails) {
totalSize += fileDetails.size;
compositeHash += fileDetails.hash;
}
const md5 = crypto.createHash('md5');
md5.update(compositeHash);
const hashOfHashes = md5.digest('hex');
return {
file: compositeURL,
hash: hashOfHashes,
size: totalSize
};
};

View file

@ -0,0 +1,70 @@
"use strict";
/*
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.
*/
const glob = require('glob');
const upath = require('upath');
const errors = require('./errors');
const getFileSize = require('./get-file-size');
const getFileHash = require('./get-file-hash');
module.exports = ({
globDirectory,
globFollow,
globIgnores,
globPattern,
globStrict
}) => {
let globbedFiles;
let warning;
try {
globbedFiles = glob.sync(globPattern, {
cwd: globDirectory,
follow: globFollow,
ignore: globIgnores,
strict: globStrict
});
} catch (err) {
throw new Error(errors['unable-to-glob-files'] + ` '${err.message}'`);
}
if (globbedFiles.length === 0) {
warning = errors['useless-glob-pattern'] + ' ' + JSON.stringify({
globDirectory,
globPattern,
globIgnores
}, null, 2);
}
const fileDetails = globbedFiles.map(file => {
const fullPath = upath.join(globDirectory, file);
const fileSize = getFileSize(fullPath);
if (fileSize === null) {
return null;
}
const fileHash = getFileHash(fullPath);
return {
file: `${upath.relative(globDirectory, fullPath)}`,
hash: fileHash,
size: fileSize
};
}); // If !== null, means it's a valid file.
const globbedFileDetails = fileDetails.filter(details => details !== null);
return {
globbedFileDetails,
warning
};
};

View file

@ -0,0 +1,23 @@
"use strict";
/*
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.
*/
const fs = require('fs');
const getStringHash = require('./get-string-hash');
const errors = require('./errors');
module.exports = file => {
try {
const buffer = fs.readFileSync(file);
return getStringHash(buffer);
} catch (err) {
throw new Error(errors['unable-to-get-file-hash'] + ` '${err.message}'`);
}
};

View file

@ -0,0 +1,128 @@
"use strict";
/*
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.
*/
const assert = require('assert');
const errors = require('./errors');
const transformManifest = require('./transform-manifest');
const getCompositeDetails = require('./get-composite-details');
const getFileDetails = require('./get-file-details');
const getStringDetails = require('./get-string-details');
module.exports = async ({
additionalManifestEntries,
dontCacheBustURLsMatching,
globDirectory,
globFollow,
globIgnores,
globPatterns,
globStrict,
manifestTransforms,
maximumFileSizeToCacheInBytes,
modifyURLPrefix,
swDest,
templatedURLs
}) => {
const warnings = []; // Initialize to an empty array so that we can still pass something to
// transformManifest() and get a normalized output.
let fileDetails = [];
const fileSet = new Set();
if (globDirectory) {
try {
fileDetails = globPatterns.reduce((accumulated, globPattern) => {
const {
globbedFileDetails,
warning
} = getFileDetails({
globDirectory,
globFollow,
globIgnores,
globPattern,
globStrict
});
if (warning) {
warnings.push(warning);
}
globbedFileDetails.forEach(fileDetails => {
if (fileSet.has(fileDetails.file)) {
return;
}
fileSet.add(fileDetails.file);
accumulated.push(fileDetails);
});
return accumulated;
}, []);
} catch (error) {
// If there's an exception thrown while globbing, then report
// it back as a warning, and don't consider it fatal.
warnings.push(error.message);
}
}
if (templatedURLs) {
for (const url of Object.keys(templatedURLs)) {
assert(!fileSet.has(url), errors['templated-url-matches-glob']);
const dependencies = templatedURLs[url];
if (Array.isArray(dependencies)) {
const details = dependencies.reduce((previous, globPattern) => {
try {
const {
globbedFileDetails,
warning
} = getFileDetails({
globDirectory,
globFollow,
globIgnores,
globPattern,
globStrict
});
if (warning) {
warnings.push(warning);
}
return previous.concat(globbedFileDetails);
} catch (error) {
const debugObj = {};
debugObj[url] = dependencies;
throw new Error(`${errors['bad-template-urls-asset']} ` + `'${globPattern}' from '${JSON.stringify(debugObj)}':\n` + error);
}
}, []);
fileDetails.push(getCompositeDetails(url, details));
} else if (typeof dependencies === 'string') {
fileDetails.push(getStringDetails(url, dependencies));
}
}
}
const transformedManifest = await transformManifest({
additionalManifestEntries,
dontCacheBustURLsMatching,
fileDetails,
manifestTransforms,
maximumFileSizeToCacheInBytes,
modifyURLPrefix
});
if (warnings.length > 0) {
transformedManifest.warnings.push(...warnings);
}
return transformedManifest;
};

View file

@ -0,0 +1,26 @@
"use strict";
/*
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.
*/
const fs = require('fs');
const errors = require('./errors');
module.exports = file => {
try {
const stat = fs.statSync(file);
if (!stat.isFile()) {
return null;
}
return stat.size;
} catch (err) {
throw new Error(errors['unable-to-get-file-size'] + ` '${err.message}'`);
}
};

View file

@ -0,0 +1,18 @@
"use strict";
/*
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.
*/
const getStringHash = require('./get-string-hash');
module.exports = (url, string) => {
return {
file: url,
hash: getStringHash(string),
size: string.length
};
};

View file

@ -0,0 +1,16 @@
"use strict";
/*
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.
*/
const crypto = require('crypto');
module.exports = string => {
const md5 = crypto.createHash('md5');
md5.update(string);
return md5.digest('hex');
};

View file

@ -0,0 +1,28 @@
"use strict";
/*
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.
*/
const prettyBytes = require('pretty-bytes');
module.exports = maximumFileSizeToCacheInBytes => {
return originalManifest => {
const warnings = [];
const manifest = originalManifest.filter(entry => {
if (entry.size <= maximumFileSizeToCacheInBytes) {
return true;
}
warnings.push(`${entry.url} is ${prettyBytes(entry.size)}, and won't ` + `be precached. Configure maximumFileSizeToCacheInBytes to change ` + `this limit.`);
return false;
});
return {
manifest,
warnings
};
};
};

View file

@ -0,0 +1,52 @@
"use strict";
/*
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.
*/
const errors = require('./errors');
const escapeRegExp = require('./escape-regexp');
module.exports = modifyURLPrefix => {
if (!modifyURLPrefix || typeof modifyURLPrefix !== 'object' || Array.isArray(modifyURLPrefix)) {
throw new Error(errors['modify-url-prefix-bad-prefixes']);
} // If there are no entries in modifyURLPrefix, just return an identity
// function as a shortcut.
if (Object.keys(modifyURLPrefix).length === 0) {
return entry => entry;
}
Object.keys(modifyURLPrefix).forEach(key => {
if (typeof modifyURLPrefix[key] !== 'string') {
throw new Error(errors['modify-url-prefix-bad-prefixes']);
}
}); // Escape the user input so it's safe to use in a regex.
const safeModifyURLPrefixes = Object.keys(modifyURLPrefix).map(escapeRegExp); // Join all the `modifyURLPrefix` keys so a single regex can be used.
const prefixMatchesStrings = safeModifyURLPrefixes.join('|'); // Add `^` to the front the prefix matches so it only matches the start of
// a string.
const modifyRegex = new RegExp(`^(${prefixMatchesStrings})`);
return originalManifest => {
const manifest = originalManifest.map(entry => {
if (typeof entry.url !== 'string') {
throw new Error(errors['manifest-entry-bad-url']);
}
entry.url = entry.url.replace(modifyRegex, match => {
return modifyURLPrefix[match];
});
return entry;
});
return {
manifest
};
};
};

View file

@ -0,0 +1,86 @@
"use strict";
/*
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.
*/
const ol = require('common-tags').oneLine;
const upath = require('upath');
/**
* Class for keeping track of which Workbox modules are used by the generated
* service worker script.
*
* @private
*/
class ModuleRegistry {
/**
* @private
*/
constructor() {
this.modulesUsed = new Map();
}
/**
* @return {Array<string>} A list of all of the import statements that are
* needed for the modules being used.
* @private
*/
getImportStatements() {
const workboxModuleImports = [];
for (const [localName, {
moduleName,
pkg
}] of this.modulesUsed) {
// By default require.resolve returns the resolved path of the 'main'
// field, which might be deeper than the package root. To work around
// this, we can find the package's root by resolving its package.json and
// strip the '/package.json' from the resolved path.
const pkgJsonPath = require.resolve(`${pkg}/package.json`);
const pkgRoot = upath.dirname(pkgJsonPath);
const importStatement = ol`import {${moduleName} as ${localName}} from
'${pkgRoot}/${moduleName}.mjs';`;
workboxModuleImports.push(importStatement);
}
return workboxModuleImports;
}
/**
* @param {string} pkg The workbox package that the module belongs to.
* @param {string} moduleName The name of the module to import.
* @return {string} The local variable name that corresponds to that module.
* @private
*/
getLocalName(pkg, moduleName) {
return `${pkg.replace(/-/g, '_')}_${moduleName}`;
}
/**
* @param {string} pkg The workbox package that the module belongs to.
* @param {string} moduleName The name of the module to import.
* @return {string} The local variable name that corresponds to that module.
* @private
*/
use(pkg, moduleName) {
const localName = this.getLocalName(pkg, moduleName);
this.modulesUsed.set(localName, {
moduleName,
pkg
});
return localName;
}
}
module.exports = ModuleRegistry;

View file

@ -0,0 +1,33 @@
"use strict";
/*
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.
*/
const errors = require('./errors');
module.exports = regexp => {
if (!(regexp instanceof RegExp)) {
throw new Error(errors['invalid-dont-cache-bust']);
}
return originalManifest => {
const manifest = originalManifest.map(entry => {
if (typeof entry.url !== 'string') {
throw new Error(errors['manifest-entry-bad-url']);
}
if (entry.url.match(regexp)) {
entry.revision = null;
}
return entry;
});
return {
manifest
};
};
};

View file

@ -0,0 +1,95 @@
"use strict";
/*
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.
*/
const template = require('lodash.template');
const swTemplate = require('../templates/sw-template');
const errors = require('./errors');
const ModuleRegistry = require('./module-registry');
const runtimeCachingConverter = require('./runtime-caching-converter');
const stringifyWithoutComments = require('./stringify-without-comments');
module.exports = ({
cacheId,
cleanupOutdatedCaches,
clientsClaim,
directoryIndex,
disableDevLogs,
ignoreURLParametersMatching,
importScripts,
manifestEntries = [],
navigateFallback,
navigateFallbackDenylist,
navigateFallbackAllowlist,
navigationPreload,
offlineGoogleAnalytics,
runtimeCaching = [],
skipWaiting
}) => {
// There needs to be at least something to precache, or else runtime caching.
if (!(manifestEntries.length > 0 || runtimeCaching.length > 0)) {
throw new Error(errors['no-manifest-entries-or-runtime-caching']);
} // These are all options that can be passed to the precacheAndRoute() method.
const precacheOptions = {
directoryIndex,
// An array of RegExp objects can't be serialized by JSON.stringify()'s
// default behavior, so if it's given, convert it manually.
ignoreURLParametersMatching: ignoreURLParametersMatching ? [] : undefined
};
let precacheOptionsString = JSON.stringify(precacheOptions, null, 2);
if (ignoreURLParametersMatching) {
precacheOptionsString = precacheOptionsString.replace(`"ignoreURLParametersMatching": []`, `"ignoreURLParametersMatching": [` + `${ignoreURLParametersMatching.join(', ')}]`);
}
let offlineAnalyticsConfigString;
if (offlineGoogleAnalytics) {
// If offlineGoogleAnalytics is a truthy value, we need to convert it to the
// format expected by the template.
offlineAnalyticsConfigString = offlineGoogleAnalytics === true ? // If it's the literal value true, then use an empty config string.
'{}' : // Otherwise, convert the config object into a more complex string, taking
// into account the fact that functions might need to be stringified.
stringifyWithoutComments(offlineGoogleAnalytics);
}
const moduleRegistry = new ModuleRegistry();
try {
const populatedTemplate = template(swTemplate)({
cacheId,
cleanupOutdatedCaches,
clientsClaim,
disableDevLogs,
importScripts,
manifestEntries,
navigateFallback,
navigateFallbackDenylist,
navigateFallbackAllowlist,
navigationPreload,
offlineAnalyticsConfigString,
precacheOptionsString,
runtimeCaching: runtimeCachingConverter(moduleRegistry, runtimeCaching),
skipWaiting,
use: moduleRegistry.use.bind(moduleRegistry)
});
const workboxImportStatements = moduleRegistry.getImportStatements(); // We need the import statements for all of the Workbox runtime modules
// prepended, so that the correct bundle can be created.
return workboxImportStatements.join('\n') + populatedTemplate;
} catch (error) {
throw new Error(`${errors['populating-sw-tmpl-failed']} '${error.message}'`);
}
};

View file

@ -0,0 +1,23 @@
"use strict";
/*
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.
*/
const upath = require('upath');
module.exports = ({
baseDirectory,
file
}) => {
// The initial path is relative to the current directory, so make it absolute.
const absolutePath = upath.resolve(file); // Convert the absolute path so that it's relative to the baseDirectory.
const relativePath = upath.relative(baseDirectory, absolutePath); // Remove any leading ./ as it won't work in a glob pattern.
const normalizedPath = upath.normalize(relativePath);
return normalizedPath;
};

View file

@ -0,0 +1,109 @@
"use strict";
/*
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.
*/
const {
SourceMapConsumer,
SourceMapGenerator
} = require('source-map');
/**
* Adapted from https://github.com/nsams/sourcemap-aware-replace, with modern
* JavaScript updates, along with additional properties copied from originalMap.
*
* @param {Object} options
* @param {string} options.jsFilename The name for the file whose contents
* correspond to originalSource.
* @param {Object} options.originalMap The sourcemap for originalSource,
* prior to any replacements.
* @param {string} options.originalSource The source code, prior to any
* replacements.
* @param {string} options.replaceString A string to swap in for searchString.
* @param {string} options.searchString A string in originalSource to replace.
* Only the first occurrence will be replaced.
* @return {{source: string, map: string}} An object containing both
* originalSource with the replacement applied, and the modified originalMap.
*
* @private
*/
async function replaceAndUpdateSourceMap({
jsFilename,
originalMap,
originalSource,
replaceString,
searchString
}) {
const generator = new SourceMapGenerator({
file: jsFilename
});
const consumer = await new SourceMapConsumer(originalMap);
let pos;
let src = originalSource;
const replacements = [];
let lineNum = 0;
let filePos = 0;
const lines = src.split('\n');
for (let line of lines) {
lineNum++;
let searchPos = 0;
while ((pos = line.indexOf(searchString, searchPos)) !== -1) {
src = src.substring(0, filePos + pos) + replaceString + src.substring(filePos + pos + searchString.length);
line = line.substring(0, pos) + replaceString + line.substring(pos + searchString.length);
replacements.push({
line: lineNum,
column: pos
});
searchPos = pos + replaceString.length;
}
filePos += line.length + 1;
}
replacements.reverse();
consumer.eachMapping(mapping => {
for (const replacement of replacements) {
if (replacement.line == mapping.generatedLine && mapping.generatedColumn > replacement.column) {
const offset = searchString.length - replaceString.length;
mapping.generatedColumn -= offset;
}
}
if (mapping.source) {
const newMapping = {
generated: {
line: mapping.generatedLine,
column: mapping.generatedColumn
},
original: {
line: mapping.originalLine,
column: mapping.originalColumn
},
source: mapping.source
};
return generator.addMapping(newMapping);
}
return mapping;
});
consumer.destroy();
const updatedSourceMap = Object.assign(JSON.parse(generator.toString()), {
names: originalMap.names,
sourceRoot: originalMap.sourceRoot,
sources: originalMap.sources,
sourcesContent: originalMap.sourcesContent
});
return {
map: JSON.stringify(updatedSourceMap),
source: src
};
}
module.exports = replaceAndUpdateSourceMap;

View file

@ -0,0 +1,150 @@
"use strict";
/*
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.
*/
const ol = require('common-tags').oneLine;
const errors = require('./errors');
const stringifyWithoutComments = require('./stringify-without-comments');
/**
* Given a set of options that configures runtime caching behavior, convert it
* to the equivalent Workbox method calls.
*
* @param {ModuleRegistry} moduleRegistry
* @param {Object} options See
* https://developers.google.com/web/tools/workbox/modules/workbox-build#generateSW-runtimeCaching
* @return {string} A JSON string representing the equivalent options.
*
* @private
*/
function getOptionsString(moduleRegistry, options = {}) {
let plugins = [];
if (options.plugins) {
// Using libs because JSON.stringify won't handle functions.
plugins = options.plugins.map(stringifyWithoutComments);
delete options.plugins;
} // Pull handler-specific config from the options object, since they are
// not directly used to construct a plugin instance. If set, need to be
// passed as options to the handler constructor instead.
const handlerOptionKeys = ['cacheName', 'networkTimeoutSeconds', 'fetchOptions', 'matchOptions'];
const handlerOptions = {};
for (const key of handlerOptionKeys) {
if (key in options) {
handlerOptions[key] = options[key];
delete options[key];
}
}
for (const [pluginName, pluginConfig] of Object.entries(options)) {
// Ensure that we have some valid configuration to pass to the plugin.
if (Object.keys(pluginConfig).length === 0) {
continue;
}
let pluginCode;
switch (pluginName) {
case 'backgroundSync':
{
const name = pluginConfig.name;
const plugin = moduleRegistry.use('workbox-background-sync', 'BackgroundSyncPlugin');
pluginCode = `new ${plugin}(${JSON.stringify(name)}`;
if ('options' in pluginConfig) {
pluginCode += `, ${stringifyWithoutComments(pluginConfig.options)}`;
}
pluginCode += `)`;
break;
}
case 'broadcastUpdate':
{
const channelName = pluginConfig.channelName;
const opts = Object.assign({
channelName
}, pluginConfig.options);
const plugin = moduleRegistry.use('workbox-broadcast-update', 'BroadcastUpdatePlugin');
pluginCode = `new ${plugin}(${stringifyWithoutComments(opts)})`;
break;
}
case 'cacheableResponse':
{
const plugin = moduleRegistry.use('workbox-cacheable-response', 'CacheableResponsePlugin');
pluginCode = `new ${plugin}(${stringifyWithoutComments(pluginConfig)})`;
break;
}
case 'expiration':
{
const plugin = moduleRegistry.use('workbox-expiration', 'ExpirationPlugin');
pluginCode = `new ${plugin}(${stringifyWithoutComments(pluginConfig)})`;
break;
}
default:
{
throw new Error(errors['bad-runtime-caching-config'] + pluginName);
}
}
plugins.push(pluginCode);
}
if (Object.keys(handlerOptions).length > 0 || plugins.length > 0) {
const optionsString = JSON.stringify(handlerOptions).slice(1, -1);
return ol`{
${optionsString ? optionsString + ',' : ''}
plugins: [${plugins.join(', ')}]
}`;
} else {
return '';
}
}
module.exports = (moduleRegistry, runtimeCaching) => {
return runtimeCaching.map(entry => {
const method = entry.method || 'GET';
if (!entry.urlPattern) {
throw new Error(errors['urlPattern-is-required']);
}
if (!entry.handler) {
throw new Error(errors['handler-is-required']);
} // This validation logic is a bit too gnarly for joi, so it's manually
// implemented here.
if (entry.options && entry.options.networkTimeoutSeconds && entry.handler !== 'NetworkFirst') {
throw new Error(errors['invalid-network-timeout-seconds']);
} // urlPattern might be a string, a RegExp object, or a function.
// If it's a string, it needs to be quoted.
const matcher = typeof entry.urlPattern === 'string' ? JSON.stringify(entry.urlPattern) : entry.urlPattern;
const registerRoute = moduleRegistry.use('workbox-routing', 'registerRoute');
if (typeof entry.handler === 'string') {
const optionsString = getOptionsString(moduleRegistry, entry.options);
const handler = moduleRegistry.use('workbox-strategies', entry.handler);
const strategyString = `new ${handler}(${optionsString})`;
return `${registerRoute}(${matcher}, ${strategyString}, '${method}');\n`;
} else if (typeof entry.handler === 'function') {
return `${registerRoute}(${matcher}, ${entry.handler}, '${method}');\n`;
}
}).filter(entry => Boolean(entry)); // Remove undefined map() return values.
};

View file

@ -0,0 +1,18 @@
"use strict";
/*
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.
*/
const objectStringify = require('stringify-object');
const stripComments = require('strip-comments');
module.exports = obj => {
return objectStringify(obj, {
transform: (_obj, _prop, str) => typeof _obj[_prop] === 'function' ? stripComments(str) : str
});
};

View file

@ -0,0 +1,144 @@
"use strict";
/*
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.
*/
const errors = require('./errors');
const additionalManifestEntriesTransform = require('./additional-manifest-entries-transform');
const maximumSizeTransform = require('./maximum-size-transform');
const modifyURLPrefixTransform = require('./modify-url-prefix-transform');
const noRevisionForURLsMatchingTransform = require('./no-revision-for-urls-matching-transform');
/**
* A `ManifestTransform` function can be used to modify the modify the `url` or
* `revision` properties of some or all of the
* {@link module:workbox-build.ManifestEntry|ManifestEntries} in the manifest.
*
* Deleting the `revision` property of an entry will cause
* the corresponding `url` to be precached without cache-busting parameters
* applied, which is to say, it implies that the URL itself contains
* proper versioning info. If the `revision` property is present, it must be
* set to a string.
*
* @example A transformation that prepended the origin of a CDN for any
* URL starting with '/assets/' could be implemented as:
*
* const cdnTransform = async (manifestEntries) => {
* const manifest = manifestEntries.map(entry => {
* const cdnOrigin = 'https://example.com';
* if (entry.url.startsWith('/assets/')) {
* entry.url = cdnOrigin + entry.url;
* }
* return entry;
* });
* return {manifest, warnings: []};
* };
*
* @example A transformation that nulls the revision field when the
* URL contains an 8-character hash surrounded by '.', indicating that it
* already contains revision information:
*
* const removeRevisionTransform = async (manifestEntries) => {
* const manifest = manifestEntries.map(entry => {
* const hashRegExp = /\.\w{8}\./;
* if (entry.url.match(hashRegExp)) {
* entry.revision = null;
* }
* return entry;
* });
* return {manifest, warnings: []};
* };
*
* @callback ManifestTransform
* @param {Array<module:workbox-build.ManifestEntry>} manifestEntries The full
* array of entries, prior to the current transformation.
* @param {Object} [compilation] When used in the webpack plugins, this param
* will be set to the current `compilation`.
* @return {Promise<module:workbox-build.ManifestTransformResult>}
* The array of entries with the transformation applied, and optionally, any
* warnings that should be reported back to the build tool.
*
* @memberof module:workbox-build
*/
module.exports = async ({
additionalManifestEntries,
dontCacheBustURLsMatching,
fileDetails,
manifestTransforms,
maximumFileSizeToCacheInBytes,
modifyURLPrefix,
transformParam
}) => {
let allWarnings = []; // Take the array of fileDetail objects and convert it into an array of
// {url, revision, size} objects, with \ replaced with /.
const normalizedManifest = fileDetails.map(fileDetails => {
return {
url: fileDetails.file.replace(/\\/g, '/'),
revision: fileDetails.hash,
size: fileDetails.size
};
});
const transformsToApply = [];
if (maximumFileSizeToCacheInBytes) {
transformsToApply.push(maximumSizeTransform(maximumFileSizeToCacheInBytes));
}
if (modifyURLPrefix) {
transformsToApply.push(modifyURLPrefixTransform(modifyURLPrefix));
}
if (dontCacheBustURLsMatching) {
transformsToApply.push(noRevisionForURLsMatchingTransform(dontCacheBustURLsMatching));
} // Run any manifestTransforms functions second-to-last.
if (manifestTransforms) {
transformsToApply.push(...manifestTransforms);
} // Run additionalManifestEntriesTransform last.
if (additionalManifestEntries) {
transformsToApply.push(additionalManifestEntriesTransform(additionalManifestEntries));
}
let transformedManifest = normalizedManifest;
for (const transform of transformsToApply) {
const result = await transform(transformedManifest, transformParam);
if (!('manifest' in result)) {
throw new Error(errors['bad-manifest-transforms-return-value']);
}
transformedManifest = result.manifest;
allWarnings = allWarnings.concat(result.warnings || []);
} // Generate some metadata about the manifest before we clear out the size
// properties from each entry.
const count = transformedManifest.length;
let size = 0;
for (const manifestEntry of transformedManifest) {
size += manifestEntry.size || 0;
delete manifestEntry.size;
}
return {
count,
size,
manifestEntries: transformedManifest,
warnings: allWarnings
};
};

View file

@ -0,0 +1,27 @@
"use strict";
/*
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.
*/
module.exports = (options, schema) => {
const {
value,
error
} = schema.validate(options, {
language: {
object: {
allowUnknown: 'is not a supported parameter.'
}
}
});
if (error) {
throw error;
}
return value;
};

View file

@ -0,0 +1,94 @@
"use strict";
/*
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.
*/
const fse = require('fs-extra');
const upath = require('upath');
const bundle = require('./bundle');
const errors = require('./errors');
const populateSWTemplate = require('./populate-sw-template');
module.exports = async ({
babelPresetEnvTargets,
cacheId,
cleanupOutdatedCaches,
clientsClaim,
directoryIndex,
disableDevLogs,
ignoreURLParametersMatching,
importScripts,
inlineWorkboxRuntime,
manifestEntries,
mode,
navigateFallback,
navigateFallbackDenylist,
navigateFallbackAllowlist,
navigationPreload,
offlineGoogleAnalytics,
runtimeCaching,
skipWaiting,
sourcemap,
swDest
}) => {
const outputDir = upath.dirname(swDest);
try {
await fse.mkdirp(outputDir);
} catch (error) {
throw new Error(`${errors['unable-to-make-sw-directory']}. ` + `'${error.message}'`);
}
const unbundledCode = populateSWTemplate({
cacheId,
cleanupOutdatedCaches,
clientsClaim,
directoryIndex,
disableDevLogs,
ignoreURLParametersMatching,
importScripts,
manifestEntries,
navigateFallback,
navigateFallbackDenylist,
navigateFallbackAllowlist,
navigationPreload,
offlineGoogleAnalytics,
runtimeCaching,
skipWaiting
});
try {
const files = await bundle({
babelPresetEnvTargets,
inlineWorkboxRuntime,
mode,
sourcemap,
swDest,
unbundledCode
});
const filePaths = [];
for (const file of files) {
const filePath = upath.resolve(file.name);
filePaths.push(filePath);
await fse.writeFile(filePath, file.contents);
}
return filePaths;
} catch (error) {
if (error.code === 'EISDIR') {
// See https://github.com/GoogleChrome/workbox/issues/612
throw new Error(errors['sw-write-failure-directory']);
}
throw new Error(`${errors['sw-write-failure']} '${error.message}'`);
}
};

View file

@ -0,0 +1,32 @@
"use strict";
/*
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.
*/
module.exports = {
babelPresetEnvTargets: ['chrome >= 56'],
cleanupOutdatedCaches: false,
clientsClaim: false,
compileSrc: true,
disableDevLogs: false,
exclude: [/\.map$/, /^manifest.*\.js$/],
globFollow: true,
globIgnores: ['**/node_modules/**/*'],
globPatterns: ['**/*.{js,css,html}'],
globStrict: true,
injectionPoint: 'self.__WB_MANIFEST',
inlineWorkboxRuntime: false,
maximumFileSizeToCacheInBytes: 2 * 1024 * 1024,
mode: 'production',
navigateFallback: undefined,
navigationPreload: false,
offlineGoogleAnalytics: false,
purgeOnQuotaError: true,
skipWaiting: false,
sourcemap: true,
swDestFilename: 'service-worker.js'
};

View file

@ -0,0 +1,15 @@
"use strict";
/*
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.
*/
const joi = require('@hapi/joi');
module.exports = joi.object().keys({
revision: joi.string().required().allow(null),
url: joi.string().required()
});

View file

@ -0,0 +1,12 @@
"use strict";
/*
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.
*/
const joi = require('@hapi/joi');
module.exports = joi.object().type(RegExp).error(() => 'the value must be a RegExp');

View file

@ -0,0 +1,25 @@
"use strict";
/*
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.
*/
const joi = require('@hapi/joi');
const defaults = require('../defaults');
const manifestEntryObject = require('../objects/manifest-entry');
const regExpObject = require('../objects/reg-exp');
module.exports = {
additionalManifestEntries: joi.array().items(joi.string(), manifestEntryObject),
dontCacheBustURLsMatching: regExpObject,
manifestTransforms: joi.array().items(joi.func().minArity(1).maxArity(2)),
maximumFileSizeToCacheInBytes: joi.number().min(1).default(defaults.maximumFileSizeToCacheInBytes),
mode: joi.string().default(process.env.NODE_ENV || defaults.mode),
modifyURLPrefix: joi.object()
};

View file

@ -0,0 +1,67 @@
"use strict";
/*
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.
*/
const joi = require('@hapi/joi');
const defaults = require('../defaults');
const regExpObject = require('../objects/reg-exp');
module.exports = {
babelPresetEnvTargets: joi.array().items(joi.string()).default(defaults.babelPresetEnvTargets),
cacheId: joi.string(),
cleanupOutdatedCaches: joi.boolean().default(defaults.cleanupOutdatedCaches),
clientsClaim: joi.boolean().default(defaults.clientsClaim),
directoryIndex: joi.string(),
disableDevLogs: joi.boolean().default(defaults.disableDevLogs),
ignoreURLParametersMatching: joi.array().items(regExpObject),
importScripts: joi.array().items(joi.string()),
inlineWorkboxRuntime: joi.boolean().default(defaults.inlineWorkboxRuntime),
navigateFallback: joi.string().default(defaults.navigateFallback),
navigateFallbackAllowlist: joi.array().items(regExpObject),
navigateFallbackBlacklist: joi.forbidden().error(new Error('navigateFallbackBlacklist has been renamed navigateFallbackDenylist.')),
navigateFallbackDenylist: joi.array().items(regExpObject),
navigateFallbackWhitelist: joi.forbidden().error(new Error('navigateFallbackWhitelist has been renamed navigateFallbackAllowlist.')),
navigationPreload: joi.boolean().default(defaults.navigationPreload),
offlineGoogleAnalytics: joi.alternatives().try(joi.boolean(), joi.object()).default(defaults.offlineGoogleAnalytics),
runtimeCaching: joi.array().items(joi.object().keys({
method: joi.string().valid('DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT'),
urlPattern: [regExpObject, joi.string(), joi.func()],
handler: [joi.func(), joi.string().valid('CacheFirst', 'CacheOnly', 'NetworkFirst', 'NetworkOnly', 'StaleWhileRevalidate')],
options: joi.object().keys({
backgroundSync: joi.object().keys({
name: joi.string().required(),
options: joi.object()
}),
broadcastUpdate: joi.object().keys({
channelName: joi.string().required(),
options: joi.object()
}),
cacheableResponse: joi.object().keys({
statuses: joi.array().items(joi.number().min(0).max(599)),
headers: joi.object()
}).or('statuses', 'headers'),
cacheName: joi.string(),
expiration: joi.object().keys({
maxEntries: joi.number().min(1),
maxAgeSeconds: joi.number().min(1),
purgeOnQuotaError: joi.boolean().default(defaults.purgeOnQuotaError)
}).or('maxEntries', 'maxAgeSeconds'),
networkTimeoutSeconds: joi.number().min(1),
plugins: joi.array().items(joi.object()),
fetchOptions: joi.object(),
matchOptions: joi.object()
}).with('expiration', 'cacheName')
}).requiredKeys('urlPattern', 'handler')).when('navigationPreload', {
is: true,
then: joi.required()
}),
skipWaiting: joi.boolean().default(defaults.skipWaiting),
sourcemap: joi.boolean().default(defaults.sourcemap)
};

View file

@ -0,0 +1,23 @@
"use strict";
/*
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.
*/
const joi = require('@hapi/joi');
const defaults = require('../defaults');
module.exports = {
globDirectory: joi.string(),
globFollow: joi.boolean().default(defaults.globFollow),
globIgnores: joi.array().items(joi.string()).default(defaults.globIgnores),
globPatterns: joi.array().items(joi.string()).default(defaults.globPatterns),
globStrict: joi.boolean().default(defaults.globStrict),
// templatedURLs is an object where any property name is valid, and the values
// can be either a string or an array of strings.
templatedURLs: joi.object().pattern(/./, [joi.string(), joi.array().items(joi.string())])
};

View file

@ -0,0 +1,17 @@
"use strict";
/*
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.
*/
const joi = require('@hapi/joi');
const defaults = require('../defaults');
module.exports = {
injectionPoint: joi.string().default(defaults.injectionPoint),
swSrc: joi.string().required()
};

View file

@ -0,0 +1,21 @@
"use strict";
/*
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.
*/
const joi = require('@hapi/joi');
const defaults = require('../defaults');
const regExpObject = require('../objects/reg-exp');
module.exports = {
chunks: joi.array().items(joi.string()),
exclude: joi.array().items(joi.string(), regExpObject, joi.func().arity(1)).default(defaults.exclude),
excludeChunks: joi.array().items(joi.string()),
include: joi.array().items(joi.string(), regExpObject, joi.func().arity(1))
};

View file

@ -0,0 +1,21 @@
"use strict";
/*
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.
*/
const joi = require('@hapi/joi');
const basePartial = require('../partials/base');
const generatePartial = require('../partials/generate');
const globPartial = require('../partials/glob');
const supportedOptions = Object.assign({
swDest: joi.string().required().regex(/\.js$/)
}, basePartial, generatePartial, globPartial);
module.exports = joi.object().keys(supportedOptions);

View file

@ -0,0 +1,17 @@
"use strict";
/*
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.
*/
const joi = require('@hapi/joi');
const basePartial = require('../partials/base');
const globPartial = require('../partials/glob');
const supportedOptions = Object.assign({}, basePartial, globPartial);
module.exports = joi.object().keys(supportedOptions);

View file

@ -0,0 +1,21 @@
"use strict";
/*
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.
*/
const joi = require('@hapi/joi');
const basePartial = require('../partials/base');
const globPartial = require('../partials/glob');
const injectPartial = require('../partials/inject');
const supportedOptions = Object.assign({
swDest: joi.string().required().regex(/\.js$/)
}, basePartial, globPartial, injectPartial);
module.exports = joi.object().keys(supportedOptions);

View file

@ -0,0 +1,24 @@
"use strict";
/*
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.
*/
const joi = require('@hapi/joi');
const basePartial = require('../partials/base');
const defaults = require('../defaults');
const generatePartial = require('../partials/generate');
const webpackPartial = require('../partials/webpack');
const supportedOptions = Object.assign({
importScriptsViaChunks: joi.array().items(joi.string()),
swDest: joi.string().default(defaults.swDestFilename)
}, basePartial, generatePartial, webpackPartial);
module.exports = joi.object().keys(supportedOptions);

View file

@ -0,0 +1,42 @@
"use strict";
/*
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.
*/
const joi = require('@hapi/joi');
const upath = require('upath');
const basePartial = require('../partials/base');
const defaults = require('../defaults');
const injectPartial = require('../partials/inject');
const webpackPartial = require('../partials/webpack'); // See https://github.com/hapijs/joi/blob/v16.0.0-rc2/API.md#anydefaultvalue-description
const swSrcBasename = context => {
const {
name
} = upath.parse(context.swSrc); // Always use the .js extension when generating a default filename.
return name + '.js';
};
swSrcBasename.description = 'derived from the swSrc file name';
const supportedOptions = Object.assign({
compileSrc: joi.boolean().default(defaults.compileSrc),
webpackCompilationPlugins: joi.array().items(joi.object()).when('compileSrc', {
is: false,
then: joi.forbidden()
})
}, basePartial, injectPartial, webpackPartial);
module.exports = joi.object().keys(supportedOptions).keys({
// List this separately, so that the swSrc validation happens first.
swDest: joi.string().default(swSrcBasename)
});

View file

@ -0,0 +1,61 @@
"use strict";
/*
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.
*/
module.exports = `/**
* Welcome to your Workbox-powered service worker!
*
* You'll need to register this file in your web app.
* See https://goo.gl/nhQhGp
*
* The rest of the code is auto-generated. Please don't update this file
* directly; instead, make changes to your Workbox build configuration
* and re-run your build process.
* See https://goo.gl/2aRDsh
*/
<% if (importScripts) { %>
importScripts(
<%= importScripts.map(JSON.stringify).join(',\\n ') %>
);
<% } %>
<% if (navigationPreload) { %><%= use('workbox-navigation-preload', 'enable') %>();<% } %>
<% if (cacheId) { %><%= use('workbox-core', 'setCacheNameDetails') %>({prefix: <%= JSON.stringify(cacheId) %>});<% } %>
<% if (skipWaiting) { %>
<%= use('workbox-core', 'skipWaiting') %>();
<% } else { %>
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'SKIP_WAITING') {
self.skipWaiting();
}
});
<% } %>
<% if (clientsClaim) { %><%= use('workbox-core', 'clientsClaim') %>();<% } %>
<% if (Array.isArray(manifestEntries) && manifestEntries.length > 0) {%>
/**
* The precacheAndRoute() method efficiently caches and responds to
* requests for URLs in the manifest.
* See https://goo.gl/S9QRab
*/
<%= use('workbox-precaching', 'precacheAndRoute') %>(<%= JSON.stringify(manifestEntries, null, 2) %>, <%= precacheOptionsString %>);
<% if (cleanupOutdatedCaches) { %><%= use('workbox-precaching', 'cleanupOutdatedCaches') %>();<% } %>
<% if (navigateFallback) { %><%= use('workbox-routing', 'registerRoute') %>(new <%= use('workbox-routing', 'NavigationRoute') %>(<%= use('workbox-precaching', 'createHandlerBoundToURL') %>(<%= JSON.stringify(navigateFallback) %>)<% if (navigateFallbackAllowlist || navigateFallbackDenylist) { %>, {
<% if (navigateFallbackAllowlist) { %>allowlist: [<%= navigateFallbackAllowlist %>],<% } %>
<% if (navigateFallbackDenylist) { %>denylist: [<%= navigateFallbackDenylist %>],<% } %>
}<% } %>));<% } %>
<% } %>
<% if (runtimeCaching) { runtimeCaching.forEach(runtimeCachingString => {%><%= runtimeCachingString %><% });} %>
<% if (offlineAnalyticsConfigString) { %><%= use('workbox-google-analytics', 'initialize') %>(<%= offlineAnalyticsConfigString %>);<% } %>
<% if (disableDevLogs) { %>self.__WB_DISABLE_DEV_LOGS = true;<% } %>`;