Skip to content

Commit 550c1f3

Browse files
committed
chore(refactor): move plugin into the class
1 parent 90b3ecc commit 550c1f3

File tree

5 files changed

+206
-214
lines changed

5 files changed

+206
-214
lines changed

src/addAllAssetsToCompilation.js

Lines changed: 0 additions & 113 deletions
This file was deleted.

src/handleUrl.js

Lines changed: 0 additions & 32 deletions
This file was deleted.

src/index.js

Lines changed: 91 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,112 @@
11
import HtmlWebpackPlugin from 'html-webpack-plugin';
2-
import addAllAssetsToCompilation from './addAllAssetsToCompilation';
2+
import pEachSeries from 'p-each-series';
3+
import micromatch from 'micromatch';
4+
import crypto from 'crypto';
5+
import globby from 'globby';
6+
import {
7+
ensureTrailingSlash,
8+
handleUrl,
9+
resolveOutput,
10+
resolvePublicPath,
11+
} from './utils';
312

413
export default class AddAssetHtmlPlugin {
514
constructor(assets = []) {
6-
this.assets = Array.isArray(assets) ? assets.slice().reverse() : [assets];
15+
this.assets = Array.isArray(assets)
16+
? assets.slice().reverse()
17+
: [assets].filter(Boolean);
718
}
819

920
/* istanbul ignore next: this would be integration tests */
1021
apply(compiler) {
1122
compiler.hooks.compilation.tap('AddAssetHtmlPlugin', compilation => {
1223
let hook;
24+
1325
if (HtmlWebpackPlugin.version === 4) {
1426
hook = HtmlWebpackPlugin.getHooks(compilation).beforeAssetTagGeneration;
1527
} else {
1628
hook = compilation.hooks.htmlWebpackPluginBeforeHtmlGeneration;
1729
}
1830

1931
hook.tapPromise('AddAssetHtmlPlugin', htmlPluginData =>
20-
addAllAssetsToCompilation(this.assets, compilation, htmlPluginData),
32+
this.addAllAssetsToCompilation(compilation, htmlPluginData),
2133
);
2234
});
2335
}
36+
37+
async addAllAssetsToCompilation(compilation, htmlPluginData) {
38+
const handledAssets = await handleUrl(this.assets);
39+
await pEachSeries(handledAssets, asset =>
40+
this.addFileToAssets(compilation, htmlPluginData, asset),
41+
);
42+
return htmlPluginData;
43+
}
44+
45+
// eslint-disable-next-line class-methods-use-this
46+
async addFileToAssets(
47+
compilation,
48+
htmlPluginData,
49+
{
50+
filepath,
51+
typeOfAsset = 'js',
52+
includeRelatedFiles = true,
53+
hash = false,
54+
publicPath,
55+
outputPath,
56+
files = [],
57+
},
58+
) {
59+
if (!filepath) {
60+
const error = new Error('No filepath defined');
61+
compilation.errors.push(error);
62+
throw error;
63+
}
64+
65+
const fileFilters = Array.isArray(files) ? files : [files];
66+
67+
if (fileFilters.length > 0) {
68+
const shouldSkip = !fileFilters.some(file =>
69+
micromatch.isMatch(htmlPluginData.outputName, file),
70+
);
71+
72+
if (shouldSkip) {
73+
return;
74+
}
75+
}
76+
77+
const addedFilename = await htmlPluginData.plugin.addFileToAssets(
78+
filepath,
79+
compilation,
80+
);
81+
82+
let suffix = '';
83+
if (hash) {
84+
const md5 = crypto.createHash('md5');
85+
md5.update(compilation.assets[addedFilename].source());
86+
suffix = `?${md5.digest('hex').substr(0, 20)}`;
87+
}
88+
89+
const resolvedPublicPath =
90+
typeof publicPath === 'undefined'
91+
? resolvePublicPath(compilation, addedFilename)
92+
: ensureTrailingSlash(publicPath);
93+
const resolvedPath = `${resolvedPublicPath}${addedFilename}${suffix}`;
94+
95+
htmlPluginData.assets[typeOfAsset].unshift(resolvedPath);
96+
97+
resolveOutput(compilation, addedFilename, outputPath);
98+
99+
if (includeRelatedFiles) {
100+
const relatedFiles = await globby(`${filepath}.*`);
101+
await Promise.all(
102+
relatedFiles.sort().map(async relatedFile => {
103+
const addedMapFilename = await htmlPluginData.plugin.addFileToAssets(
104+
relatedFile,
105+
compilation,
106+
);
107+
resolveOutput(compilation, addedMapFilename, outputPath);
108+
}),
109+
);
110+
}
111+
}
24112
}

src/utils.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import path from 'path';
2+
import globby from 'globby';
3+
4+
export function ensureTrailingSlash(string) {
5+
if (string.length && string.substr(-1, 1) !== '/') {
6+
return `${string}/`;
7+
}
8+
9+
return string;
10+
}
11+
12+
// Copied from html-webpack-plugin
13+
export function resolvePublicPath(compilation, filename) {
14+
/* istanbul ignore else */
15+
const publicPath =
16+
typeof compilation.options.output.publicPath !== 'undefined'
17+
? compilation.options.output.publicPath
18+
: path.relative(path.dirname(filename), '.'); // TODO: How to test this? I haven't written this logic, unsure what it does
19+
20+
return ensureTrailingSlash(publicPath);
21+
}
22+
23+
export function resolveOutput(compilation, addedFilename, outputPath) {
24+
if (outputPath && outputPath.length) {
25+
/* eslint-disable no-param-reassign */
26+
compilation.assets[`${outputPath}/${addedFilename}`] =
27+
compilation.assets[addedFilename];
28+
delete compilation.assets[addedFilename];
29+
/* eslint-enable */
30+
}
31+
}
32+
33+
/**
34+
* handle globby filepath and return an array with all matched assets.
35+
*
36+
* @export
37+
* @param {Array} assets
38+
* @returns
39+
*/
40+
export async function handleUrl(assets) {
41+
const globbyAssets = [];
42+
const normalAssets = [];
43+
// if filepath is null or undefined, just bubble up.
44+
assets.forEach(
45+
asset =>
46+
asset.filepath && globby.hasMagic(asset.filepath)
47+
? globbyAssets.push(asset)
48+
: normalAssets.push(asset),
49+
);
50+
const ret = [];
51+
await Promise.all(
52+
globbyAssets.map(asset =>
53+
globby(asset.filepath).then(paths =>
54+
paths.forEach(filepath =>
55+
ret.push(Object.assign({}, asset, { filepath })),
56+
),
57+
),
58+
),
59+
);
60+
61+
return ret.concat(normalAssets);
62+
}

0 commit comments

Comments
 (0)