From 26105034da4fcce7ac883c899d781f016559310d Mon Sep 17 00:00:00 2001 From: ruki Date: Thu, 8 Nov 2018 00:38:48 +0800 Subject: switch to vuepress --- node_modules/workbox-build/src/lib/cdn-utils.js | 48 +++++++ .../src/lib/copy-workbox-libraries.js | 89 ++++++++++++ node_modules/workbox-build/src/lib/errors.js | 112 +++++++++++++++ node_modules/workbox-build/src/lib/filter-files.js | 131 +++++++++++++++++ .../workbox-build/src/lib/get-composite-details.js | 37 +++++ .../workbox-build/src/lib/get-file-details.js | 66 +++++++++ .../workbox-build/src/lib/get-file-hash.js | 29 ++++ .../src/lib/get-file-manifest-entries.js | 118 ++++++++++++++++ .../workbox-build/src/lib/get-file-size.js | 31 ++++ .../workbox-build/src/lib/get-string-details.js | 25 ++++ .../workbox-build/src/lib/get-string-hash.js | 23 +++ .../src/lib/maximum-size-transform.js | 35 +++++ .../src/lib/modify-url-prefix-transform.js | 79 +++++++++++ .../lib/no-revision-for-urls-matching-transform.js | 39 +++++ .../workbox-build/src/lib/populate-sw-template.js | 94 ++++++++++++ .../src/lib/runtime-caching-converter.js | 157 +++++++++++++++++++++ .../src/lib/stringify-without-comments.js | 24 ++++ .../workbox-build/src/lib/use-build-type.js | 49 +++++++ .../src/lib/write-sw-using-default-template.js | 75 ++++++++++ 19 files changed, 1261 insertions(+) create mode 100644 node_modules/workbox-build/src/lib/cdn-utils.js create mode 100644 node_modules/workbox-build/src/lib/copy-workbox-libraries.js create mode 100644 node_modules/workbox-build/src/lib/errors.js create mode 100644 node_modules/workbox-build/src/lib/filter-files.js create mode 100644 node_modules/workbox-build/src/lib/get-composite-details.js create mode 100644 node_modules/workbox-build/src/lib/get-file-details.js create mode 100644 node_modules/workbox-build/src/lib/get-file-hash.js create mode 100644 node_modules/workbox-build/src/lib/get-file-manifest-entries.js create mode 100644 node_modules/workbox-build/src/lib/get-file-size.js create mode 100644 node_modules/workbox-build/src/lib/get-string-details.js create mode 100644 node_modules/workbox-build/src/lib/get-string-hash.js create mode 100644 node_modules/workbox-build/src/lib/maximum-size-transform.js create mode 100644 node_modules/workbox-build/src/lib/modify-url-prefix-transform.js create mode 100644 node_modules/workbox-build/src/lib/no-revision-for-urls-matching-transform.js create mode 100644 node_modules/workbox-build/src/lib/populate-sw-template.js create mode 100644 node_modules/workbox-build/src/lib/runtime-caching-converter.js create mode 100644 node_modules/workbox-build/src/lib/stringify-without-comments.js create mode 100644 node_modules/workbox-build/src/lib/use-build-type.js create mode 100644 node_modules/workbox-build/src/lib/write-sw-using-default-template.js (limited to 'node_modules/workbox-build/src/lib') diff --git a/node_modules/workbox-build/src/lib/cdn-utils.js b/node_modules/workbox-build/src/lib/cdn-utils.js new file mode 100644 index 00000000..4231341a --- /dev/null +++ b/node_modules/workbox-build/src/lib/cdn-utils.js @@ -0,0 +1,48 @@ +/* + Copyright 2017 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +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, +}; diff --git a/node_modules/workbox-build/src/lib/copy-workbox-libraries.js b/node_modules/workbox-build/src/lib/copy-workbox-libraries.js new file mode 100644 index 00000000..4bc8d38b --- /dev/null +++ b/node_modules/workbox-build/src/lib/copy-workbox-libraries.js @@ -0,0 +1,89 @@ +/* + Copyright 2017 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +const fse = require('fs-extra'); +const path = require('path'); + +const errors = require('./errors'); +const useBuildType = require('./use-build-type'); + +// Used to filter the libraries to copy based on our package.json dependencies. +const WORKBOX_PREFIX = 'workbox-'; +const BUILD_TYPES = [ + 'dev', + 'prod', +]; + +/** + * 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, as it's called automatically when + * `importWorkboxFrom` is set to `local`. + * + * @param {string} destDirectory The path to the parent directory under which + * the new directory of libraries will be created. + * @return {Promise} 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 = path.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) { + const pkg = require(`${library}/package.json`); + const defaultPathToLibrary = require.resolve(`${library}/${pkg.main}`); + + for (const buildType of BUILD_TYPES) { + // Special-case logic for workbox-sw, which only has a single build type. + // This prevents a race condition with two identical copy promises; + // see https://github.com/GoogleChrome/workbox/issues/1180 + if (library === 'workbox-sw' && buildType === BUILD_TYPES[0]) { + continue; + } + + const srcPath = useBuildType(defaultPathToLibrary, buildType); + const destPath = path.join(workboxDirectoryPath, + path.basename(srcPath)); + copyPromises.push(fse.copy(srcPath, destPath)); + copyPromises.push(fse.copy(`${srcPath}.map`, `${destPath}.map`)); + } + } + + try { + await Promise.all(copyPromises); + return workboxDirectoryName; + } catch (error) { + throw Error(`${errors['unable-to-copy-workbox-libraries']} ${error}`); + } +}; diff --git a/node_modules/workbox-build/src/lib/errors.js b/node_modules/workbox-build/src/lib/errors.js new file mode 100644 index 00000000..603b049d --- /dev/null +++ b/node_modules/workbox-build/src/lib/errors.js @@ -0,0 +1,112 @@ +/* + Copyright 2017 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +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 RegExp:`, + '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`'swSrc' and 'swDest' should not be set to the same ` + + `file. Please use a different file path for 'swDest'.`, + '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().`, +}; diff --git a/node_modules/workbox-build/src/lib/filter-files.js b/node_modules/workbox-build/src/lib/filter-files.js new file mode 100644 index 00000000..979da046 --- /dev/null +++ b/node_modules/workbox-build/src/lib/filter-files.js @@ -0,0 +1,131 @@ +/* + Copyright 2017 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +const maximumSizeTransform = require('./maximum-size-transform'); +const modifyUrlPrefixTranform = 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 = (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 removes the revision field when the + * URL contains an 8-character hash surrounded by '.', indicating that it + * already contains revision information: + * + * const removeRevisionTransform = (manifestEntries) => { + * const manifest = manifestEntries.map(entry => { + * const hashRegExp = /\.\w{8}\./; + * if (entry.url.match(hashRegExp)) { + * delete entry.revision; + * } + * return entry; + * }); + * return {manifest, warnings: []}; + * }; + * + * @callback ManifestTransform + * @param {Array} manifestEntries The full + * array of entries, prior to the current transformation. + * @return {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 = ({ + dontCacheBustUrlsMatching, + fileDetails, + manifestTransforms, + maximumFileSizeToCacheInBytes, + modifyUrlPrefix, +}) => { + 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, + }; + }); + + let transformsToApply = []; + + if (maximumFileSizeToCacheInBytes) { + transformsToApply.push(maximumSizeTransform(maximumFileSizeToCacheInBytes)); + } + + if (modifyUrlPrefix) { + transformsToApply.push(modifyUrlPrefixTranform(modifyUrlPrefix)); + } + + if (dontCacheBustUrlsMatching) { + transformsToApply.push( + noRevisionForUrlsMatchingTransform(dontCacheBustUrlsMatching)); + } + + // Any additional manifestTransforms that were passed will be applied last. + transformsToApply = transformsToApply.concat(manifestTransforms || []); + + let transformedManifest = normalizedManifest; + for (const transform of transformsToApply) { + const {manifest, warnings} = transform(transformedManifest); + transformedManifest = manifest; + allWarnings = allWarnings.concat(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; + delete manifestEntry.size; + } + + return { + count, + size, + manifestEntries: transformedManifest, + warnings: allWarnings, + }; +}; diff --git a/node_modules/workbox-build/src/lib/get-composite-details.js b/node_modules/workbox-build/src/lib/get-composite-details.js new file mode 100644 index 00000000..c59e5128 --- /dev/null +++ b/node_modules/workbox-build/src/lib/get-composite-details.js @@ -0,0 +1,37 @@ +/* + Copyright 2017 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +const crypto = require('crypto'); + +module.exports = (compositeUrl, dependencyDetails) => { + let totalSize = 0; + let compositeHash = ''; + + for (let 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, + }; +}; diff --git a/node_modules/workbox-build/src/lib/get-file-details.js b/node_modules/workbox-build/src/lib/get-file-details.js new file mode 100644 index 00000000..afd32628 --- /dev/null +++ b/node_modules/workbox-build/src/lib/get-file-details.js @@ -0,0 +1,66 @@ +/* + Copyright 2017 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +const glob = require('glob'); +const path = require('path'); + +const errors = require('./errors'); +const getFileSize = require('./get-file-size'); +const getFileHash = require('./get-file-hash'); + +module.exports = (globOptions) => { + const { + globDirectory, + globFollow, + globIgnores, + globPattern, + globStrict, + } = globOptions; + let globbedFiles; + 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) { + throw new Error(errors['useless-glob-pattern'] + ' ' + + JSON.stringify({globDirectory, globPattern, globIgnores}, null, 2)); + } + + const fileDetails = globbedFiles.map((file) => { + const fullPath = path.join(globDirectory, file); + const fileSize = getFileSize(fullPath); + if (fileSize === null) { + return null; + } + + const fileHash = getFileHash(fullPath); + return { + file: `${path.relative(globDirectory, fullPath)}`, + hash: fileHash, + size: fileSize, + }; + }); + + // If !== null, means it's a valid file. + return fileDetails.filter((details) => details !== null); +}; diff --git a/node_modules/workbox-build/src/lib/get-file-hash.js b/node_modules/workbox-build/src/lib/get-file-hash.js new file mode 100644 index 00000000..77e6f44b --- /dev/null +++ b/node_modules/workbox-build/src/lib/get-file-hash.js @@ -0,0 +1,29 @@ +/* + Copyright 2017 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +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}'`); + } +}; diff --git a/node_modules/workbox-build/src/lib/get-file-manifest-entries.js b/node_modules/workbox-build/src/lib/get-file-manifest-entries.js new file mode 100644 index 00000000..e1c81d70 --- /dev/null +++ b/node_modules/workbox-build/src/lib/get-file-manifest-entries.js @@ -0,0 +1,118 @@ +/* + Copyright 2017 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +const assert = require('assert'); +const path = require('path'); + +const errors = require('./errors'); +const filterFiles = require('./filter-files'); +const getCompositeDetails = require('./get-composite-details'); +const getFileDetails = require('./get-file-details'); +const getStringDetails = require('./get-string-details'); + +module.exports = async ({ + 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 + // filterFiles() and get a normalized output. + let fileDetails = []; + const fileSet = new Set(); + + if (globDirectory) { + if (swDest) { + // Ensure that we ignore the SW file we're eventually writing to disk. + globIgnores.push(`**/${path.basename(swDest)}`); + } + + try { + fileDetails = globPatterns.reduce((accumulated, globPattern) => { + const globbedFileDetails = getFileDetails({ + globDirectory, + globFollow, + globIgnores, + globPattern, + globStrict, + }); + + 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 (let 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 = getFileDetails({ + globDirectory, + globFollow, + globIgnores, + globPattern, + globStrict, + }); + 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 filteredFiles = filterFiles({fileDetails, + maximumFileSizeToCacheInBytes, modifyUrlPrefix, dontCacheBustUrlsMatching, + manifestTransforms}); + + if (warnings.length > 0) { + filteredFiles.warnings.push(...warnings); + } + + return filteredFiles; +}; diff --git a/node_modules/workbox-build/src/lib/get-file-size.js b/node_modules/workbox-build/src/lib/get-file-size.js new file mode 100644 index 00000000..2b73cb09 --- /dev/null +++ b/node_modules/workbox-build/src/lib/get-file-size.js @@ -0,0 +1,31 @@ +/* + Copyright 2017 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +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}'`); + } +}; diff --git a/node_modules/workbox-build/src/lib/get-string-details.js b/node_modules/workbox-build/src/lib/get-string-details.js new file mode 100644 index 00000000..e778336d --- /dev/null +++ b/node_modules/workbox-build/src/lib/get-string-details.js @@ -0,0 +1,25 @@ +/* + Copyright 2017 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +const getStringHash = require('./get-string-hash'); + +module.exports = (url, string) => { + return { + file: url, + hash: getStringHash(string), + size: string.length, + }; +}; diff --git a/node_modules/workbox-build/src/lib/get-string-hash.js b/node_modules/workbox-build/src/lib/get-string-hash.js new file mode 100644 index 00000000..934f5ab9 --- /dev/null +++ b/node_modules/workbox-build/src/lib/get-string-hash.js @@ -0,0 +1,23 @@ +/* + Copyright 2017 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +const crypto = require('crypto'); + +module.exports = (string) => { + const md5 = crypto.createHash('md5'); + md5.update(string); + return md5.digest('hex'); +}; diff --git a/node_modules/workbox-build/src/lib/maximum-size-transform.js b/node_modules/workbox-build/src/lib/maximum-size-transform.js new file mode 100644 index 00000000..2924ef22 --- /dev/null +++ b/node_modules/workbox-build/src/lib/maximum-size-transform.js @@ -0,0 +1,35 @@ +/* + Copyright 2017 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +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}; + }; +}; diff --git a/node_modules/workbox-build/src/lib/modify-url-prefix-transform.js b/node_modules/workbox-build/src/lib/modify-url-prefix-transform.js new file mode 100644 index 00000000..bdb83b50 --- /dev/null +++ b/node_modules/workbox-build/src/lib/modify-url-prefix-transform.js @@ -0,0 +1,79 @@ +/* + Copyright 2017 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +const errors = require('./errors'); + +/** + * Escaping user input to be treated as a literal string within a regular + * expression can be accomplished by simple replacement. + * + * From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions + * + * @private + * @param {string} string The string to be used as part of a regular + * expression + * @return {string} A string that is safe to use in a regular + * expression. + * + * @private + */ +const escapeRegExp = (string) => { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); +}; + +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}; + }; +}; diff --git a/node_modules/workbox-build/src/lib/no-revision-for-urls-matching-transform.js b/node_modules/workbox-build/src/lib/no-revision-for-urls-matching-transform.js new file mode 100644 index 00000000..e4d17c72 --- /dev/null +++ b/node_modules/workbox-build/src/lib/no-revision-for-urls-matching-transform.js @@ -0,0 +1,39 @@ +/* + Copyright 2017 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +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)) { + delete entry.revision; + } + + return entry; + }); + + return {manifest}; + }; +}; diff --git a/node_modules/workbox-build/src/lib/populate-sw-template.js b/node_modules/workbox-build/src/lib/populate-sw-template.js new file mode 100644 index 00000000..ff3baae4 --- /dev/null +++ b/node_modules/workbox-build/src/lib/populate-sw-template.js @@ -0,0 +1,94 @@ +/* + Copyright 2017 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +const template = require('lodash.template'); +const swTemplate = require('../templates/sw-template'); + +const errors = require('./errors'); +const runtimeCachingConverter = require('./runtime-caching-converter'); +const stringifyWithoutComments = require('./stringify-without-comments'); + +module.exports = ({ + cacheId, + clientsClaim, + directoryIndex, + ignoreUrlParametersMatching, + importScripts, + manifestEntries, + modulePathPrefix, + navigateFallback, + navigateFallbackBlacklist, + navigateFallbackWhitelist, + offlineGoogleAnalytics, + runtimeCaching, + skipWaiting, + workboxSWImport, +}) => { + // 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); + } + + try { + const populatedTemplate = template(swTemplate)({ + cacheId, + clientsClaim, + importScripts, + manifestEntries, + modulePathPrefix, + navigateFallback, + navigateFallbackBlacklist, + navigateFallbackWhitelist, + offlineAnalyticsConfigString, + precacheOptionsString, + skipWaiting, + runtimeCaching: runtimeCachingConverter(runtimeCaching), + workboxSWImport, + }); + + // Clean up multiple blank lines. + return populatedTemplate.replace(/\n{3,}/g, '\n\n').trim() + '\n'; + } catch (error) { + throw new Error( + `${errors['populating-sw-tmpl-failed']} '${error.message}'`); + } +}; diff --git a/node_modules/workbox-build/src/lib/runtime-caching-converter.js b/node_modules/workbox-build/src/lib/runtime-caching-converter.js new file mode 100644 index 00000000..7082379e --- /dev/null +++ b/node_modules/workbox-build/src/lib/runtime-caching-converter.js @@ -0,0 +1,157 @@ +/* + Copyright 2017 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +const ol = require('common-tags').oneLine; + +const errors = require('./errors'); +const stringifyWithoutComments = require('./stringify-without-comments'); + +/** + * Given a set of options that configures `sw-toolbox`'s behavior, convert it + * into a string that would configure equivalent `workbox-sw` behavior. + * + * @param {Object} options See + * https://googlechrome.github.io/sw-toolbox/api.html#options + * @return {string} A JSON string representing the equivalent options. + * + * @private + */ +function getOptionsString(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]; + } + } + + const pluginsMapping = { + backgroundSync: 'workbox.backgroundSync.Plugin', + broadcastUpdate: 'workbox.broadcastUpdate.Plugin', + expiration: 'workbox.expiration.Plugin', + cacheableResponse: 'workbox.cacheableResponse.Plugin', + }; + + for (const [pluginName, pluginConfig] of Object.entries(options)) { + // Ensure that we have some valid configuration to pass to Plugin(). + if (Object.keys(pluginConfig).length === 0) { + continue; + } + + const pluginString = pluginsMapping[pluginName]; + if (!pluginString) { + throw new Error(`${errors['bad-runtime-caching-config']} ${pluginName}`); + } + + let pluginCode; + switch (pluginName) { + // Special case logic for plugins that have a required parameter, and then + // an additional optional config parameter. + case 'backgroundSync': { + const name = pluginConfig.name; + pluginCode = `new ${pluginString}(${JSON.stringify(name)}`; + if ('options' in pluginConfig) { + pluginCode += `, ${JSON.stringify(pluginConfig.options)}`; + } + pluginCode += `)`; + + break; + } + + case 'broadcastUpdate': { + const channelName = pluginConfig.channelName; + pluginCode = `new ${pluginString}(${JSON.stringify(channelName)}`; + if ('options' in pluginConfig) { + pluginCode += `, ${JSON.stringify(pluginConfig.options)}`; + } + pluginCode += `)`; + + break; + } + + // For plugins that just pass in an Object to the constructor, like + // expiration and cacheableResponse + default: { + pluginCode = `new ${pluginString}(${JSON.stringify(pluginConfig)})`; + } + } + + 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 = (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 either a string or a RegExp object. + // If it's a string, it needs to be quoted. If it's a RegExp, it should + // be used as-is. + const matcher = typeof entry.urlPattern === 'string' ? + JSON.stringify(entry.urlPattern) : + entry.urlPattern; + + if (typeof entry.handler === 'string') { + const optionsString = getOptionsString(entry.options || {}); + + const strategyString = + `workbox.strategies.${entry.handler}(${optionsString})`; + + return `workbox.routing.registerRoute(` + + `${matcher}, ${strategyString}, '${method}');\n`; + } else if (typeof entry.handler === 'function') { + return `workbox.routing.registerRoute(` + + `${matcher}, ${entry.handler}, '${method}');\n`; + } + }).filter((entry) => Boolean(entry)); // Remove undefined map() return values. +}; diff --git a/node_modules/workbox-build/src/lib/stringify-without-comments.js b/node_modules/workbox-build/src/lib/stringify-without-comments.js new file mode 100644 index 00000000..8429ff7d --- /dev/null +++ b/node_modules/workbox-build/src/lib/stringify-without-comments.js @@ -0,0 +1,24 @@ +/* + Copyright 2018 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +const objectStringify = require('stringify-object'); +const stripComments = require('strip-comments'); + +module.exports = (obj) => { + return objectStringify(obj, { + transform: (_obj, _prop, str) => stripComments(str), + }); +}; diff --git a/node_modules/workbox-build/src/lib/use-build-type.js b/node_modules/workbox-build/src/lib/use-build-type.js new file mode 100644 index 00000000..ae21b72e --- /dev/null +++ b/node_modules/workbox-build/src/lib/use-build-type.js @@ -0,0 +1,49 @@ +/* + Copyright 2017 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +// This is the build type that is expected to be present "by default". +const DEFAULT_BUILD_TYPE = 'prod'; + +/** + * Switches a string from using the "default" build type to an alternative + * build type. In practice, this is used to swap out "prod" for "dev" in the + * filename of a Workbox library. + * + * @param {string} source The path to a file, which will normally contain + * DEFAULT_BUILD_TYPE somewhere in it. + * @param {string} buildType The alternative build type value to swap in. + * @return {string} source, with the last occurrence of DEFAULT_BUILD_TYPE + * replaced with buildType. + * @private + */ +module.exports = (source, buildType) => { + // If we want the DEFAULT_BUILD_TYPE, then just return things as-is. + if (buildType === DEFAULT_BUILD_TYPE) { + return source; + } + // Otherwise, look for the last instance of DEFAULT_BUILD_TYPE, and replace it + // with the new buildType. This is easier via split/join than RegExp. + const parts = source.split(DEFAULT_BUILD_TYPE); + // Join the last two split parts with the new buildType. (If parts only has + // one item, this will be a no-op.) + const replaced = parts.slice(parts.length - 2).join(buildType); + // Take the remaining parts, if any exist, and join them with the replaced + // part using the DEFAULT_BUILD_TYPE, to restore any other matches as-is. + return [ + ...parts.slice(0, parts.length - 2), + replaced, + ].join(DEFAULT_BUILD_TYPE); +}; diff --git a/node_modules/workbox-build/src/lib/write-sw-using-default-template.js b/node_modules/workbox-build/src/lib/write-sw-using-default-template.js new file mode 100644 index 00000000..4a573775 --- /dev/null +++ b/node_modules/workbox-build/src/lib/write-sw-using-default-template.js @@ -0,0 +1,75 @@ +/* + Copyright 2017 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +const fse = require('fs-extra'); +const path = require('path'); + +const errors = require('./errors'); +const populateSWTemplate = require('./populate-sw-template'); + +module.exports = async ({ + cacheId, + clientsClaim, + directoryIndex, + handleFetch, + ignoreUrlParametersMatching, + importScripts, + manifestEntries, + modulePathPrefix, + navigateFallback, + navigateFallbackBlacklist, + navigateFallbackWhitelist, + offlineGoogleAnalytics, + runtimeCaching, + skipWaiting, + swDest, + workboxSWImport, +}) => { + try { + await fse.mkdirp(path.dirname(swDest)); + } catch (error) { + throw new Error(`${errors['unable-to-make-sw-directory']}. ` + + `'${error.message}'`); + } + + const populatedTemplate = populateSWTemplate({ + cacheId, + clientsClaim, + directoryIndex, + handleFetch, + ignoreUrlParametersMatching, + importScripts, + manifestEntries, + modulePathPrefix, + navigateFallback, + navigateFallbackBlacklist, + navigateFallbackWhitelist, + offlineGoogleAnalytics, + runtimeCaching, + skipWaiting, + workboxSWImport, + }); + + try { + await fse.writeFile(swDest, populatedTemplate); + } 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}'`); + } +}; -- cgit v1.2.3