Skip to content
This repository has been archived by the owner on Jan 21, 2021. It is now read-only.

Commit

Permalink
Merge pull request #36 from laysent/master
Browse files Browse the repository at this point in the history
Provide a way to include all assets (issue #35)
  • Loading branch information
jeffposnick authored Feb 28, 2018
2 parents e29cdd4 + 40a1220 commit 0f80892
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 19 deletions.
55 changes: 49 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,14 @@ will be injected into the document `<head>`:
<link rel="preload" as="script" href="chunk.d15e7fdfc91b34bb78c4.js">
```

You can also configure the plugin to preload all chunks (vendor, async, normal chunks) using `include: 'all'`, or only preload initial chunks with `include: 'initial'`:
You can also configure the plugin to preload all chunks (vendor, async, normal chunks) using `include: 'allChunks'`, or only preload initial chunks with `include: 'initial'`:

```js
plugins: [
new HtmlWebpackPlugin(),
new PreloadWebpackPlugin({
rel: 'preload',
include: 'all' // or 'initial'
include: 'allChunks' // or 'initial'
})
]
```
Expand All @@ -161,6 +161,28 @@ will inject just this:
<link rel="preload" as="script" href="home.31132ae6680e598f8879.js">
```

It is very common in Webpack to use loaders such as `file-loader` to generate assets for specific
types, such as fonts or images. If you wish to preload these files as well, you can use `include`
with value `allAssets`:

```js
plugins: [
new HtmlWebpackPlugin(),
new PreloadWebpackPlugin({
rel: 'preload',
include: 'allAssets',
})
]
```

One thing worth noticing: `file-loader` provides an option to specify `publicPath` just for assets.
However, that information seems to be lost when this plugin is doing its job. Thus, this plugin
will use `publicPath` defined in `output` config. It could be an issue, if `publicPath` in `file-loader`
and `publicPath` in `webpack` config have different values.

Usually you don't want to preload all of them but only keep the necessary resources, you can use
`fileBlacklist` or `fileWhitelist` shown below to filter.

Filtering chunks
---------------------

Expand All @@ -180,9 +202,31 @@ new PreloadWebpackPlugin({
})
```

## Filtering Html
If you use `include="allAssets"`, you might find excluding all unnecessary files one by one a
bit annoying. In this case, you can use `fileWhitelist` to only include the files you want:

```js
new PreloadWebpackPlugin({
fileWhitelist: [/\.files/, /\.to/, /\.include/],
})
```

notice that if `fileWhitelist` is not provided, it will not filter any file out.

Also, you could use `fileWhitelist` and `fileBlacklist` together:

```js
new PreloadWebpackPlugin({
fileWhitelist: [/\.files/, /\.to/, /\.include/],
fileBlacklist: [/\.files/, /\.to/, /\.exclude/],
})
```

In example above, only files with name matches `/\.include/` will be included.

In some case, you may don't want to preload resource on some file. But using `fileBlacklist` is werid, because you may want to inlcude this chunk on another file. So you can use `excludeHtmlNames` to tell preload plugin to ignore this file.
## Filtering HTML

In some case, you may don't want to preload resource on some file. But using `fileBlacklist` is weird, because you may want to inlcude this chunk on another file. So you can use `excludeHtmlNames` to tell preload plugin to ignore this file.

If you have multiple html like index.html and example.html, you can exclude index.html like this.

Expand All @@ -201,8 +245,7 @@ plugins: [
// I want this to affect only index.html
new PreloadWebpackPlugin({
excludeHtmlNames: ['index.html'],
})
]
})
```

Resource Hints
Expand Down
29 changes: 23 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,16 @@ class PreloadPlugin {
} catch (e) {
extractedChunks = compilation.chunks;
}
} else if (options.include === 'all') {
// Async chunks, vendor chunks, normal chunks.
} else if (options.include === 'allChunks' || options.include === 'all') {
if (options.include === 'all') {
/* eslint-disable no-console */
console.warn('[WARNING]: { include: "all" } is deprecated, please use "allChunks" instead.');
/* eslint-enable no-console */
}
// Async chunks, vendor chunks, normal chunks.
extractedChunks = compilation.chunks;
} else if (options.include === 'allAssets') {
extractedChunks = [{files: Object.keys(compilation.assets)}];
} else if (Array.isArray(options.include)) {
// Keep only user specified chunks
extractedChunks = compilation
Expand All @@ -103,11 +110,21 @@ class PreloadPlugin {

const publicPath = compilation.outputOptions.publicPath || '';

// Only handle the chunk import by the htmlWebpackPlugin
extractedChunks = extractedChunks.filter(chunk => doesChunkBelongToHTML(
chunk, Object.values(htmlPluginData.assets.chunks), {}));
// only handle the chunks associated to this htmlWebpackPlugin instance, in case of multiple html plugin outputs
// allow `allAssets` mode to skip, as assets are just files to be filtered by black/whitelist, not real chunks
if (options.include !== 'allAssets') {
extractedChunks = extractedChunks.filter(chunk => doesChunkBelongToHTML(
chunk, Object.values(htmlPluginData.assets.chunks), {}));
}

flatten(extractedChunks.map(chunk => chunk.files)).filter(entry => {
flatten(extractedChunks.map(chunk => chunk.files))
.filter(entry => {
return (
!this.options.fileWhitelist ||
this.options.fileWhitelist.some(regex => regex.test(entry) === true)
);
})
.filter(entry => {
return this.options.fileBlacklist.every(regex => regex.test(entry) === false);
}).forEach(entry => {
entry = `${publicPath}${entry}`;
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,14 @@
"homepage": "https://github.com/googlechromelabs/preload-webpack-plugin",
"devDependencies": {
"babel-eslint": "^7.1.1",
"css-loader": "^0.28.7",
"eslint": "^3.14.1",
"eslint-config-google": "^0.7.1",
"extract-text-webpack-plugin": "^3.0.0",
"file-loader": "^0.11.2",
"html-webpack-plugin": "^2.26.0",
"jasmine": "^2.5.3",
"webpack": "^3.2.0"
"webpack": "^3.4.0"
},
"peerDependencies": {
"webpack": "^3.2.0"
Expand Down
Empty file added test/fixtures/font.woff2
Empty file.
22 changes: 22 additions & 0 deletions test/fixtures/load-css.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* @license
* 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
*
* http://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.
*/
console.log('lol');
console.log(require('./style.css'));
require.ensure(["./home.js"], function() {
// var a = require("module-a");
// console.log(a);
}, 'home');
4 changes: 4 additions & 0 deletions test/fixtures/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@font-face {
font-family: test;
src: url(./font.woff2);
}
101 changes: 95 additions & 6 deletions test/spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const PreloadPlugin = require('../');
const OUTPUT_DIR = path.join(__dirname, 'dist');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

describe('PreloadPlugin preloads or prefetches async chunks', function() {
it('adds preload tags to async chunks', function(done) {
Expand Down Expand Up @@ -120,7 +121,7 @@ describe('PreloadPlugin preloads normal chunks', function() {
new PreloadPlugin({
rel: 'preload',
as: 'script',
include: 'all'
include: 'allChunks'
})
]
}, function(err, result) {
Expand Down Expand Up @@ -149,7 +150,7 @@ describe('PreloadPlugin preloads normal chunks', function() {
new HtmlWebpackPlugin(),
new PreloadPlugin({
rel: 'preload',
include: 'all'
include: 'allChunks'
})
]
}, function(err, result) {
Expand Down Expand Up @@ -177,7 +178,7 @@ describe('PreloadPlugin preloads normal chunks', function() {
new PreloadPlugin({
rel: 'preload',
as: 'script',
include: 'all'
include: 'allChunks'
})
]
}, function(err, result) {
Expand Down Expand Up @@ -206,7 +207,7 @@ describe('PreloadPlugin preloads normal chunks', function() {
new HtmlWebpackPlugin(),
new PreloadPlugin({
rel: 'preload',
include: 'all'
include: 'allChunks'
})
]
}, function(err, result) {
Expand Down Expand Up @@ -237,7 +238,7 @@ describe('PreloadPlugin preloads normal chunks', function() {
if (entry.indexOf('/chunk') === 0) return 'style';
return 'script';
},
include: 'all',
include: 'allChunks',
}),
],
}, function(err, result) {
Expand All @@ -263,7 +264,7 @@ describe('PreloadPlugin prefetches normal chunks', function() {
new HtmlWebpackPlugin(),
new PreloadPlugin({
rel: 'prefetch',
include: 'all'
include: 'allChunks'
})
]
}, function(err, result) {
Expand Down Expand Up @@ -337,6 +338,94 @@ describe('PreloadPlugin filters chunks', function() {
});
compiler.outputFileSystem = new MemoryFileSystem();
});
it('use fileWhitelist to include only specific files', (done) => {
const compiler = webpack({
entry: path.join(__dirname, 'fixtures', 'file.js'),
devtool: 'cheap-source-map',
output: {
path: OUTPUT_DIR,
filename: 'bundle.js',
chunkFilename: '[name].js',
publicPath: '/',
},
plugins: [
new HtmlWebpackPlugin(),
new PreloadPlugin({
rel: 'preload',
as: 'script',
fileWhitelist: [/home/],
})
]
}, function(err, result) {
expect(err).toBeFalsy();
expect(JSON.stringify(result.compilation.errors)).toBe('[]');
const html = result.compilation.assets['index.html'].source();
expect(html).toContain('<link rel="preload" as="script" href="/home.js');
// exclude by default fileBlacklist
expect(html).not.toContain('<link rel="preload" as="script" href="/home.js.map');
// not included in fileWhitelist
expect(html).not.toContain('<link rel="preload" as="script" href="/bundle.js"');
done();
});
compiler.outputFileSystem = new MemoryFileSystem();
});
});

describe('PreloadPlugin preloads all assets', function() {
it('adds preload tags', function(done) {
const compiler = webpack({
entry: path.join(__dirname, 'fixtures', 'load-css.js'),
output: {
path: OUTPUT_DIR,
filename: 'bundle.js',
chunkFilename: 'chunk.[chunkhash].js',
publicPath: '/',
},
module: {
rules: [
{
test: /\.css$/,
loader: ExtractTextPlugin.extract({
fallback: 'css-loader',
use: [
{
loader: 'css-loader',
},
],
}),
},
{
test: /\.woff2?$/,
loader: 'file-loader',
options: {
name: '[name].[ext]',
},
},
],
},
plugins: [
new ExtractTextPlugin({
filename: 'style.css',
allChunks: true,
}),
new HtmlWebpackPlugin(),
new PreloadPlugin({
rel: 'preload',
include: 'allAssets'
}),
]
}, function(err, result) {
expect(err).toBeFalsy();
expect(JSON.stringify(result.compilation.errors)).toBe('[]');
const html = result.compilation.assets['index.html'].source();
expect(html).toContain('<link rel="preload" as="script" href="/chunk');
expect(html).toContain('<link rel="preload" as="script" href="/bundle.js"');
expect(html).toContain('<link rel="preload" as="style" href="/style.css"');
expect(html).toContain('<link rel="preload" as="font" crossorigin="crossorigin" href="/font.woff2"');
done();
});
compiler.outputFileSystem = new MemoryFileSystem();
});
});

describe('filtering unwanted files', function() {
Expand Down

0 comments on commit 0f80892

Please sign in to comment.