Skip to content

Commit

Permalink
adds prependManifest and PrependManifestPlugin
Browse files Browse the repository at this point in the history
  • Loading branch information
anilanar committed Aug 9, 2017
1 parent 155f103 commit 8cafb93
Show file tree
Hide file tree
Showing 15 changed files with 325 additions and 5 deletions.
2 changes: 2 additions & 0 deletions packages/workbox-build/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const generateSW = require('./lib/generate-sw');
const getFileManifestEntries = require('./lib/get-file-manifest-entries');
const generateFileManifest = require('./lib/generate-file-manifest');
const injectManifest = require('./lib/inject-manifest');
const prependManifest = require('./lib/prepend-manifest');

/**
* # workbox-build
Expand Down Expand Up @@ -88,4 +89,5 @@ module.exports = {
generateFileManifest,
getFileManifestEntries,
injectManifest,
prependManifest,
};
2 changes: 2 additions & 0 deletions packages/workbox-build/src/lib/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ module.exports = {
`an object with string key value pairs.`,
'invalid-inject-manifest-arg': `The input to 'injectManifest()' must be ` +
`be an object.`,
'invalid-prepend-manifest-arg': `The input to 'prependManifest()' must be ` +
`be an object.`,
'injection-point-not-found': `Unable to find a place to inject the ` +
`manifest. Please ensure that you have 'workboxSW.precache([])' ` +
`somewhere in your service worker file.`,
Expand Down
3 changes: 2 additions & 1 deletion packages/workbox-build/src/lib/generate-file-manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const getFileManifestEntries = require('./get-file-manifest-entries');
const writeFileManifest = require('./utils/write-file-manifest');
const isValidInput = require('./utils/is-valid-input');
const errors = require('./errors');

/**
Expand Down Expand Up @@ -65,7 +66,7 @@ const errors = require('./errors');
* @memberof module:workbox-build
*/
const generateFileManifest = (input) => {
if (!input || typeof input !== 'object' || Array.isArray(input)) {
if (!isValidInput(input)) {
return Promise.reject(
new Error(errors['invalid-generate-file-manifest-arg']));
}
Expand Down
3 changes: 2 additions & 1 deletion packages/workbox-build/src/lib/generate-sw.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const path = require('path');
const copyWorkboxSW = require('./utils/copy-workbox-sw');
const isValidInput = require('./utils/is-valid-input');
const getFileManifestEntries = require('./get-file-manifest-entries');
const writeServiceWorker = require('./write-sw');
const errors = require('./errors');
Expand Down Expand Up @@ -99,7 +100,7 @@ const constants = require('./constants');
* @memberof module:workbox-build
*/
const generateSW = function(input) {
if (!input || typeof input !== 'object' || Array.isArray(input)) {
if (!isValidInput(input)) {
return Promise.reject(new Error(errors['invalid-generate-sw-input']));
}

Expand Down
3 changes: 2 additions & 1 deletion packages/workbox-build/src/lib/get-file-manifest-entries.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const filterFiles = require('./utils/filter-files');
const getCompositeDetails = require('./utils/get-composite-details');
const getFileDetails = require('./utils/get-file-details');
const getStringDetails = require('./utils/get-string-details');
const isValidInput = require('./utils/is-valid-input');
const constants = require('./constants');

/**
Expand Down Expand Up @@ -55,7 +56,7 @@ const constants = require('./constants');
* @memberof module:workbox-build
*/
const getFileManifestEntries = (input) => {
if (!input || typeof input !== 'object' || Array.isArray(input)) {
if (!isValidInput(input)) {
return Promise.reject(
new Error(errors['invalid-get-manifest-entries-input']));
}
Expand Down
5 changes: 3 additions & 2 deletions packages/workbox-build/src/lib/inject-manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const fs = require('fs');
const mkdirp = require('mkdirp');
const path = require('path');

const isValidInput = require('./utils/is-valid-input');
const getFileManifestEntries = require('./get-file-manifest-entries');
const errors = require('./errors');

Expand Down Expand Up @@ -66,7 +67,7 @@ const errors = require('./errors');
* @memberof module:workbox-build
*/
const injectManifest = (input) => {
if (!input || typeof input !== 'object' || Array.isArray(input)) {
if (!isValidInput(input)) {
return Promise.reject(
new Error(errors['invalid-inject-manifest-arg']));
}
Expand Down Expand Up @@ -94,7 +95,7 @@ const injectManifest = (input) => {
if (err) {
return reject(
new Error(
errors['unable-to-make-injection-directory'] +
errors['unable-to-make-sw-directory'] +
` '${err.message}'`
)
);
Expand Down
102 changes: 102 additions & 0 deletions packages/workbox-build/src/lib/prepend-manifest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
'use strict';

const fs = require('fs');
const mkdirp = require('mkdirp');
const path = require('path');

const isValidInput = require('./utils/is-valid-input');
const getFileManifestEntries = require('./get-file-manifest-entries');
const errors = require('./errors');

/**
* This method will read an existing service worker file and prepend it with
* an array of assets to precache. The array is assigned to
* `self.__file_manifest`. This allows the service worker to use the manifest
* for other purposes or mutate it before precaching.
*
* @param {Object} input
* @param {String} input.swSrc File path and name of the service worker file
* to read and inject the manifest into before writing to `swDest`.
* @param {String} input.globDirectory The directory you wish to run the
* `globPatterns` against.
* @param {Array<String>} input.globPatterns Files matching against any of
* these glob patterns will be included in the file manifest.
*
* Defaults to ['**\/*.{js,css}']
* @param {String|Array<String>} [input.globIgnores] Files matching against any
* of these glob patterns will be excluded from the file manifest, even if the
* file matches against a `globPatterns` pattern. Defaults to ignoring
* 'node_modules'.
* @param {Object<String,Array|String>} [input.templatedUrls]
* If a URL is rendered with templates on the server, its contents may
* depend on multiple files. This maps URLs to an array of file names, or to a
* string value, that uniquely determines the URL's contents.
* @param {String} [input.modifyUrlPrefix] An object of key value pairs
* where URL's starting with the key value will be replaced with the
* corresponding value.
* @param {number} [input.maximumFileSizeToCacheInBytes] This value can be used
* to determine the maximum size of files that will be precached.
*
* Defaults to 2MB.
* @param {RegExp} [input.dontCacheBustUrlsMatching] An optional regex that will
* return a URL string and exclude the revision details for urls matching this
* regex. Useful if you have assets with file revisions in the URL.
* @param {Array<ManifestTransform>} [input.manifestTransforms] A list of
* manifest transformations, which will be applied sequentially against the
* generated manifest. If `modifyUrlPrefix` or `dontCacheBustUrlsMatching` are
* also specified, their corresponding transformations will be applied first.
* @return {Promise} Resolves once the service worker has been written
* with the prepended precache list.
*
* @example <caption>Prepend a manifest of static assets, which could
* then be used with a service worker.</caption>
* const swBuild = require('workbox-build');
*
* swBuild.prependManifest({
* globDirectory: './build/',
* globPatterns: ['**\/*.{html,js,css}'],
* globIgnores: ['admin.html'],
* swSrc: './src/sw.js',
* swDest: './build/sw.js',
* manifestVariable: 'assetManifest',
* })
* .then(() => {
* console.log('Build Manifest generated.');
* });
*
* @memberof module:workbox-build
*/
const prependManifest = (input) => {
if (!isValidInput(input)) {
return Promise.reject(
new Error(errors['invalid-prepend-manifest-arg']));
}

return getFileManifestEntries(input)
.then((manifestEntries) => {
let swFileContents = fs.readFileSync(input.swSrc, 'utf8');

const entriesString = JSON.stringify(manifestEntries, null, 2);
swFileContents =
`self.__file_manifest = ${entriesString};\n${swFileContents}`;

return new Promise((resolve, reject) => {
mkdirp(path.dirname(input.swDest), (err) => {
if (err) {
return reject(
new Error(
errors['unable-to-make-sw-directory'] +
` '${err.message}'`
)
);
}
resolve();
});
})
.then(() => {
fs.writeFileSync(input.swDest, swFileContents);
});
});
};

module.exports = prependManifest;
3 changes: 3 additions & 0 deletions packages/workbox-build/src/lib/utils/is-valid-input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = (input) => input
&& typeof input === 'object'
&& !Array.isArray(input);
58 changes: 58 additions & 0 deletions packages/workbox-build/test/node/prepend-manifest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
const path = require('path');
const fs = require('fs');
const fsExtra = require('fs-extra');
const expect = require('chai').expect;

const swBuild = require('../../build/index.js');

describe(`Test Prepend Manifest`, function() {
let tmpDirectory;

before(function() {
tmpDirectory = fs.mkdtempSync(
path.join(__dirname, 'tmp-')
);
});

after(function() {
fsExtra.removeSync(tmpDirectory);
});

const TEST_INPUT_FILE = 'service-worker.js';
const expectedString = `self.__file_manifest = [
{
"url": "index.css",
"revision": "d41d8cd98f00b204e9800998ecf8427e"
},
{
"url": "index.html",
"revision": "d41d8cd98f00b204e9800998ecf8427e"
}
];\n`;
it(`should be able to read and prepend service worker`, function() {
const swDest = path.join(tmpDirectory, `sw.js`);
return swBuild.prependManifest({
globDirectory: path.join(
__dirname,
'..',
'static',
'prepend-samples',
'assets',
),
globPatterns: ['**/*.{html,css}'],
swSrc: path.join(
__dirname,
'..',
'static',
'prepend-samples',
TEST_INPUT_FILE,
),
swDest,
})
.then(() => {
const fileOutput = fs.readFileSync(swDest).toString();
const manifestPart = fileOutput.substr(0, expectedString.length);
expect(manifestPart).to.equal(expectedString);
});
});
});
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
const workboxSW = new WorkboxSW();
workboxSW.precache([self.__file_manifest]);
2 changes: 2 additions & 0 deletions packages/workbox-webpack-plugin/src/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const GenerateFileManifestPlugin = require('./lib/generate-file-manifest');
const GenerateSWPlugin = require('./lib/generate-sw');
const InjectManifestPlugin = require('./lib/inject-manifest');
const PrependManifestPlugin = require('./lib/prepend-manifest');

/**
* Use one of the plugins to integrate a webpack project with
Expand Down Expand Up @@ -35,4 +36,5 @@ module.exports = {
GenerateSWPlugin,
GenerateFileManifestPlugin,
InjectManifestPlugin,
PrependManifestPlugin,
};
70 changes: 70 additions & 0 deletions packages/workbox-webpack-plugin/src/lib/prepend-manifest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
const swBuild = require('workbox-build');
const path = require('path');
const BasePlugin = require('./base-plugin');
const errors = require('./errors');

/**
* An instance of this plugin prepends a file with the manifest assigned to
* `self.__file_manifest`. The manifest is generated using
* [workbox-build:getFileManifestEntries]{@link
* module:workbox-build.getFileManifestEntries}.
*
* @memberof module:workbox-webpack-plugin
*/
class PrependManifestPlugin extends BasePlugin {
/**
* Create a new instance of `PrependManifestPlugin`.
*
* @param {Object} [config] All the options as passed to
* [workbox-build:getFileManifestEntries]{@link
* module:workbox-build.injectManifest}. See
* [workbox-build:getFileManifestEntries]{@link
* module:workbox-build.injectManifest} for all possible options.
* @param {String} [config.swSrc] When invalid, compilation throws an error.
* @param {String} [config.swDest] Defaults to `%{outputPath}/sw.js`.
*/
constructor(config) {
super(config);
}
/**
* @private
* @param {Object} compilation The [compilation](https://github.com/webpack/docs/wiki/how-to-write-a-plugin#accessing-the-compilation),
* passed from Webpack to this plugin.
* @throws Throws an error if `swSrc` option is invalid.
* @return {Object} The configuration for a given compilation.
*/
getConfig(compilation) {
const config = super.getConfig(compilation);

if (!config.swSrc) {
throw new Error(errors['invalid-sw-src']);
}

if (!config.swDest) {
config.swDest = path.join(compilation.options.output.path, 'sw.js');
}

return config;
}
/**
* This method uses [workbox-build:injectManifest]{
* @link module:workbox-build.injectManifest} to generate a manifest file.
*
* @private
* @param {Object} compilation The [compilation](https://github.com/webpack/docs/wiki/how-to-write-a-plugin#accessing-the-compilation),
* @param {Function} [callback] function that must be invoked when handler
* finishes running.
*/
handleAfterEmit(compilation, callback) {
try {
const config = this.getConfig(compilation, callback);
swBuild.prependManifest(config)
.then(() => callback())
.catch((e) => callback(e));
} catch (e) {
callback(e);
}
}
}

module.exports = PrependManifestPlugin;
Loading

0 comments on commit 8cafb93

Please sign in to comment.