applying transfer to react app

This commit is contained in:
Tyler Koenig
2021-09-20 16:54:47 -04:00
parent 8819f31dd0
commit c612b7d702
37373 changed files with 3775588 additions and 2871 deletions
+19
View File
@@ -0,0 +1,19 @@
Copyright 2018 Google LLC
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+1
View File
@@ -0,0 +1 @@
This module's documentation can be found at https://developers.google.com/web/tools/workbox/modules/workbox-webpack-plugin
+286
View File
@@ -0,0 +1,286 @@
"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 {
RawSource
} = require('webpack-sources');
const bundle = require('workbox-build/build/lib/bundle');
const populateSWTemplate = require('workbox-build/build/lib/populate-sw-template');
const validate = require('workbox-build/build/lib/validate-options');
const webpackGenerateSWSchema = require('workbox-build/build/options/schema/webpack-generate-sw');
const getScriptFilesForChunks = require('./lib/get-script-files-for-chunks');
const getManifestEntriesFromCompilation = require('./lib/get-manifest-entries-from-compilation');
const relativeToOutputPath = require('./lib/relative-to-output-path'); // Used to keep track of swDest files written by *any* instance of this plugin.
// See https://github.com/GoogleChrome/workbox/issues/2181
const _generatedAssetNames = new Set();
/**
* This class supports creating a new, ready-to-use service worker file as
* part of the webpack compilation process.
*
* Use an instance of `GenerateSW` in the
* [`plugins` array](https://webpack.js.org/concepts/plugins/#usage) of a
* webpack config.
*
* @memberof module:workbox-webpack-plugin
*/
class GenerateSW {
// eslint-disable-next-line jsdoc/newline-after-description
/**
* Creates an instance of GenerateSW.
*
* @param {Object} config The configuration to use.
*
* @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 {Array<string>} [config.chunks] One or more chunk names whose corresponding
* output files should be included in the precache manifest.
*
* @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 {Array<string|RegExp|Function>} [config.exclude=[/\.map$/, /^manifest.*\.js$]]
* One or more specifiers used to exclude assets from the precache manifest.
* This is interpreted following
* [the same rules](https://webpack.js.org/configuration/module/#condition)
* as `webpack`'s standard `exclude` option.
*
* @param {Array<string>} [config.excludeChunks] One or more chunk names whose
* corresponding output files should be excluded from the precache manifest.
*
* @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 {Array<string>} [config.importScriptsViaChunks] One or more names of
* webpack chunks. The content of those chunks will be included in the
* generated service worker, via a call to `importScripts()`.
*
* @param {Array<string|RegExp|Function>} [config.include]
* One or more specifiers used to include assets in the precache manifest.
* This is interpreted following
* [the same rules](https://webpack.js.org/configuration/module/#condition)
* as `webpack`'s standard `include` option.
*
* @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] If set to 'production', then an optimized service
* worker bundle that excludes debugging info will be produced. If not explicitly
* configured here, the `mode` value configured in the current `webpack` compiltion
* will be used.
*
* @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<module:workbox-build.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 {string} [config.swDest='service-worker.js'] The asset name of the
* service worker file that will be created by this plugin.
*/
constructor(config = {}) {
this.config = config;
this.alreadyCalled = false;
}
/**
* @param {Object} [compiler] default compiler object passed from webpack
*
* @private
*/
propagateWebpackConfig(compiler) {
// Because this.config is listed last, properties that are already set
// there take precedence over derived properties from the compiler.
this.config = Object.assign({
mode: compiler.options.mode,
sourcemap: Boolean(compiler.options.devtool)
}, this.config);
}
/**
* @param {Object} [compiler] default compiler object passed from webpack
*
* @private
*/
apply(compiler) {
this.propagateWebpackConfig(compiler);
compiler.hooks.emit.tapPromise(this.constructor.name, compilation => this.handleEmit(compilation).catch(error => compilation.errors.push(error)));
}
/**
* @param {Object} compilation The webpack compilation.
*
* @private
*/
async handleEmit(compilation) {
// See https://github.com/GoogleChrome/workbox/issues/1790
if (this.alreadyCalled) {
compilation.warnings.push(`${this.constructor.name} has been called ` + `multiple times, perhaps due to running webpack in --watch mode. The ` + `precache manifest generated after the first call may be inaccurate! ` + `Please see https://github.com/GoogleChrome/workbox/issues/1790 for ` + `more information.`);
} else {
this.alreadyCalled = true;
}
let config;
try {
// emit might be called multiple times; instead of modifying this.config,
// use a validated copy.
// See https://github.com/GoogleChrome/workbox/issues/2158
config = validate(this.config, webpackGenerateSWSchema);
} catch (error) {
throw new Error(`Please check your ${this.constructor.name} plugin ` + `configuration:\n${error.message}`);
} // Ensure that we don't precache any of the assets generated by *any*
// instance of this plugin.
config.exclude.push(({
asset
}) => _generatedAssetNames.has(asset.name));
if (config.importScriptsViaChunks) {
// Anything loaded via importScripts() is implicitly cached by the service
// worker, and should not be added to the precache manifest.
config.excludeChunks = (config.excludeChunks || []).concat(config.importScriptsViaChunks);
const scripts = getScriptFilesForChunks(compilation, config.importScriptsViaChunks);
config.importScripts = (config.importScripts || []).concat(scripts);
}
config.manifestEntries = await getManifestEntriesFromCompilation(compilation, config);
const unbundledCode = populateSWTemplate(config);
const files = await bundle({
babelPresetEnvTargets: config.babelPresetEnvTargets,
inlineWorkboxRuntime: config.inlineWorkboxRuntime,
mode: config.mode,
sourcemap: config.sourcemap,
swDest: relativeToOutputPath(compilation, config.swDest),
unbundledCode
});
for (const file of files) {
compilation.assets[file.name] = new RawSource(file.contents);
_generatedAssetNames.add(file.name);
}
}
}
module.exports = GenerateSW;
+21
View File
@@ -0,0 +1,21 @@
"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 GenerateSW = require('./generate-sw');
const InjectManifest = require('./inject-manifest');
/**
* @module workbox-webpack-plugin
*/
module.exports = {
GenerateSW,
InjectManifest
};
+301
View File
@@ -0,0 +1,301 @@
"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 {
RawSource
} = require('webpack-sources');
const {
SingleEntryPlugin
} = require('webpack');
const replaceAndUpdateSourceMap = require('workbox-build/build/lib/replace-and-update-source-map');
const stringify = require('fast-json-stable-stringify');
const upath = require('upath');
const validate = require('workbox-build/build/lib/validate-options');
const webpackInjectManifestSchema = require('workbox-build/build/options/schema/webpack-inject-manifest');
const getManifestEntriesFromCompilation = require('./lib/get-manifest-entries-from-compilation');
const getSourcemapAssetName = require('./lib/get-sourcemap-asset-name');
const relativeToOutputPath = require('./lib/relative-to-output-path'); // Used to keep track of swDest files written by *any* instance of this plugin.
// See https://github.com/GoogleChrome/workbox/issues/2181
const _generatedAssetNames = new Set();
/**
* This class supports compiling a service worker file provided via `swSrc`,
* and injecting into that service worker a list of URLs and revision
* information for precaching based on the webpack asset pipeline.
*
* Use an instance of `InjectManifest` in the
* [`plugins` array](https://webpack.js.org/concepts/plugins/#usage) of a
* webpack config.
*
* @memberof module:workbox-webpack-plugin
*/
class InjectManifest {
// eslint-disable-next-line jsdoc/newline-after-description
/**
* Creates an instance of InjectManifest.
*
* @param {Object} config The configuration to use.
*
* @param {string} config.swSrc An existing service worker file that will be
* compiled and have a precache manifest injected into it.
*
* @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.chunks] One or more chunk names whose corresponding
* output files should be included in the precache manifest.
*
* @param {boolean} [config.compileSrc=true] When `true` (the default), the
* `swSrc` file will be compiled by webpack. When `false`, compilation will
* not occur (and `webpackCompilationPlugins` can't be used.) Set to `false`
* if you want to inject the manifest into, e.g., a JSON file.
*
* @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 {Array<string|RegExp|Function>} [config.exclude=[/\.map$/, /^manifest.*\.js$]]
* One or more specifiers used to exclude assets from the precache manifest.
* This is interpreted following
* [the same rules](https://webpack.js.org/configuration/module/#condition)
* as `webpack`'s standard `exclude` option.
*
* @param {Array<string>} [config.importScriptsViaChunks] One or more names of
* webpack chunks. The content of those chunks will be included in the
* generated service worker, via a call to `importScripts()`.
*
* @param {Array<string>} [config.excludeChunks] One or more chunk names whose
* corresponding output files should be excluded from the precache manifest.
*
* @param {Array<string|RegExp|Function>} [config.include]
* One or more specifiers used to include assets in the precache manifest.
* This is interpreted following
* [the same rules](https://webpack.js.org/configuration/module/#condition)
* as `webpack`'s standard `include` option.
*
* @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] If set to 'production', then an optimized service
* worker bundle that excludes debugging info will be produced. If not explicitly
* configured here, the `mode` value configured in the current `webpack`
* compilation will be used.
*
* @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.swDest] The asset name of the
* service worker file that will be created by this plugin. If omitted, the
* name will be based on the `swSrc` name.
*
* @param {Array<Object>} [config.webpackCompilationPlugins] Optional `webpack`
* plugins that will be used when compiling the `swSrc` input file.
*/
constructor(config = {}) {
this.config = config;
this.alreadyCalled = false;
}
/**
* @param {Object} [compiler] default compiler object passed from webpack
*
* @private
*/
propagateWebpackConfig(compiler) {
// Because this.config is listed last, properties that are already set
// there take precedence over derived properties from the compiler.
this.config = Object.assign({
mode: compiler.mode
}, this.config);
}
/**
* @param {Object} [compiler] default compiler object passed from webpack
*
* @private
*/
apply(compiler) {
this.propagateWebpackConfig(compiler);
compiler.hooks.make.tapPromise(this.constructor.name, compilation => this.handleMake(compilation, compiler).catch(error => compilation.errors.push(error)));
compiler.hooks.emit.tapPromise(this.constructor.name, compilation => this.handleEmit(compilation).catch(error => compilation.errors.push(error)));
}
/**
* @param {Object} compilation The webpack compilation.
* @param {Object} parentCompiler The webpack parent compiler.
*
* @private
*/
async performChildCompilation(compilation, parentCompiler) {
const outputOptions = {
path: parentCompiler.options.output.path,
filename: this.config.swDest
};
const childCompiler = compilation.createChildCompiler(this.constructor.name, outputOptions);
childCompiler.context = parentCompiler.context;
childCompiler.inputFileSystem = parentCompiler.inputFileSystem;
childCompiler.outputFileSystem = parentCompiler.outputFileSystem;
if (Array.isArray(this.config.webpackCompilationPlugins)) {
for (const plugin of this.config.webpackCompilationPlugins) {
plugin.apply(childCompiler);
}
}
new SingleEntryPlugin(parentCompiler.context, this.config.swSrc, this.constructor.name).apply(childCompiler);
await new Promise((resolve, reject) => {
childCompiler.runAsChild((error, entries, childCompilation) => {
if (error) {
reject(error);
} else {
compilation.warnings = compilation.warnings.concat(childCompilation.warnings);
compilation.errors = compilation.errors.concat(childCompilation.errors);
resolve();
}
});
});
}
/**
* @param {Object} compilation The webpack compilation.
* @param {Object} parentCompiler The webpack parent compiler.
*
* @private
*/
addSrcToAssets(compilation, parentCompiler) {
const source = parentCompiler.inputFileSystem.readFileSync(this.config.swSrc).toString();
compilation.assets[this.config.swDest] = new RawSource(source);
}
/**
* @param {Object} compilation The webpack compilation.
* @param {Object} parentCompiler The webpack parent compiler.
*
* @private
*/
async handleMake(compilation, parentCompiler) {
try {
this.config = validate(this.config, webpackInjectManifestSchema);
} catch (error) {
throw new Error(`Please check your ${this.constructor.name} plugin ` + `configuration:\n${error.message}`);
}
this.config.swDest = relativeToOutputPath(compilation, this.config.swDest);
_generatedAssetNames.add(this.config.swDest);
if (this.config.compileSrc) {
await this.performChildCompilation(compilation, parentCompiler);
} else {
this.addSrcToAssets(compilation, parentCompiler);
}
}
/**
* @param {Object} compilation The webpack compilation.
*
* @private
*/
async handleEmit(compilation) {
// See https://github.com/GoogleChrome/workbox/issues/1790
if (this.alreadyCalled) {
compilation.warnings.push(`${this.constructor.name} has been called ` + `multiple times, perhaps due to running webpack in --watch mode. The ` + `precache manifest generated after the first call may be inaccurate! ` + `Please see https://github.com/GoogleChrome/workbox/issues/1790 for ` + `more information.`);
} else {
this.alreadyCalled = true;
}
const config = Object.assign({}, this.config); // Ensure that we don't precache any of the assets generated by *any*
// instance of this plugin.
config.exclude.push(({
asset
}) => _generatedAssetNames.has(asset.name)); // See https://webpack.js.org/contribute/plugin-patterns/#monitoring-the-watch-graph
const absoluteSwSrc = upath.resolve(this.config.swSrc);
compilation.fileDependencies.add(absoluteSwSrc);
const swAsset = compilation.assets[config.swDest];
const initialSWAssetString = swAsset.source();
if (!initialSWAssetString.includes(config.injectionPoint)) {
throw new Error(`Can't find ${config.injectionPoint} in your SW source.`);
}
const manifestEntries = await getManifestEntriesFromCompilation(compilation, config);
let manifestString = stringify(manifestEntries);
if (this.config.compileSrc) {
// See https://github.com/GoogleChrome/workbox/issues/2263
manifestString = manifestString.replace(/"/g, `'`);
}
const sourcemapAssetName = getSourcemapAssetName(compilation, initialSWAssetString, config.swDest);
if (sourcemapAssetName) {
const sourcemapAsset = compilation.assets[sourcemapAssetName];
const {
source,
map
} = await replaceAndUpdateSourceMap({
jsFilename: config.swDest,
originalMap: JSON.parse(sourcemapAsset.source()),
originalSource: initialSWAssetString,
replaceString: manifestString,
searchString: config.injectionPoint
});
compilation.assets[sourcemapAssetName] = new RawSource(map);
compilation.assets[config.swDest] = new RawSource(source);
} else {
// If there's no sourcemap associated with swDest, a simple string
// replacement will suffice.
compilation.assets[config.swDest] = new RawSource(initialSWAssetString.replace(config.injectionPoint, manifestString));
}
}
}
module.exports = InjectManifest;
+21
View File
@@ -0,0 +1,21 @@
"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');
/**
* @param {WebpackAsset} asset
* @return {string} The MD5 hash of the asset's source.
*
* @private
*/
module.exports = asset => {
return crypto.createHash('md5').update(Buffer.from(asset.source())).digest('hex');
};
@@ -0,0 +1,208 @@
"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 {
matchPart
} = require('webpack').ModuleFilenameHelpers;
const transformManifest = require('workbox-build/build/lib/transform-manifest');
const getAssetHash = require('./get-asset-hash');
const resolveWebpackURL = require('./resolve-webpack-url');
/**
* For a given asset, checks whether at least one of the conditions matches.
*
* @param {Asset} asset The webpack asset in question. This will be passed
* to any functions that are listed as conditions.
* @param {Compilation} compilation The webpack compilation. This will be passed
* to any functions that are listed as conditions.
* @param {Array<string|RegExp|Function>} conditions
* @return {boolean} Whether or not at least one condition matches.
* @private
*/
function checkConditions(asset, compilation, conditions = []) {
for (const condition of conditions) {
if (typeof condition === 'function') {
if (condition({
asset,
compilation
})) {
return true;
}
} else {
if (matchPart(asset.name, condition)) {
return true;
}
}
} // We'll only get here if none of the conditions applied.
return false;
}
/**
* Creates a mapping of an asset name to an Set of zero or more chunk names
* that the asset is associated with.
*
* Those chunk names come from a combination of the `chunkName` property on the
* asset, as well as the `stats.namedChunkGroups` property. That is the only
* way to find out if an asset has an implicit descendent relationship with a
* chunk, if it was, e.g., created by `SplitChunksPlugin`.
*
* See https://github.com/GoogleChrome/workbox/issues/1859
* See https://github.com/webpack/webpack/issues/7073
*
* @param {Object} stats The webpack compilation stats.
* @return {object<string, Set<string>>}
* @private
*/
function assetToChunkNameMapping(stats) {
const mapping = {};
for (const asset of stats.assets) {
mapping[asset.name] = new Set(asset.chunkNames);
}
for (const [chunkName, {
assets
}] of Object.entries(stats.namedChunkGroups)) {
for (const assetName of assets) {
// See https://github.com/GoogleChrome/workbox/issues/2194
if (mapping[assetName]) {
mapping[assetName].add(chunkName);
}
}
}
return mapping;
}
/**
* Filters the set of assets out, based on the configuration options provided:
* - chunks and excludeChunks, for chunkName-based criteria.
* - include and exclude, for more general criteria.
*
* @param {Compilation} compilation The webpack compilation.
* @param {Object} config The validated configuration, obtained from the plugin.
* @return {Set<Asset>} The assets that should be included in the manifest,
* based on the criteria provided.
* @private
*/
function filterAssets(compilation, config) {
const filteredAssets = new Set(); // See https://webpack.js.org/configuration/stats/#stats
// We only need assets and chunkGroups here.
const stats = compilation.getStats().toJson({
assets: true,
chunkGroups: true
});
const assetNameToChunkNames = assetToChunkNameMapping(stats); // See https://github.com/GoogleChrome/workbox/issues/1287
if (Array.isArray(config.chunks)) {
for (const chunk of config.chunks) {
if (!(chunk in stats.namedChunkGroups)) {
compilation.warnings.push(`The chunk '${chunk}' was provided in ` + `your Workbox chunks config, but was not found in the compilation.`);
}
}
} // See https://webpack.js.org/api/stats/#asset-objects
for (const asset of stats.assets) {
// chunkName based filtering is funky because:
// - Each asset might belong to one or more chunkNames.
// - If *any* of those chunk names match our config.excludeChunks,
// then we skip that asset.
// - If the config.chunks is defined *and* there's no match
// between at least one of the chunkNames and one entry, then
// we skip that assets as well.
const isExcludedChunk = Array.isArray(config.excludeChunks) && config.excludeChunks.some(chunkName => {
return assetNameToChunkNames[asset.name].has(chunkName);
});
if (isExcludedChunk) {
continue;
}
const isIncludedChunk = !Array.isArray(config.chunks) || config.chunks.some(chunkName => {
return assetNameToChunkNames[asset.name].has(chunkName);
});
if (!isIncludedChunk) {
continue;
} // Next, check asset-level checks via includes/excludes:
const isExcluded = checkConditions(asset, compilation, config.exclude);
if (isExcluded) {
continue;
} // Treat an empty config.includes as an implicit inclusion.
const isIncluded = !Array.isArray(config.include) || checkConditions(asset, compilation, config.include);
if (!isIncluded) {
continue;
} // If we've gotten this far, then add the asset.
filteredAssets.add(asset);
}
return filteredAssets;
}
module.exports = async (compilation, config) => {
const filteredAssets = filterAssets(compilation, config);
const {
publicPath
} = compilation.options.output;
const fileDetails = [];
for (const asset of filteredAssets) {
// Not sure why this would be false, but checking just in case, since
// our original list of assets comes from compilation.getStats().toJson(),
// not from compilation.assets.
if (asset.name in compilation.assets) {
// This matches the format expected by transformManifest().
fileDetails.push({
file: resolveWebpackURL(publicPath, asset.name),
hash: getAssetHash(compilation.assets[asset.name]),
size: asset.size || 0
});
} else {
compilation.warnings.push(`Could not precache ${asset.name}, as it's ` + `missing from compilation.assets. Please open a bug against Workbox ` + `with details about your webpack config.`);
}
} // We also get back `size` and `count`, and it would be nice to log that
// somewhere, but... webpack doesn't offer info-level logs?
// https://github.com/webpack/webpack/issues/3996
const {
manifestEntries,
warnings
} = await transformManifest({
fileDetails,
additionalManifestEntries: config.additionalManifestEntries,
dontCacheBustURLsMatching: config.dontCacheBustURLsMatching,
manifestTransforms: config.manifestTransforms,
maximumFileSizeToCacheInBytes: config.maximumFileSizeToCacheInBytes,
modifyURLPrefix: config.modifyURLPrefix,
transformParam: compilation
});
compilation.warnings = compilation.warnings.concat(warnings || []); // Ensure that the entries are properly sorted by URL.
const sortedEntries = manifestEntries.sort((a, b) => a.url === b.url ? 0 : a.url > b.url ? 1 : -1);
return sortedEntries;
};
@@ -0,0 +1,45 @@
"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');
const resolveWebpackURL = require('./resolve-webpack-url');
module.exports = (compilation, chunkNames) => {
const {
chunks
} = compilation.getStats().toJson({
chunks: true
});
const {
publicPath
} = compilation.options.output;
const scriptFiles = new Set();
for (const chunkName of chunkNames) {
const chunk = chunks.find(chunk => chunk.names.includes(chunkName));
if (chunk) {
for (const file of chunk.files) {
// See https://github.com/GoogleChrome/workbox/issues/2161
if (upath.extname(file) === '.js') {
scriptFiles.add(resolveWebpackURL(publicPath, file));
}
}
} else {
compilation.warnings.push(`${chunkName} was provided to ` + `importScriptsViaChunks, but didn't match any named chunks.`);
}
}
if (scriptFiles.size === 0) {
compilation.warnings.push(`There were no assets matching ` + `importScriptsViaChunks: [${chunkNames}].`);
}
return Array.from(scriptFiles);
};
@@ -0,0 +1,49 @@
"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 sourceMapURL = require('source-map-url');
const upath = require('upath');
/**
* If our bundled swDest 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
*
* @param {Object} compilation The current webpack compilation.
* @param {string} swContents The contents of the swSrc file, which may or
* may not include a valid sourcemap comment.
* @param {string} swDest The configured swDest value.
* @return {string|undefined} If the swContents contains a valid soucemap
* comment pointing to an asset present in the compilation, this will return the
* name of that asset. Otherwise, it will return undefined.
*
* @private
*/
module.exports = (compilation, swContents, swDest) => {
const url = sourceMapURL.getFrom(swContents);
if (url) {
// Translate the relative URL to what the presumed name for the webpack
// asset should be.
// This *might* not be a valid asset if the sourcemap URL that was found
// was added by another module incidentally.
// See https://github.com/GoogleChrome/workbox/issues/2250
const swAssetDirname = upath.dirname(swDest);
const sourcemapURLAssetName = upath.normalize(upath.join(swAssetDirname, url));
if (sourcemapURLAssetName in compilation.assets) {
return sourcemapURLAssetName;
}
}
};
@@ -0,0 +1,30 @@
"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');
/**
* @param {Object} compilation The webpack compilation.
* @param {string} swDest The original swDest value.
*
* @return {string} If swDest was not absolute, the returns swDest as-is.
* Otherwise, returns swDest relative to the compilation's output path.
*
* @private
*/
module.exports = (compilation, swDest) => {
// See https://github.com/jantimon/html-webpack-plugin/pull/266/files#diff-168726dbe96b3ce427e7fedce31bb0bcR38
if (upath.resolve(swDest) === upath.normalize(swDest)) {
return upath.relative(compilation.options.output.path, swDest);
} // Otherwise, return swDest as-is.
return swDest;
};
+23
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.
*/
/**
* Resolves a url in the way that webpack would (with string concatenation)
*
* Use publicPath + filePath instead of url.resolve(publicPath, filePath) see:
* https://webpack.js.org/configuration/output/#output-publicpath
*
* @function resolveWebpackURL
* @param {Array<string>} paths File paths to join
* @return {string} Joined file path
*
* @private
*/
module.exports = (...paths) => paths.join('');
+79
View File
@@ -0,0 +1,79 @@
{
"_from": "workbox-webpack-plugin@5.1.4",
"_id": "workbox-webpack-plugin@5.1.4",
"_inBundle": false,
"_integrity": "sha512-PZafF4HpugZndqISi3rZ4ZK4A4DxO8rAqt2FwRptgsDx7NF8TVKP86/huHquUsRjMGQllsNdn4FNl8CD/UvKmQ==",
"_location": "/workbox-webpack-plugin",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "workbox-webpack-plugin@5.1.4",
"name": "workbox-webpack-plugin",
"escapedName": "workbox-webpack-plugin",
"rawSpec": "5.1.4",
"saveSpec": null,
"fetchSpec": "5.1.4"
},
"_requiredBy": [
"/react-scripts"
],
"_resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-5.1.4.tgz",
"_shasum": "7bfe8c16e40fe9ed8937080ac7ae9c8bde01e79c",
"_spec": "workbox-webpack-plugin@5.1.4",
"_where": "/Users/tylerkoenig/Code/personal/react-scss2/node_modules/react-scripts",
"author": {
"name": "Google's Web DevRel Team"
},
"bugs": {
"url": "https://github.com/GoogleChrome/workbox/issues"
},
"bundleDependencies": false,
"dependencies": {
"@babel/runtime": "^7.5.5",
"fast-json-stable-stringify": "^2.0.0",
"source-map-url": "^0.4.0",
"upath": "^1.1.2",
"webpack-sources": "^1.3.0",
"workbox-build": "^5.1.4"
},
"deprecated": false,
"description": "A plugin for your Webpack build process, helping you generate a manifest of local files that workbox-sw should precache.",
"engines": {
"node": ">=8.0.0"
},
"files": [
"build"
],
"gitHead": "a95b6fd489c2a66574f1655b2de3acd2ece35fb3",
"homepage": "https://github.com/GoogleChrome/workbox",
"keywords": [
"workbox",
"workboxjs",
"webpack",
"service worker",
"caching",
"fetch requests",
"offline",
"file manifest"
],
"license": "MIT",
"main": "build/index.js",
"name": "workbox-webpack-plugin",
"peerDependencies": {
"webpack": "^4.0.0"
},
"repository": {
"type": "git",
"url": "git+https://github.com/googlechrome/workbox.git"
},
"scripts": {
"build": "gulp build-packages --package workbox-webpack-plugin",
"prepare": "npm run build",
"version": "npm run build"
},
"version": "5.1.4",
"workbox": {
"packageType": "node"
}
}