Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add in asset filename filtering via {test, include, exclude} #1149

Merged
merged 2 commits into from
Jan 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 6 additions & 13 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
"firebase-tools": "^3.13.1",
"fs-extra": "^4.0.1",
"geckodriver": "^1.8.1",
"generate-asset-webpack-plugin": "^0.3.0",
"github": "^12.0.1",
"glob": "^7.1.2",
"gulp": "github:gulpjs/gulp#4.0",
Expand Down
3 changes: 3 additions & 0 deletions packages/workbox-webpack-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
"json-stable-stringify": "^1.0.1",
"workbox-build": "^3.0.0-alpha.3"
},
"peerDependencies": {
"webpack": "^2.0.0 || ^3.0.0"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems unusual to me, is it stipulating that workbox only works with Webpack 2 and 3 (i.e. not 4)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am following UglifyJS's lead here in limited the acceptable peer dependency: https://github.com/webpack-contrib/uglifyjs-webpack-plugin/blob/025262284c86196d0a4c4fe71e186132579629ec/package.json#L75-L77

(My understanding is that webpack 4 changes the plugin architecture anyway, so I think we should track that separately: #1151)

},
"author": "Will Farley <a.will.farley@gmail.com> (http://www.willfarley.org/)",
"license": "Apache-2.0",
"repository": "googlechrome/workbox",
Expand Down
6 changes: 6 additions & 0 deletions packages/workbox-webpack-plugin/src/generate-sw.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ class GenerateSW {
constructor(config = {}) {
this.config = Object.assign({}, {
chunks: [],
exclude: [
// Exclude source maps.
/\.map$/,
// Exclude anything starting with manifest and ending .js or .json.
/^manifest.*\.js(?:on)?$/,
],
excludeChunks: [],
importScripts: [],
importWorkboxFrom: 'cdn',
Expand Down
6 changes: 6 additions & 0 deletions packages/workbox-webpack-plugin/src/inject-manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ class InjectManifest {

this.config = Object.assign({}, {
chunks: [],
exclude: [
// Exclude source maps.
/\.map$/,
// Exclude anything starting with manifest and ending .js or .json.
/^manifest.*\.js(?:on)?$/,
],
excludeChunks: [],
importScripts: [],
importWorkboxFrom: 'cdn',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
limitations under the License.
*/

const ModuleFilenameHelpers = require('webpack/lib/ModuleFilenameHelpers');

const getAssetHash = require('./get-asset-hash');
const resolveWebpackUrl = require('./resolve-webpack-url');

Expand Down Expand Up @@ -177,6 +179,13 @@ function getManifestEntriesFromCompilation(compilation, config) {

const manifestEntries = [];
for (const [file, metadata] of Object.entries(filteredAssetMetadata)) {
// Filter based on test/include/exclude options set in the config,
// following webpack's conventions.
// This matches the behavior of, e.g., UglifyJS's webpack plugin.
if (!ModuleFilenameHelpers.matchObject(config, file)) {
continue;
}

const publicUrl = resolveWebpackUrl(publicPath, file);
const manifestEntry = getEntry(knownHashes, publicUrl, metadata.hash);
manifestEntries.push(manifestEntry);
Expand Down
6 changes: 6 additions & 0 deletions packages/workbox-webpack-plugin/src/lib/sanitize-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,14 @@
function forGetManifest(originalConfig) {
const propertiesToRemove = [
'chunks',
'exclude',
'excludeChunks',
'importScripts',
'importWorkboxFrom',
'include',
'swDest',
'swSrc',
'test',
];

return sanitizeConfig(originalConfig, propertiesToRemove);
Expand All @@ -46,9 +49,12 @@ function forGetManifest(originalConfig) {
function forGenerateSWString(originalConfig) {
const propertiesToRemove = [
'chunks',
'exclude',
'excludeChunks',
'importWorkboxFrom',
'include',
'swDest',
'test',
];

return sanitizeConfig(originalConfig, propertiesToRemove);
Expand Down
248 changes: 248 additions & 0 deletions test/workbox-webpack-plugin/node/generate-sw.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const CopyWebpackPlugin = require('copy-webpack-plugin');
const GenerateAssetPlugin = require('generate-asset-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const expect = require('chai').expect;
const fse = require('fs-extra');
Expand Down Expand Up @@ -655,4 +656,251 @@ describe(`[workbox-webpack-plugin] GenerateSW (End to End)`, function() {
});
});
});

describe(`[workbox-webpack-plugin] Filtering via test/include/exclude`, function() {
const TEST_ASSET_CB = (compilation, callback) => callback(null, 'test');

it(`should exclude .map and manifest.js(on) files by default`, function(done) {
const FILE_MANIFEST_NAME = 'precache-manifest.43591bdf46c7ac47eb8d7b2bcd41f13e.js';
const outputDir = tempy.directory();
const config = {
entry: path.join(SRC_DIR, WEBPACK_ENTRY_FILENAME),
output: {
filename: WEBPACK_ENTRY_FILENAME,
path: outputDir,
},
devtool: 'source-map',
plugins: [
new GenerateAssetPlugin({
filename: 'manifest.js',
fn: TEST_ASSET_CB,
}),
new GenerateAssetPlugin({
filename: 'manifest.json',
fn: TEST_ASSET_CB,
}),
new GenerateSW(),
],
};

const compiler = webpack(config);
compiler.run(async (webpackError) => {
if (webpackError) {
return done(webpackError);
}

const swFile = path.join(outputDir, 'service-worker.js');
try {
// First, validate that the generated service-worker.js meets some basic assumptions.
await validateServiceWorkerRuntime({swFile, expectedMethodCalls: {
importScripts: [[
FILE_MANIFEST_NAME,
WORKBOX_SW_FILE_NAME,
]],
suppressWarnings: [[]],
precacheAndRoute: [[[], {}]],
}});

// Next, test the generated manifest to ensure that it contains
// exactly the entries that we expect.
const manifestFileContents = await fse.readFile(path.join(outputDir, FILE_MANIFEST_NAME), 'utf-8');
const context = {self: {}};
vm.runInNewContext(manifestFileContents, context);

const expectedEntries = [{
revision: '8e8e9f093f036bd18dfa',
url: 'webpackEntry.js',
}];
expect(context.self.__precacheManifest).to.eql(expectedEntries);

done();
} catch (error) {
done(error);
}
});
});

it(`should allow developers to override the default exclude filter`, function(done) {
const FILE_MANIFEST_NAME = 'precache-manifest.b87ef85173e527290f94979b09e72d12.js';
const outputDir = tempy.directory();
const config = {
entry: path.join(SRC_DIR, WEBPACK_ENTRY_FILENAME),
output: {
filename: WEBPACK_ENTRY_FILENAME,
path: outputDir,
},
devtool: 'source-map',
plugins: [
new GenerateSW({
exclude: [],
}),
],
};

const compiler = webpack(config);
compiler.run(async (webpackError) => {
if (webpackError) {
return done(webpackError);
}

const swFile = path.join(outputDir, 'service-worker.js');
try {
// First, validate that the generated service-worker.js meets some basic assumptions.
await validateServiceWorkerRuntime({swFile, expectedMethodCalls: {
importScripts: [[
FILE_MANIFEST_NAME,
WORKBOX_SW_FILE_NAME,
]],
suppressWarnings: [[]],
precacheAndRoute: [[[], {}]],
}});

// Next, test the generated manifest to ensure that it contains
// exactly the entries that we expect.
const manifestFileContents = await fse.readFile(path.join(outputDir, FILE_MANIFEST_NAME), 'utf-8');
const context = {self: {}};
vm.runInNewContext(manifestFileContents, context);

const expectedEntries = [{
revision: '8e8e9f093f036bd18dfa',
url: 'webpackEntry.js.map',
}, {
revision: '8e8e9f093f036bd18dfa',
url: 'webpackEntry.js',
}];
expect(context.self.__precacheManifest).to.eql(expectedEntries);

done();
} catch (error) {
done(error);
}
});
});

it(`should allow developers to whitelist via include`, function(done) {
const FILE_MANIFEST_NAME = 'precache-manifest.1242f9e007897f035a52e56690ff17a6.js';
const outputDir = tempy.directory();
const config = {
entry: path.join(SRC_DIR, WEBPACK_ENTRY_FILENAME),
output: {
filename: WEBPACK_ENTRY_FILENAME,
path: outputDir,
},
devtool: 'source-map',
plugins: [
new CopyWebpackPlugin([{
from: SRC_DIR,
to: outputDir,
}]),
new GenerateSW({
include: [/.html$/],
}),
],
};

const compiler = webpack(config);
compiler.run(async (webpackError) => {
if (webpackError) {
return done(webpackError);
}

const swFile = path.join(outputDir, 'service-worker.js');
try {
// First, validate that the generated service-worker.js meets some basic assumptions.
await validateServiceWorkerRuntime({swFile, expectedMethodCalls: {
importScripts: [[
FILE_MANIFEST_NAME,
WORKBOX_SW_FILE_NAME,
]],
suppressWarnings: [[]],
precacheAndRoute: [[[], {}]],
}});

// Next, test the generated manifest to ensure that it contains
// exactly the entries that we expect.
const manifestFileContents = await fse.readFile(path.join(outputDir, FILE_MANIFEST_NAME), 'utf-8');
const context = {self: {}};
vm.runInNewContext(manifestFileContents, context);

const expectedEntries = [{
revision: 'a3a71ce0b9b43c459cf58bd37e911b74',
url: 'page-2.html',
}, {
revision: '544658ab25ee8762dc241e8b1c5ed96d',
url: 'page-1.html',
}, {
revision: '3883c45b119c9d7e9ad75a1b4a4672ac',
url: 'index.html',
}];
expect(context.self.__precacheManifest).to.eql(expectedEntries);

done();
} catch (error) {
done(error);
}
});
});

it(`should allow developers to combine the test and exclude filters`, function(done) {
const FILE_MANIFEST_NAME = 'precache-manifest.83df65831eb442f8ad5fbeb8edecc558.js';
const outputDir = tempy.directory();
const config = {
entry: path.join(SRC_DIR, WEBPACK_ENTRY_FILENAME),
output: {
filename: WEBPACK_ENTRY_FILENAME,
path: outputDir,
},
devtool: 'source-map',
plugins: [
new CopyWebpackPlugin([{
from: SRC_DIR,
to: outputDir,
}]),
new GenerateSW({
test: [/.html$/],
exclude: [/index/],
}),
],
};

const compiler = webpack(config);
compiler.run(async (webpackError) => {
if (webpackError) {
return done(webpackError);
}

const swFile = path.join(outputDir, 'service-worker.js');
try {
// First, validate that the generated service-worker.js meets some basic assumptions.
await validateServiceWorkerRuntime({swFile, expectedMethodCalls: {
importScripts: [[
FILE_MANIFEST_NAME,
WORKBOX_SW_FILE_NAME,
]],
suppressWarnings: [[]],
precacheAndRoute: [[[], {}]],
}});

// Next, test the generated manifest to ensure that it contains
// exactly the entries that we expect.
const manifestFileContents = await fse.readFile(path.join(outputDir, FILE_MANIFEST_NAME), 'utf-8');
const context = {self: {}};
vm.runInNewContext(manifestFileContents, context);

const expectedEntries = [{
revision: 'a3a71ce0b9b43c459cf58bd37e911b74',
url: 'page-2.html',
}, {
revision: '544658ab25ee8762dc241e8b1c5ed96d',
url: 'page-1.html',
}];
expect(context.self.__precacheManifest).to.eql(expectedEntries);

done();
} catch (error) {
done(error);
}
});
});
});
});
Loading