Skip to content

Commit a214736

Browse files
fix: reemit assets from loaders (#1811)
1 parent 0db3c2b commit a214736

File tree

3 files changed

+59
-26
lines changed

3 files changed

+59
-26
lines changed

index.js

+19-8
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const getHtmlWebpackPluginHooks = require('./lib/hooks.js').getHtmlWebpackPlugin
2121
/** @typedef {import("webpack").Compiler} Compiler */
2222
/** @typedef {ReturnType<Compiler["getInfrastructureLogger"]>} Logger */
2323
/** @typedef {import("webpack/lib/Compilation.js")} Compilation */
24-
/** @typedef {Array<{ source: import('webpack').sources.Source, name: string }>} PreviousEmittedAssets */
24+
/** @typedef {Array<{ name: string, source: import('webpack').sources.Source, info?: import('webpack').AssetInfo }>} PreviousEmittedAssets */
2525
/** @typedef {{ publicPath: string, js: Array<string>, css: Array<string>, manifest?: string, favicon?: string }} AssetsInformationByGroups */
2626

2727
class HtmlWebpackPlugin {
@@ -1023,8 +1023,8 @@ class HtmlWebpackPlugin {
10231023
const newAssetJson = JSON.stringify(this.getAssetFiles(assetsInformationByGroups));
10241024

10251025
if (isCompilationCached && this.options.cache && assetJson.value === newAssetJson) {
1026-
previousEmittedAssets.forEach(({ name, source }) => {
1027-
compilation.emitAsset(name, source);
1026+
previousEmittedAssets.forEach(({ name, source, info }) => {
1027+
compilation.emitAsset(name, source, info);
10281028
});
10291029
return callback();
10301030
} else {
@@ -1084,15 +1084,26 @@ class HtmlWebpackPlugin {
10841084
if ('error' in templateResult) {
10851085
return this.options.showErrors ? prettyError(templateResult.error, compiler.context).toHtml() : 'ERROR';
10861086
}
1087+
10871088
// Allow to use a custom function / string instead
10881089
if (this.options.templateContent !== false) {
10891090
return this.options.templateContent;
10901091
}
1091-
// Once everything is compiled evaluate the html factory
1092-
// and replace it with its content
1093-
return ('compiledEntry' in templateResult)
1094-
? this.evaluateCompilationResult(templateResult.compiledEntry.content, assetsInformationByGroups.publicPath, this.options.template)
1095-
: Promise.reject(new Error('Child compilation contained no compiledEntry'));
1092+
1093+
// Once everything is compiled evaluate the html factory and replace it with its content
1094+
if ('compiledEntry' in templateResult) {
1095+
const compiledEntry = templateResult.compiledEntry;
1096+
const assets = compiledEntry.assets;
1097+
1098+
// Store assets from child compiler to reemit them later
1099+
for (const name in assets) {
1100+
previousEmittedAssets.push({ name, source: assets[name].source, info: assets[name].info });
1101+
}
1102+
1103+
return this.evaluateCompilationResult(compiledEntry.content, assetsInformationByGroups.publicPath, this.options.template);
1104+
}
1105+
1106+
return Promise.reject(new Error('Child compilation contained no compiledEntry'));
10961107
});
10971108
const templateExectutionPromise = Promise.all([assetsPromise, assetTagGroupsPromise, templateEvaluationPromise])
10981109
// Execute the template

lib/cached-child-compiler.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@
2727
/** @typedef {import("webpack").Compiler} Compiler */
2828
/** @typedef {import("webpack").Compilation} Compilation */
2929
/** @typedef {import("webpack/lib/FileSystemInfo").Snapshot} Snapshot */
30-
/** @typedef {{hash: string, entry: any, content: string }} ChildCompilationResultEntry */
30+
/** @typedef {import("./child-compiler").ChildCompilationTemplateResult} ChildCompilationTemplateResult */
3131
/** @typedef {{fileDependencies: string[], contextDependencies: string[], missingDependencies: string[]}} FileDependencies */
3232
/** @typedef {{
3333
dependencies: FileDependencies,
34-
compiledEntries: {[entryName: string]: ChildCompilationResultEntry}
34+
compiledEntries: {[entryName: string]: ChildCompilationTemplateResult}
3535
} | {
3636
dependencies: FileDependencies,
3737
error: Error
@@ -96,7 +96,7 @@ class CachedChildCompilation {
9696
* @param {string} entry
9797
* @returns {
9898
| { mainCompilationHash: string, error: Error }
99-
| { mainCompilationHash: string, compiledEntry: ChildCompilationResultEntry }
99+
| { mainCompilationHash: string, compiledEntry: ChildCompilationTemplateResult }
100100
}
101101
*/
102102
getCompilationEntryResult (entry) {

lib/child-compiler.js

+37-15
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
/** @typedef {import("webpack").Chunk} Chunk */
1313
/** @typedef {import("webpack").sources.Source} Source */
14+
/** @typedef {{hash: string, entry: Chunk, content: string, assets: {[name: string]: { source: Source, info: import("webpack").AssetInfo }}}} ChildCompilationTemplateResult */
1415

1516
let instanceId = 0;
1617
/**
@@ -30,17 +31,11 @@ class HtmlWebpackChildCompiler {
3031
* The template array will allow us to keep track which input generated which output
3132
*/
3233
this.templates = templates;
33-
/**
34-
* @type {Promise<{[templatePath: string]: { content: string, hash: string, entry: Chunk }}>}
35-
*/
34+
/** @type {Promise<{[templatePath: string]: ChildCompilationTemplateResult}>} */
3635
this.compilationPromise; // eslint-disable-line
37-
/**
38-
* @type {number}
39-
*/
36+
/** @type {number | undefined} */
4037
this.compilationStartedTimestamp; // eslint-disable-line
41-
/**
42-
* @type {number}
43-
*/
38+
/** @type {number | undefined} */
4439
this.compilationEndedTimestamp; // eslint-disable-line
4540
/**
4641
* All file dependencies of the child compiler
@@ -51,6 +46,7 @@ class HtmlWebpackChildCompiler {
5146

5247
/**
5348
* Returns true if the childCompiler is currently compiling
49+
*
5450
* @returns {boolean}
5551
*/
5652
isCompiling () {
@@ -59,6 +55,8 @@ class HtmlWebpackChildCompiler {
5955

6056
/**
6157
* Returns true if the childCompiler is done compiling
58+
*
59+
* @returns {boolean}
6260
*/
6361
didCompile () {
6462
return this.compilationEndedTimestamp !== undefined;
@@ -69,7 +67,7 @@ class HtmlWebpackChildCompiler {
6967
* once it is started no more templates can be added
7068
*
7169
* @param {import('webpack').Compilation} mainCompilation
72-
* @returns {Promise<{[templatePath: string]: { content: string, hash: string, entry: Chunk }}>}
70+
* @returns {Promise<{[templatePath: string]: ChildCompilationTemplateResult}>}
7371
*/
7472
compileTemplates (mainCompilation) {
7573
const webpack = mainCompilation.compiler.webpack;
@@ -125,13 +123,17 @@ class HtmlWebpackChildCompiler {
125123
// The following config enables relative URL support for the child compiler
126124
childCompiler.options.module = { ...childCompiler.options.module };
127125
childCompiler.options.module.parser = { ...childCompiler.options.module.parser };
128-
childCompiler.options.module.parser.javascript = { ...childCompiler.options.module.parser.javascript,
129-
url: 'relative' };
126+
childCompiler.options.module.parser.javascript = {
127+
...childCompiler.options.module.parser.javascript,
128+
url: 'relative'
129+
};
130130

131131
this.compilationStartedTimestamp = new Date().getTime();
132+
/** @type {Promise<{[templatePath: string]: ChildCompilationTemplateResult}>} */
132133
this.compilationPromise = new Promise((resolve, reject) => {
133134
/** @type {Source[]} */
134135
const extractedAssets = [];
136+
135137
childCompiler.hooks.thisCompilation.tap('HtmlWebpackPlugin', (compilation) => {
136138
compilation.hooks.processAssets.tap(
137139
{
@@ -142,6 +144,7 @@ class HtmlWebpackChildCompiler {
142144
temporaryTemplateNames.forEach((temporaryTemplateName) => {
143145
if (assets[temporaryTemplateName]) {
144146
extractedAssets.push(assets[temporaryTemplateName]);
147+
145148
compilation.deleteAsset(temporaryTemplateName);
146149
}
147150
});
@@ -151,13 +154,16 @@ class HtmlWebpackChildCompiler {
151154

152155
childCompiler.runAsChild((err, entries, childCompilation) => {
153156
// Extract templates
157+
// TODO fine a better way to store entries and results, to avoid duplicate chunks and assets
154158
const compiledTemplates = entries
155159
? extractedAssets.map((asset) => asset.source())
156160
: [];
161+
157162
// Extract file dependencies
158163
if (entries && childCompilation) {
159164
this.fileDependencies = { fileDependencies: Array.from(childCompilation.fileDependencies), contextDependencies: Array.from(childCompilation.contextDependencies), missingDependencies: Array.from(childCompilation.missingDependencies) };
160165
}
166+
161167
// Reject the promise if the childCompilation contains error
162168
if (childCompilation && childCompilation.errors && childCompilation.errors.length) {
163169
const errorDetails = childCompilation.errors.map(error => {
@@ -167,34 +173,50 @@ class HtmlWebpackChildCompiler {
167173
}
168174
return message;
169175
}).join('\n');
176+
170177
reject(new Error('Child compilation failed:\n' + errorDetails));
178+
171179
return;
172180
}
181+
173182
// Reject if the error object contains errors
174183
if (err) {
175184
reject(err);
176185
return;
177186
}
187+
178188
if (!childCompilation || !entries) {
179189
reject(new Error('Empty child compilation'));
180190
return;
181191
}
192+
182193
/**
183-
* @type {{[templatePath: string]: { content: string, hash: string, entry: Chunk }}}
194+
* @type {{[templatePath: string]: ChildCompilationTemplateResult}}
184195
*/
185196
const result = {};
197+
198+
/** @type {{[name: string]: { source: Source, info: import("webpack").AssetInfo }}} */
199+
const assets = {};
200+
201+
for (const asset of childCompilation.getAssets()) {
202+
assets[asset.name] = { source: asset.source, info: asset.info };
203+
}
204+
186205
compiledTemplates.forEach((templateSource, entryIndex) => {
187206
// The compiledTemplates are generated from the entries added in
188207
// the addTemplate function.
189-
// Therefore the array index of this.templates should be the as entryIndex.
208+
// Therefore, the array index of this.templates should be the as entryIndex.
190209
result[this.templates[entryIndex]] = {
191210
// TODO, can we have Buffer here?
192211
content: /** @type {string} */ (templateSource),
193212
hash: childCompilation.hash || 'XXXX',
194-
entry: entries[entryIndex]
213+
entry: entries[entryIndex],
214+
assets
195215
};
196216
});
217+
197218
this.compilationEndedTimestamp = new Date().getTime();
219+
198220
resolve(result);
199221
});
200222
});

0 commit comments

Comments
 (0)