html-webpack-plugin 5.6.0 → 5.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -1,34 +1,124 @@
1
1
  // @ts-check
2
- 'use strict';
2
+ "use strict";
3
3
 
4
- const promisify = require('util').promisify;
4
+ const promisify = require("util").promisify;
5
5
 
6
- const vm = require('vm');
7
- const fs = require('fs');
8
- const _ = require('lodash');
9
- const path = require('path');
10
- const { CachedChildCompilation } = require('./lib/cached-child-compiler');
6
+ const vm = require("vm");
7
+ const fs = require("fs");
8
+ const _uniq = require("lodash/uniq");
9
+ const path = require("path");
10
+ const { CachedChildCompilation } = require("./lib/cached-child-compiler");
11
11
 
12
- const { createHtmlTagObject, htmlTagObjectToString, HtmlTagArray } = require('./lib/html-tags');
13
- const prettyError = require('./lib/errors.js');
14
- const chunkSorter = require('./lib/chunksorter.js');
15
- const getHtmlWebpackPluginHooks = require('./lib/hooks.js').getHtmlWebpackPluginHooks;
12
+ const {
13
+ createHtmlTagObject,
14
+ htmlTagObjectToString,
15
+ HtmlTagArray,
16
+ } = require("./lib/html-tags");
17
+ const prettyError = require("./lib/errors.js");
18
+ const chunkSorter = require("./lib/chunksorter.js");
19
+ const { AsyncSeriesWaterfallHook } = require("tapable");
16
20
 
17
21
  /** @typedef {import("./typings").HtmlTagObject} HtmlTagObject */
18
22
  /** @typedef {import("./typings").Options} HtmlWebpackOptions */
19
23
  /** @typedef {import("./typings").ProcessedOptions} ProcessedHtmlWebpackOptions */
20
24
  /** @typedef {import("./typings").TemplateParameter} TemplateParameter */
21
25
  /** @typedef {import("webpack").Compiler} Compiler */
26
+ /** @typedef {import("webpack").Compilation} Compilation */
27
+ /** @typedef {Required<Compilation["outputOptions"]["publicPath"]>} PublicPath */
22
28
  /** @typedef {ReturnType<Compiler["getInfrastructureLogger"]>} Logger */
23
- /** @typedef {import("webpack/lib/Compilation.js")} Compilation */
29
+ /** @typedef {Compilation["entrypoints"] extends Map<string, infer I> ? I : never} Entrypoint */
24
30
  /** @typedef {Array<{ name: string, source: import('webpack').sources.Source, info?: import('webpack').AssetInfo }>} PreviousEmittedAssets */
25
31
  /** @typedef {{ publicPath: string, js: Array<string>, css: Array<string>, manifest?: string, favicon?: string }} AssetsInformationByGroups */
32
+ /** @typedef {import("./typings").Hooks} HtmlWebpackPluginHooks */
33
+ /**
34
+ * @type {WeakMap<Compilation, HtmlWebpackPluginHooks>}}
35
+ */
36
+ const compilationHooksMap = new WeakMap();
26
37
 
27
38
  class HtmlWebpackPlugin {
39
+ // The following is the API definition for all available hooks
40
+ // For the TypeScript definition, see the Hooks type in typings.d.ts
41
+ /**
42
+ beforeAssetTagGeneration:
43
+ AsyncSeriesWaterfallHook<{
44
+ assets: {
45
+ publicPath: string,
46
+ js: Array<string>,
47
+ css: Array<string>,
48
+ favicon?: string | undefined,
49
+ manifest?: string | undefined
50
+ },
51
+ outputName: string,
52
+ plugin: HtmlWebpackPlugin
53
+ }>,
54
+ alterAssetTags:
55
+ AsyncSeriesWaterfallHook<{
56
+ assetTags: {
57
+ scripts: Array<HtmlTagObject>,
58
+ styles: Array<HtmlTagObject>,
59
+ meta: Array<HtmlTagObject>,
60
+ },
61
+ publicPath: string,
62
+ outputName: string,
63
+ plugin: HtmlWebpackPlugin
64
+ }>,
65
+ alterAssetTagGroups:
66
+ AsyncSeriesWaterfallHook<{
67
+ headTags: Array<HtmlTagObject | HtmlTagObject>,
68
+ bodyTags: Array<HtmlTagObject | HtmlTagObject>,
69
+ publicPath: string,
70
+ outputName: string,
71
+ plugin: HtmlWebpackPlugin
72
+ }>,
73
+ afterTemplateExecution:
74
+ AsyncSeriesWaterfallHook<{
75
+ html: string,
76
+ headTags: Array<HtmlTagObject | HtmlTagObject>,
77
+ bodyTags: Array<HtmlTagObject | HtmlTagObject>,
78
+ outputName: string,
79
+ plugin: HtmlWebpackPlugin,
80
+ }>,
81
+ beforeEmit:
82
+ AsyncSeriesWaterfallHook<{
83
+ html: string,
84
+ outputName: string,
85
+ plugin: HtmlWebpackPlugin,
86
+ }>,
87
+ afterEmit:
88
+ AsyncSeriesWaterfallHook<{
89
+ outputName: string,
90
+ plugin: HtmlWebpackPlugin
91
+ }>
92
+ */
93
+
94
+ /**
95
+ * Returns all public hooks of the html webpack plugin for the given compilation
96
+ *
97
+ * @param {Compilation} compilation
98
+ * @returns {HtmlWebpackPluginHooks}
99
+ */
100
+ static getCompilationHooks(compilation) {
101
+ let hooks = compilationHooksMap.get(compilation);
102
+
103
+ if (!hooks) {
104
+ hooks = {
105
+ beforeAssetTagGeneration: new AsyncSeriesWaterfallHook(["pluginArgs"]),
106
+ alterAssetTags: new AsyncSeriesWaterfallHook(["pluginArgs"]),
107
+ alterAssetTagGroups: new AsyncSeriesWaterfallHook(["pluginArgs"]),
108
+ afterTemplateExecution: new AsyncSeriesWaterfallHook(["pluginArgs"]),
109
+ beforeEmit: new AsyncSeriesWaterfallHook(["pluginArgs"]),
110
+ afterEmit: new AsyncSeriesWaterfallHook(["pluginArgs"]),
111
+ };
112
+ compilationHooksMap.set(compilation, hooks);
113
+ }
114
+
115
+ return hooks;
116
+ }
117
+
28
118
  /**
29
119
  * @param {HtmlWebpackOptions} [options]
30
120
  */
31
- constructor (options) {
121
+ constructor(options) {
32
122
  /** @type {HtmlWebpackOptions} */
33
123
  // TODO remove me in the next major release
34
124
  this.userOptions = options || {};
@@ -37,26 +127,29 @@ class HtmlWebpackPlugin {
37
127
  // Default options
38
128
  /** @type {ProcessedHtmlWebpackOptions} */
39
129
  const defaultOptions = {
40
- template: 'auto',
130
+ template: "auto",
41
131
  templateContent: false,
42
132
  templateParameters: templateParametersGenerator,
43
- filename: 'index.html',
44
- publicPath: this.userOptions.publicPath === undefined ? 'auto' : this.userOptions.publicPath,
133
+ filename: "index.html",
134
+ publicPath:
135
+ this.userOptions.publicPath === undefined
136
+ ? "auto"
137
+ : this.userOptions.publicPath,
45
138
  hash: false,
46
- inject: this.userOptions.scriptLoading === 'blocking' ? 'body' : 'head',
47
- scriptLoading: 'defer',
139
+ inject: this.userOptions.scriptLoading === "blocking" ? "body" : "head",
140
+ scriptLoading: "defer",
48
141
  compile: true,
49
142
  favicon: false,
50
- minify: 'auto',
143
+ minify: "auto",
51
144
  cache: true,
52
145
  showErrors: true,
53
- chunks: 'all',
146
+ chunks: "all",
54
147
  excludeChunks: [],
55
- chunksSortMode: 'auto',
148
+ chunksSortMode: "auto",
56
149
  meta: {},
57
150
  base: false,
58
- title: 'Webpack App',
59
- xhtml: false
151
+ title: "Webpack App",
152
+ xhtml: false,
60
153
  };
61
154
 
62
155
  /** @type {ProcessedHtmlWebpackOptions} */
@@ -68,113 +161,152 @@ class HtmlWebpackPlugin {
68
161
  * @param {Compiler} compiler
69
162
  * @returns {void}
70
163
  */
71
- apply (compiler) {
72
- this.logger = compiler.getInfrastructureLogger('HtmlWebpackPlugin');
164
+ apply(compiler) {
165
+ this.logger = compiler.getInfrastructureLogger("HtmlWebpackPlugin");
73
166
 
74
- // Wait for configuration preset plugions to apply all configure webpack defaults
75
- compiler.hooks.initialize.tap('HtmlWebpackPlugin', () => {
76
- const options = this.options;
167
+ const options = this.options;
77
168
 
78
- options.template = this.getTemplatePath(this.options.template, compiler.context);
169
+ options.template = this.getTemplatePath(
170
+ this.options.template,
171
+ compiler.context,
172
+ );
79
173
 
80
- // Assert correct option spelling
81
- if (options.scriptLoading !== 'defer' && options.scriptLoading !== 'blocking' && options.scriptLoading !== 'module' && options.scriptLoading !== 'systemjs-module') {
82
- /** @type {Logger} */
83
- (this.logger).error('The "scriptLoading" option need to be set to "defer", "blocking" or "module" or "systemjs-module"');
84
- }
174
+ // Assert correct option spelling
175
+ if (
176
+ options.scriptLoading !== "defer" &&
177
+ options.scriptLoading !== "blocking" &&
178
+ options.scriptLoading !== "module" &&
179
+ options.scriptLoading !== "systemjs-module"
180
+ ) {
181
+ /** @type {Logger} */
182
+ (this.logger).error(
183
+ 'The "scriptLoading" option need to be set to "defer", "blocking" or "module" or "systemjs-module"',
184
+ );
185
+ }
85
186
 
86
- if (options.inject !== true && options.inject !== false && options.inject !== 'head' && options.inject !== 'body') {
87
- /** @type {Logger} */
88
- (this.logger).error('The `inject` option needs to be set to true, false, "head" or "body');
89
- }
187
+ if (
188
+ options.inject !== true &&
189
+ options.inject !== false &&
190
+ options.inject !== "head" &&
191
+ options.inject !== "body"
192
+ ) {
193
+ /** @type {Logger} */
194
+ (this.logger).error(
195
+ 'The `inject` option needs to be set to true, false, "head" or "body',
196
+ );
197
+ }
90
198
 
91
- if (
92
- this.options.templateParameters !== false &&
93
- typeof this.options.templateParameters !== 'function' &&
94
- typeof this.options.templateParameters !== 'object'
95
- ) {
96
- /** @type {Logger} */
97
- (this.logger).error('The `templateParameters` has to be either a function or an object or false');
98
- }
199
+ if (
200
+ this.options.templateParameters !== false &&
201
+ typeof this.options.templateParameters !== "function" &&
202
+ typeof this.options.templateParameters !== "object"
203
+ ) {
204
+ /** @type {Logger} */
205
+ (this.logger).error(
206
+ "The `templateParameters` has to be either a function or an object or false",
207
+ );
208
+ }
99
209
 
100
- // Default metaOptions if no template is provided
101
- if (!this.userOptions.template && options.templateContent === false && options.meta) {
102
- options.meta = Object.assign(
103
- {},
104
- options.meta,
105
- {
106
- // TODO remove in the next major release
107
- // From https://developer.mozilla.org/en-US/docs/Mozilla/Mobile/Viewport_meta_tag
108
- viewport: 'width=device-width, initial-scale=1'
109
- },
110
- this.userOptions.meta
111
- );
112
- }
210
+ // Default metaOptions if no template is provided
211
+ if (
212
+ !this.userOptions.template &&
213
+ options.templateContent === false &&
214
+ options.meta
215
+ ) {
216
+ options.meta = Object.assign(
217
+ {},
218
+ options.meta,
219
+ {
220
+ // TODO remove in the next major release
221
+ // From https://developer.mozilla.org/en-US/docs/Mozilla/Mobile/Viewport_meta_tag
222
+ viewport: "width=device-width, initial-scale=1",
223
+ },
224
+ this.userOptions.meta,
225
+ );
226
+ }
113
227
 
114
- // entryName to fileName conversion function
115
- const userOptionFilename = this.userOptions.filename || this.options.filename;
116
- const filenameFunction = typeof userOptionFilename === 'function'
228
+ // entryName to fileName conversion function
229
+ const userOptionFilename =
230
+ this.userOptions.filename || this.options.filename;
231
+ const filenameFunction =
232
+ typeof userOptionFilename === "function"
117
233
  ? userOptionFilename
118
- // Replace '[name]' with entry name
119
- : (entryName) => userOptionFilename.replace(/\[name\]/g, entryName);
120
-
121
- /** output filenames for the given entry names */
122
- const entryNames = Object.keys(compiler.options.entry);
123
- const outputFileNames = new Set((entryNames.length ? entryNames : ['main']).map(filenameFunction));
124
-
125
- // Hook all options into the webpack compiler
126
- outputFileNames.forEach((outputFileName) => {
127
- // Instance variables to keep caching information for multiple builds
128
- const assetJson = { value: undefined };
129
- /**
130
- * store the previous generated asset to emit them even if the content did not change
131
- * to support watch mode for third party plugins like the clean-webpack-plugin or the compression plugin
132
- * @type {PreviousEmittedAssets}
133
- */
134
- const previousEmittedAssets = [];
234
+ : // Replace '[name]' with entry name
235
+ (entryName) => userOptionFilename.replace(/\[name\]/g, entryName);
135
236
 
136
- // Inject child compiler plugin
137
- const childCompilerPlugin = new CachedChildCompilation(compiler);
237
+ /** output filenames for the given entry names */
238
+ const entryNames = Object.keys(compiler.options.entry);
239
+ const outputFileNames = new Set(
240
+ (entryNames.length ? entryNames : ["main"]).map(filenameFunction),
241
+ );
138
242
 
139
- if (!this.options.templateContent) {
140
- childCompilerPlugin.addEntry(this.options.template);
141
- }
243
+ // Hook all options into the webpack compiler
244
+ outputFileNames.forEach((outputFileName) => {
245
+ // Instance variables to keep caching information for multiple builds
246
+ const assetJson = { value: undefined };
247
+ /**
248
+ * store the previous generated asset to emit them even if the content did not change
249
+ * to support watch mode for third party plugins like the clean-webpack-plugin or the compression plugin
250
+ * @type {PreviousEmittedAssets}
251
+ */
252
+ const previousEmittedAssets = [];
253
+
254
+ // Inject child compiler plugin
255
+ const childCompilerPlugin = new CachedChildCompilation(compiler);
256
+
257
+ if (!this.options.templateContent) {
258
+ childCompilerPlugin.addEntry(this.options.template);
259
+ }
142
260
 
143
- // convert absolute filename into relative so that webpack can
144
- // generate it at correct location
145
- let filename = outputFileName;
261
+ // convert absolute filename into relative so that webpack can
262
+ // generate it at correct location
263
+ let filename = outputFileName;
146
264
 
147
- if (path.resolve(filename) === path.normalize(filename)) {
148
- const outputPath = /** @type {string} - Once initialized the path is always a string */(compiler.options.output.path);
265
+ if (path.resolve(filename) === path.normalize(filename)) {
266
+ const outputPath =
267
+ /** @type {string} - Once initialized the path is always a string */ (
268
+ compiler.options.output.path
269
+ );
149
270
 
150
- filename = path.relative(outputPath, filename);
151
- }
271
+ filename = path.relative(outputPath, filename);
272
+ }
152
273
 
153
- compiler.hooks.thisCompilation.tap('HtmlWebpackPlugin',
154
- /**
155
- * Hook into the webpack compilation
156
- * @param {Compilation} compilation
157
- */
158
- (compilation) => {
159
- compilation.hooks.processAssets.tapAsync(
160
- {
161
- name: 'HtmlWebpackPlugin',
162
- stage:
274
+ compiler.hooks.thisCompilation.tap(
275
+ "HtmlWebpackPlugin",
276
+ /**
277
+ * Hook into the webpack compilation
278
+ * @param {Compilation} compilation
279
+ */
280
+ (compilation) => {
281
+ compilation.hooks.processAssets.tapAsync(
282
+ {
283
+ name: "HtmlWebpackPlugin",
284
+ stage:
163
285
  /**
164
286
  * Generate the html after minification and dev tooling is done
165
287
  */
166
- compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_INLINE
167
- },
168
- /**
169
- * Hook into the process assets hook
170
- * @param {any} _
171
- * @param {(err?: Error) => void} callback
172
- */
173
- (_, callback) => {
174
- this.generateHTML(compiler, compilation, filename, childCompilerPlugin, previousEmittedAssets, assetJson, callback);
175
- });
176
- });
177
- });
288
+ compiler.webpack.Compilation
289
+ .PROCESS_ASSETS_STAGE_OPTIMIZE_INLINE,
290
+ },
291
+ /**
292
+ * Hook into the process assets hook
293
+ * @param {any} _
294
+ * @param {(err?: Error) => void} callback
295
+ */
296
+ (_, callback) => {
297
+ this.generateHTML(
298
+ compiler,
299
+ compilation,
300
+ filename,
301
+ childCompilerPlugin,
302
+ previousEmittedAssets,
303
+ assetJson,
304
+ callback,
305
+ );
306
+ },
307
+ );
308
+ },
309
+ );
178
310
  });
179
311
  }
180
312
 
@@ -185,23 +317,28 @@ class HtmlWebpackPlugin {
185
317
  * @param {string} template The path to the template e.g. './index.html'
186
318
  * @param {string} context The webpack base resolution path for relative paths e.g. process.cwd()
187
319
  */
188
- getTemplatePath (template, context) {
189
- if (template === 'auto') {
190
- template = path.resolve(context, 'src/index.ejs');
320
+ getTemplatePath(template, context) {
321
+ if (template === "auto") {
322
+ template = path.resolve(context, "src/index.ejs");
191
323
  if (!fs.existsSync(template)) {
192
- template = path.join(__dirname, 'default_index.ejs');
324
+ template = path.join(__dirname, "default_index.ejs");
193
325
  }
194
326
  }
195
327
 
196
328
  // If the template doesn't use a loader use the lodash template loader
197
- if (template.indexOf('!') === -1) {
198
- template = require.resolve('./lib/loader.js') + '!' + path.resolve(context, template);
329
+ if (template.indexOf("!") === -1) {
330
+ template =
331
+ require.resolve("./lib/loader.js") +
332
+ "!" +
333
+ path.resolve(context, template);
199
334
  }
200
335
 
201
336
  // Resolve template path
202
337
  return template.replace(
203
338
  /([!])([^/\\][^!?]+|[^/\\!?])($|\?[^!?\n]+$)/,
204
- (match, prefix, filepath, postfix) => prefix + path.resolve(filepath) + postfix);
339
+ (match, prefix, filepath, postfix) =>
340
+ prefix + path.resolve(filepath) + postfix,
341
+ );
205
342
  }
206
343
 
207
344
  /**
@@ -212,15 +349,21 @@ class HtmlWebpackPlugin {
212
349
  * @param {string[]|'all'} includedChunks
213
350
  * @param {string[]} excludedChunks
214
351
  */
215
- filterEntryChunks (chunks, includedChunks, excludedChunks) {
216
- return chunks.filter(chunkName => {
352
+ filterEntryChunks(chunks, includedChunks, excludedChunks) {
353
+ return chunks.filter((chunkName) => {
217
354
  // Skip if the chunks should be filtered and the given chunk was not added explicity
218
- if (Array.isArray(includedChunks) && includedChunks.indexOf(chunkName) === -1) {
355
+ if (
356
+ Array.isArray(includedChunks) &&
357
+ includedChunks.indexOf(chunkName) === -1
358
+ ) {
219
359
  return false;
220
360
  }
221
361
 
222
362
  // Skip if the chunks should be filtered and the given chunk was excluded explicity
223
- if (Array.isArray(excludedChunks) && excludedChunks.indexOf(chunkName) !== -1) {
363
+ if (
364
+ Array.isArray(excludedChunks) &&
365
+ excludedChunks.indexOf(chunkName) !== -1
366
+ ) {
224
367
  return false;
225
368
  }
226
369
 
@@ -237,13 +380,13 @@ class HtmlWebpackPlugin {
237
380
  * @param {string|((entryNameA: string, entryNameB: string) => number)} sortMode
238
381
  * @param {Compilation} compilation
239
382
  */
240
- sortEntryChunks (entryNames, sortMode, compilation) {
383
+ sortEntryChunks(entryNames, sortMode, compilation) {
241
384
  // Custom function
242
- if (typeof sortMode === 'function') {
385
+ if (typeof sortMode === "function") {
243
386
  return entryNames.sort(sortMode);
244
387
  }
245
388
  // Check if the given sort mode is a valid chunkSorter sort mode
246
- if (typeof chunkSorter[sortMode] !== 'undefined') {
389
+ if (typeof chunkSorter[sortMode] !== "undefined") {
247
390
  return chunkSorter[sortMode](entryNames, compilation, this.options);
248
391
  }
249
392
  throw new Error('"' + sortMode + '" is not a valid chunk sort mode');
@@ -271,17 +414,18 @@ class HtmlWebpackPlugin {
271
414
  * @private
272
415
  * @param {string} filePath
273
416
  */
274
- urlencodePath (filePath) {
417
+ urlencodePath(filePath) {
275
418
  // People use the filepath in quite unexpected ways.
276
419
  // Try to extract the first querystring of the url:
277
420
  //
278
421
  // some+path/demo.html?value=abc?def
279
422
  //
280
- const queryStringStart = filePath.indexOf('?');
281
- const urlPath = queryStringStart === -1 ? filePath : filePath.substr(0, queryStringStart);
423
+ const queryStringStart = filePath.indexOf("?");
424
+ const urlPath =
425
+ queryStringStart === -1 ? filePath : filePath.substr(0, queryStringStart);
282
426
  const queryString = filePath.substr(urlPath.length);
283
427
  // Encode all parts except '/' which are not part of the querystring:
284
- const encodedUrlPath = urlPath.split('/').map(encodeURIComponent).join('/');
428
+ const encodedUrlPath = urlPath.split("/").map(encodeURIComponent).join("/");
285
429
  return encodedUrlPath + queryString;
286
430
  }
287
431
 
@@ -290,14 +434,15 @@ class HtmlWebpackPlugin {
290
434
  * E.g. http://localhost:8080/ -> http://localhost:8080/?50c9096ba6183fd728eeb065a26ec175
291
435
  *
292
436
  * @private
293
- * @param {string} url
437
+ * @param {string | undefined} url
294
438
  * @param {string} hash
295
439
  */
296
- appendHash (url, hash) {
440
+ appendHash(url, hash) {
297
441
  if (!url) {
298
442
  return url;
299
443
  }
300
- return url + (url.indexOf('?') === -1 ? '?' : '&') + hash;
444
+
445
+ return url + (url.indexOf("?") === -1 ? "?" : "&") + hash;
301
446
  }
302
447
 
303
448
  /**
@@ -310,30 +455,42 @@ class HtmlWebpackPlugin {
310
455
  * @param {string | 'auto'} customPublicPath
311
456
  * @returns {string}
312
457
  */
313
- getPublicPath (compilation, filename, customPublicPath) {
458
+ getPublicPath(compilation, filename, customPublicPath) {
314
459
  /**
315
460
  * @type {string} the configured public path to the asset root
316
461
  * if a path publicPath is set in the current webpack config use it otherwise
317
462
  * fallback to a relative path
318
463
  */
319
- const webpackPublicPath = compilation.getAssetPath(compilation.outputOptions.publicPath, { hash: compilation.hash });
464
+ const webpackPublicPath = compilation.getAssetPath(
465
+ /** @type {NonNullable<Compilation["outputOptions"]["publicPath"]>} */ (
466
+ compilation.outputOptions.publicPath
467
+ ),
468
+ { hash: compilation.hash },
469
+ );
320
470
  // Webpack 5 introduced "auto" as default value
321
- const isPublicPathDefined = webpackPublicPath !== 'auto';
471
+ const isPublicPathDefined = webpackPublicPath !== "auto";
322
472
 
323
473
  let publicPath =
324
- // If the html-webpack-plugin options contain a custom public path uset it
325
- customPublicPath !== 'auto'
474
+ // If the html-webpack-plugin options contain a custom public path unset it
475
+ customPublicPath !== "auto"
326
476
  ? customPublicPath
327
- : (isPublicPathDefined
328
- // If a hard coded public path exists use it
329
- ? webpackPublicPath
330
- // If no public path was set get a relative url path
331
- : path.relative(path.resolve(compilation.options.output.path, path.dirname(filename)), compilation.options.output.path)
332
- .split(path.sep).join('/')
333
- );
334
-
335
- if (publicPath.length && publicPath.substr(-1, 1) !== '/') {
336
- publicPath += '/';
477
+ : isPublicPathDefined
478
+ ? // If a hard coded public path exists use it
479
+ webpackPublicPath
480
+ : // If no public path was set get a relative url path
481
+ path
482
+ .relative(
483
+ path.resolve(
484
+ /** @type {string} */ (compilation.options.output.path),
485
+ path.dirname(filename),
486
+ ),
487
+ /** @type {string} */ (compilation.options.output.path),
488
+ )
489
+ .split(path.sep)
490
+ .join("/");
491
+
492
+ if (publicPath.length && publicPath.substr(-1, 1) !== "/") {
493
+ publicPath += "/";
337
494
  }
338
495
 
339
496
  return publicPath;
@@ -348,9 +505,13 @@ class HtmlWebpackPlugin {
348
505
  * @param {string[]} entryNames
349
506
  * @returns {AssetsInformationByGroups}
350
507
  */
351
- getAssetsInformationByGroups (compilation, outputName, entryNames) {
508
+ getAssetsInformationByGroups(compilation, outputName, entryNames) {
352
509
  /** The public path used inside the html file */
353
- const publicPath = this.getPublicPath(compilation, outputName, this.options.publicPath);
510
+ const publicPath = this.getPublicPath(
511
+ compilation,
512
+ outputName,
513
+ this.options.publicPath,
514
+ );
354
515
  /**
355
516
  * @type {AssetsInformationByGroups}
356
517
  */
@@ -362,14 +523,19 @@ class HtmlWebpackPlugin {
362
523
  // Will contain all css files
363
524
  css: [],
364
525
  // Will contain the html5 appcache manifest files if it exists
365
- manifest: Object.keys(compilation.assets).find(assetFile => path.extname(assetFile) === '.appcache'),
526
+ manifest: Object.keys(compilation.assets).find(
527
+ (assetFile) => path.extname(assetFile) === ".appcache",
528
+ ),
366
529
  // Favicon
367
- favicon: undefined
530
+ favicon: undefined,
368
531
  };
369
532
 
370
533
  // Append a hash for cache busting
371
534
  if (this.options.hash && assets.manifest) {
372
- assets.manifest = this.appendHash(assets.manifest, /** @type {string} */ (compilation.hash));
535
+ assets.manifest = this.appendHash(
536
+ assets.manifest,
537
+ /** @type {string} */ (compilation.hash),
538
+ );
373
539
  }
374
540
 
375
541
  // Extract paths to .js, .mjs and .css files from the current compilation
@@ -379,7 +545,9 @@ class HtmlWebpackPlugin {
379
545
  for (let i = 0; i < entryNames.length; i++) {
380
546
  const entryName = entryNames[i];
381
547
  /** entryPointUnfilteredFiles - also includes hot module update files */
382
- const entryPointUnfilteredFiles = compilation.entrypoints.get(entryName).getFiles();
548
+ const entryPointUnfilteredFiles = /** @type {Entrypoint} */ (
549
+ compilation.entrypoints.get(entryName)
550
+ ).getFiles();
383
551
  const entryPointFiles = entryPointUnfilteredFiles.filter((chunkFile) => {
384
552
  const asset = compilation.getAsset(chunkFile);
385
553
 
@@ -390,21 +558,28 @@ class HtmlWebpackPlugin {
390
558
  // Prevent hot-module files from being included:
391
559
  const assetMetaInformation = asset.info || {};
392
560
 
393
- return !(assetMetaInformation.hotModuleReplacement || assetMetaInformation.development);
561
+ return !(
562
+ assetMetaInformation.hotModuleReplacement ||
563
+ assetMetaInformation.development
564
+ );
394
565
  });
395
566
  // Prepend the publicPath and append the hash depending on the
396
567
  // webpack.output.publicPath and hashOptions
397
568
  // E.g. bundle.js -> /bundle.js?hash
398
- const entryPointPublicPaths = entryPointFiles
399
- .map(chunkFile => {
400
- const entryPointPublicPath = publicPath + this.urlencodePath(chunkFile);
401
- return this.options.hash
402
- ? this.appendHash(entryPointPublicPath, compilation.hash)
403
- : entryPointPublicPath;
404
- });
569
+ const entryPointPublicPaths = entryPointFiles.map((chunkFile) => {
570
+ const entryPointPublicPath = publicPath + this.urlencodePath(chunkFile);
571
+ return this.options.hash
572
+ ? this.appendHash(
573
+ entryPointPublicPath,
574
+ /** @type {string} */ (compilation.hash),
575
+ )
576
+ : entryPointPublicPath;
577
+ });
405
578
 
406
579
  entryPointPublicPaths.forEach((entryPointPublicPath) => {
407
- const extMatch = extensionRegexp.exec(entryPointPublicPath);
580
+ const extMatch = extensionRegexp.exec(
581
+ /** @type {string} */ (entryPointPublicPath),
582
+ );
408
583
 
409
584
  // Skip if the public path is not a .css, .mjs or .js file
410
585
  if (!extMatch) {
@@ -420,7 +595,7 @@ class HtmlWebpackPlugin {
420
595
  entryPointPublicPathMap[entryPointPublicPath] = true;
421
596
 
422
597
  // ext will contain .js or .css, because .mjs recognizes as .js
423
- const ext = extMatch[1] === 'mjs' ? 'js' : extMatch[1];
598
+ const ext = extMatch[1] === "mjs" ? "js" : extMatch[1];
424
599
 
425
600
  assets[ext].push(entryPointPublicPath);
426
601
  });
@@ -441,18 +616,22 @@ class HtmlWebpackPlugin {
441
616
  * @param {string} templateFilename
442
617
  * @returns {Promise<string | (() => string | Promise<string>)>}
443
618
  */
444
- evaluateCompilationResult (source, publicPath, templateFilename) {
619
+ evaluateCompilationResult(source, publicPath, templateFilename) {
445
620
  if (!source) {
446
- return Promise.reject(new Error('The child compilation didn\'t provide a result'));
621
+ return Promise.reject(
622
+ new Error("The child compilation didn't provide a result"),
623
+ );
447
624
  }
448
625
 
449
626
  // The LibraryTemplatePlugin stores the template result in a local variable.
450
627
  // By adding it to the end the value gets extracted during evaluation
451
- if (source.indexOf('HTML_WEBPACK_PLUGIN_RESULT') >= 0) {
452
- source += ';\nHTML_WEBPACK_PLUGIN_RESULT';
628
+ if (source.indexOf("HTML_WEBPACK_PLUGIN_RESULT") >= 0) {
629
+ source += ";\nHTML_WEBPACK_PLUGIN_RESULT";
453
630
  }
454
631
 
455
- const templateWithoutLoaders = templateFilename.replace(/^.+!/, '').replace(/\?.+$/, '');
632
+ const templateWithoutLoaders = templateFilename
633
+ .replace(/^.+!/, "")
634
+ .replace(/\?.+$/, "");
456
635
  const vmContext = vm.createContext({
457
636
  ...global,
458
637
  HTML_WEBPACK_PLUGIN: true,
@@ -507,10 +686,12 @@ class HtmlWebpackPlugin {
507
686
  WebAssembly: global.WebAssembly,
508
687
  WritableStream: global.WritableStream,
509
688
  WritableStreamDefaultController: global.WritableStreamDefaultController,
510
- WritableStreamDefaultWriter: global.WritableStreamDefaultWriter
689
+ WritableStreamDefaultWriter: global.WritableStreamDefaultWriter,
511
690
  });
512
691
 
513
- const vmScript = new vm.Script(source, { filename: templateWithoutLoaders });
692
+ const vmScript = new vm.Script(source, {
693
+ filename: templateWithoutLoaders,
694
+ });
514
695
 
515
696
  // Evaluate code and cast to string
516
697
  let newSource;
@@ -521,13 +702,21 @@ class HtmlWebpackPlugin {
521
702
  return Promise.reject(e);
522
703
  }
523
704
 
524
- if (typeof newSource === 'object' && newSource.__esModule && newSource.default) {
705
+ if (
706
+ typeof newSource === "object" &&
707
+ newSource.__esModule &&
708
+ newSource.default
709
+ ) {
525
710
  newSource = newSource.default;
526
711
  }
527
712
 
528
- return typeof newSource === 'string' || typeof newSource === 'function'
713
+ return typeof newSource === "string" || typeof newSource === "function"
529
714
  ? Promise.resolve(newSource)
530
- : Promise.reject(new Error('The loader "' + templateWithoutLoaders + '" didn\'t return html.'));
715
+ : Promise.reject(
716
+ new Error(
717
+ 'The loader "' + templateWithoutLoaders + "\" didn't return html.",
718
+ ),
719
+ );
531
720
  }
532
721
 
533
722
  /**
@@ -537,15 +726,17 @@ class HtmlWebpackPlugin {
537
726
  * @param {Array<HtmlTagObject>} assetTagGroup
538
727
  * @returns {Array<HtmlTagObject>}
539
728
  */
540
- prepareAssetTagGroupForRendering (assetTagGroup) {
729
+ prepareAssetTagGroupForRendering(assetTagGroup) {
541
730
  const xhtml = this.options.xhtml;
542
- return HtmlTagArray.from(assetTagGroup.map((assetTag) => {
543
- const copiedAssetTag = Object.assign({}, assetTag);
544
- copiedAssetTag.toString = function () {
545
- return htmlTagObjectToString(this, xhtml);
546
- };
547
- return copiedAssetTag;
548
- }));
731
+ return HtmlTagArray.from(
732
+ assetTagGroup.map((assetTag) => {
733
+ const copiedAssetTag = Object.assign({}, assetTag);
734
+ copiedAssetTag.toString = function () {
735
+ return htmlTagObjectToString(this, xhtml);
736
+ };
737
+ return copiedAssetTag;
738
+ }),
739
+ );
549
740
  }
550
741
 
551
742
  /**
@@ -560,32 +751,50 @@ class HtmlWebpackPlugin {
560
751
  }} assetTags
561
752
  * @returns {Promise<{[key: any]: any}>}
562
753
  */
563
- getTemplateParameters (compilation, assetsInformationByGroups, assetTags) {
754
+ getTemplateParameters(compilation, assetsInformationByGroups, assetTags) {
564
755
  const templateParameters = this.options.templateParameters;
565
756
 
566
757
  if (templateParameters === false) {
567
758
  return Promise.resolve({});
568
759
  }
569
760
 
570
- if (typeof templateParameters !== 'function' && typeof templateParameters !== 'object') {
571
- throw new Error('templateParameters has to be either a function or an object');
761
+ if (
762
+ typeof templateParameters !== "function" &&
763
+ typeof templateParameters !== "object"
764
+ ) {
765
+ throw new Error(
766
+ "templateParameters has to be either a function or an object",
767
+ );
572
768
  }
573
769
 
574
- const templateParameterFunction = typeof templateParameters === 'function'
575
- // A custom function can overwrite the entire template parameter preparation
576
- ? templateParameters
577
- // If the template parameters is an object merge it with the default values
578
- : (compilation, assetsInformationByGroups, assetTags, options) => Object.assign({},
579
- templateParametersGenerator(compilation, assetsInformationByGroups, assetTags, options),
580
- templateParameters
581
- );
770
+ const templateParameterFunction =
771
+ typeof templateParameters === "function"
772
+ ? // A custom function can overwrite the entire template parameter preparation
773
+ templateParameters
774
+ : // If the template parameters is an object merge it with the default values
775
+ (compilation, assetsInformationByGroups, assetTags, options) =>
776
+ Object.assign(
777
+ {},
778
+ templateParametersGenerator(
779
+ compilation,
780
+ assetsInformationByGroups,
781
+ assetTags,
782
+ options,
783
+ ),
784
+ templateParameters,
785
+ );
582
786
  const preparedAssetTags = {
583
787
  headTags: this.prepareAssetTagGroupForRendering(assetTags.headTags),
584
- bodyTags: this.prepareAssetTagGroupForRendering(assetTags.bodyTags)
788
+ bodyTags: this.prepareAssetTagGroupForRendering(assetTags.bodyTags),
585
789
  };
586
- return Promise
587
- .resolve()
588
- .then(() => templateParameterFunction(compilation, assetsInformationByGroups, preparedAssetTags, this.options));
790
+ return Promise.resolve().then(() =>
791
+ templateParameterFunction(
792
+ compilation,
793
+ assetsInformationByGroups,
794
+ preparedAssetTags,
795
+ this.options,
796
+ ),
797
+ );
589
798
  }
590
799
 
591
800
  /**
@@ -601,9 +810,18 @@ class HtmlWebpackPlugin {
601
810
  * @param {Compilation} compilation
602
811
  * @returns Promise<string>
603
812
  */
604
- executeTemplate (templateFunction, assetsInformationByGroups, assetTags, compilation) {
813
+ executeTemplate(
814
+ templateFunction,
815
+ assetsInformationByGroups,
816
+ assetTags,
817
+ compilation,
818
+ ) {
605
819
  // Template processing
606
- const templateParamsPromise = this.getTemplateParameters(compilation, assetsInformationByGroups, assetTags);
820
+ const templateParamsPromise = this.getTemplateParameters(
821
+ compilation,
822
+ assetsInformationByGroups,
823
+ assetTags,
824
+ );
607
825
 
608
826
  return templateParamsPromise.then((templateParams) => {
609
827
  try {
@@ -611,7 +829,8 @@ class HtmlWebpackPlugin {
611
829
  // If html is a string turn it into a promise
612
830
  return templateFunction(templateParams);
613
831
  } catch (e) {
614
- compilation.errors.push(new Error('Template execution failed: ' + e));
832
+ // @ts-ignore
833
+ compilation.errors.push(new Error("Template execution failed: " + e));
615
834
  return Promise.reject(e);
616
835
  }
617
836
  });
@@ -627,11 +846,20 @@ class HtmlWebpackPlugin {
627
846
  * @param {{headTags: HtmlTagObject[], bodyTags: HtmlTagObject[]}} assetTags The asset tags to inject
628
847
  * @returns {Promise<string>}
629
848
  */
630
- postProcessHtml (compiler, originalHtml, assetsInformationByGroups, assetTags) {
849
+ postProcessHtml(
850
+ compiler,
851
+ originalHtml,
852
+ assetsInformationByGroups,
853
+ assetTags,
854
+ ) {
631
855
  let html = originalHtml;
632
856
 
633
- if (typeof html !== 'string') {
634
- return Promise.reject(new Error('Expected html to be a string but got ' + JSON.stringify(html)));
857
+ if (typeof html !== "string") {
858
+ return Promise.reject(
859
+ new Error(
860
+ "Expected html to be a string but got " + JSON.stringify(html),
861
+ ),
862
+ );
635
863
  }
636
864
 
637
865
  if (this.options.inject) {
@@ -639,22 +867,33 @@ class HtmlWebpackPlugin {
639
867
  const headRegExp = /(<\/head\s*>)/i;
640
868
  const bodyRegExp = /(<\/body\s*>)/i;
641
869
  const metaViewportRegExp = /<meta[^>]+name=["']viewport["'][^>]*>/i;
642
- const body = assetTags.bodyTags.map((assetTagObject) => htmlTagObjectToString(assetTagObject, this.options.xhtml));
643
- const head = assetTags.headTags.filter((item) => {
644
- if (item.tagName === 'meta' && item.attributes && item.attributes.name === 'viewport' && metaViewportRegExp.test(html)) {
645
- return false;
646
- }
870
+ const body = assetTags.bodyTags.map((assetTagObject) =>
871
+ htmlTagObjectToString(assetTagObject, this.options.xhtml),
872
+ );
873
+ const head = assetTags.headTags
874
+ .filter((item) => {
875
+ if (
876
+ item.tagName === "meta" &&
877
+ item.attributes &&
878
+ item.attributes.name === "viewport" &&
879
+ metaViewportRegExp.test(html)
880
+ ) {
881
+ return false;
882
+ }
647
883
 
648
- return true;
649
- }).map((assetTagObject) => htmlTagObjectToString(assetTagObject, this.options.xhtml));
884
+ return true;
885
+ })
886
+ .map((assetTagObject) =>
887
+ htmlTagObjectToString(assetTagObject, this.options.xhtml),
888
+ );
650
889
 
651
890
  if (body.length) {
652
891
  if (bodyRegExp.test(html)) {
653
892
  // Append assets to body element
654
- html = html.replace(bodyRegExp, match => body.join('') + match);
893
+ html = html.replace(bodyRegExp, (match) => body.join("") + match);
655
894
  } else {
656
895
  // Append scripts to the end of the file if no <body> element exists:
657
- html += body.join('');
896
+ html += body.join("");
658
897
  }
659
898
  }
660
899
 
@@ -662,14 +901,14 @@ class HtmlWebpackPlugin {
662
901
  // Create a head tag if none exists
663
902
  if (!headRegExp.test(html)) {
664
903
  if (!htmlRegExp.test(html)) {
665
- html = '<head></head>' + html;
904
+ html = "<head></head>" + html;
666
905
  } else {
667
- html = html.replace(htmlRegExp, match => match + '<head></head>');
906
+ html = html.replace(htmlRegExp, (match) => match + "<head></head>");
668
907
  }
669
908
  }
670
909
 
671
910
  // Append assets to head element
672
- html = html.replace(headRegExp, match => head.join('') + match);
911
+ html = html.replace(headRegExp, (match) => head.join("") + match);
673
912
  }
674
913
 
675
914
  // Inject manifest into the opening html tag
@@ -679,7 +918,13 @@ class HtmlWebpackPlugin {
679
918
  if (/\smanifest\s*=/.test(match)) {
680
919
  return match;
681
920
  }
682
- return start + ' manifest="' + assetsInformationByGroups.manifest + '"' + end;
921
+ return (
922
+ start +
923
+ ' manifest="' +
924
+ assetsInformationByGroups.manifest +
925
+ '"' +
926
+ end
927
+ );
683
928
  });
684
929
  }
685
930
  }
@@ -687,41 +932,48 @@ class HtmlWebpackPlugin {
687
932
  // TODO avoid this logic and use https://github.com/webpack-contrib/html-minimizer-webpack-plugin under the hood in the next major version
688
933
  // Check if webpack is running in production mode
689
934
  // @see https://github.com/webpack/webpack/blob/3366421f1784c449f415cda5930a8e445086f688/lib/WebpackOptionsDefaulter.js#L12-L14
690
- const isProductionLikeMode = compiler.options.mode === 'production' || !compiler.options.mode;
691
- const needMinify = this.options.minify === true || typeof this.options.minify === 'object' || (this.options.minify === 'auto' && isProductionLikeMode);
935
+ const isProductionLikeMode =
936
+ compiler.options.mode === "production" || !compiler.options.mode;
937
+ const needMinify =
938
+ this.options.minify === true ||
939
+ typeof this.options.minify === "object" ||
940
+ (this.options.minify === "auto" && isProductionLikeMode);
692
941
 
693
942
  if (!needMinify) {
694
943
  return Promise.resolve(html);
695
944
  }
696
945
 
697
- const minifyOptions = typeof this.options.minify === 'object'
698
- ? this.options.minify
699
- : {
700
- // https://www.npmjs.com/package/html-minifier-terser#options-quick-reference
701
- collapseWhitespace: true,
702
- keepClosingSlash: true,
703
- removeComments: true,
704
- removeRedundantAttributes: true,
705
- removeScriptTypeAttributes: true,
706
- removeStyleLinkTypeAttributes: true,
707
- useShortDoctype: true
708
- };
946
+ const minifyOptions =
947
+ typeof this.options.minify === "object"
948
+ ? this.options.minify
949
+ : {
950
+ // https://www.npmjs.com/package/html-minifier-terser#options-quick-reference
951
+ collapseWhitespace: true,
952
+ keepClosingSlash: true,
953
+ removeComments: true,
954
+ removeRedundantAttributes: true,
955
+ removeScriptTypeAttributes: true,
956
+ removeStyleLinkTypeAttributes: true,
957
+ useShortDoctype: true,
958
+ };
709
959
 
710
960
  try {
711
- html = require('html-minifier-terser').minify(html, minifyOptions);
961
+ html = require("html-minifier-terser").minify(html, minifyOptions);
712
962
  } catch (e) {
713
- const isParseError = String(e.message).indexOf('Parse Error') === 0;
963
+ const isParseError = String(e.message).indexOf("Parse Error") === 0;
714
964
 
715
965
  if (isParseError) {
716
- e.message = 'html-webpack-plugin could not minify the generated output.\n' +
717
- 'In production mode the html minifcation is enabled by default.\n' +
718
- 'If you are not generating a valid html output please disable it manually.\n' +
719
- 'You can do so by adding the following setting to your HtmlWebpackPlugin config:\n|\n|' +
720
- ' minify: false\n|\n' +
721
- 'See https://github.com/jantimon/html-webpack-plugin#options for details.\n\n' +
722
- 'For parser dedicated bugs please create an issue here:\n' +
723
- 'https://danielruf.github.io/html-minifier-terser/' +
724
- '\n' + e.message;
966
+ e.message =
967
+ "html-webpack-plugin could not minify the generated output.\n" +
968
+ "In production mode the html minification is enabled by default.\n" +
969
+ "If you are not generating a valid html output please disable it manually.\n" +
970
+ "You can do so by adding the following setting to your HtmlWebpackPlugin config:\n|\n|" +
971
+ " minify: false\n|\n" +
972
+ "See https://github.com/jantimon/html-webpack-plugin#options for details.\n\n" +
973
+ "For parser dedicated bugs please create an issue here:\n" +
974
+ "https://danielruf.github.io/html-minifier-terser/" +
975
+ "\n" +
976
+ e.message;
725
977
  }
726
978
 
727
979
  return Promise.reject(e);
@@ -734,8 +986,12 @@ class HtmlWebpackPlugin {
734
986
  * Helper to return a sorted unique array of all asset files out of the asset object
735
987
  * @private
736
988
  */
737
- getAssetFiles (assets) {
738
- const files = _.uniq(Object.keys(assets).filter(assetType => assetType !== 'chunks' && assets[assetType]).reduce((files, assetType) => files.concat(assets[assetType]), []));
989
+ getAssetFiles(assets) {
990
+ const files = _uniq(
991
+ Object.keys(assets)
992
+ .filter((assetType) => assetType !== "chunks" && assets[assetType])
993
+ .reduce((files, assetType) => files.concat(assets[assetType]), []),
994
+ );
739
995
  files.sort();
740
996
  return files;
741
997
  }
@@ -751,7 +1007,13 @@ class HtmlWebpackPlugin {
751
1007
  * @param {PreviousEmittedAssets} previousEmittedAssets
752
1008
  * @returns {Promise<string|undefined>}
753
1009
  */
754
- generateFavicon (compiler, favicon, compilation, publicPath, previousEmittedAssets) {
1010
+ generateFavicon(
1011
+ compiler,
1012
+ favicon,
1013
+ compilation,
1014
+ publicPath,
1015
+ previousEmittedAssets,
1016
+ ) {
755
1017
  if (!favicon) {
756
1018
  return Promise.resolve(undefined);
757
1019
  }
@@ -760,7 +1022,10 @@ class HtmlWebpackPlugin {
760
1022
 
761
1023
  return promisify(compilation.inputFileSystem.readFile)(filename)
762
1024
  .then((buf) => {
763
- const source = new compiler.webpack.sources.RawSource(/** @type {string | Buffer} */ (buf), false);
1025
+ const source = new compiler.webpack.sources.RawSource(
1026
+ /** @type {string | Buffer} */ (buf),
1027
+ false,
1028
+ );
764
1029
  const name = path.basename(filename);
765
1030
 
766
1031
  compilation.fileDependencies.add(filename);
@@ -770,12 +1035,19 @@ class HtmlWebpackPlugin {
770
1035
  const faviconPath = publicPath + name;
771
1036
 
772
1037
  if (this.options.hash) {
773
- return this.appendHash(faviconPath, /** @type {string} */ (compilation.hash));
1038
+ return this.appendHash(
1039
+ faviconPath,
1040
+ /** @type {string} */ (compilation.hash),
1041
+ );
774
1042
  }
775
1043
 
776
1044
  return faviconPath;
777
1045
  })
778
- .catch(() => Promise.reject(new Error('HtmlWebpackPlugin: could not load file ' + filename)));
1046
+ .catch(() =>
1047
+ Promise.reject(
1048
+ new Error("HtmlWebpackPlugin: could not load file " + filename),
1049
+ ),
1050
+ );
779
1051
  }
780
1052
 
781
1053
  /**
@@ -785,26 +1057,26 @@ class HtmlWebpackPlugin {
785
1057
  * @param {Array<string>} jsAssets
786
1058
  * @returns {Array<HtmlTagObject>}
787
1059
  */
788
- generatedScriptTags (jsAssets) {
1060
+ generatedScriptTags(jsAssets) {
789
1061
  // @ts-ignore
790
- return jsAssets.map(src => {
1062
+ return jsAssets.map((src) => {
791
1063
  const attributes = {};
792
1064
 
793
- if (this.options.scriptLoading === 'defer') {
1065
+ if (this.options.scriptLoading === "defer") {
794
1066
  attributes.defer = true;
795
- } else if (this.options.scriptLoading === 'module') {
796
- attributes.type = 'module';
797
- } else if (this.options.scriptLoading === 'systemjs-module') {
798
- attributes.type = 'systemjs-module';
1067
+ } else if (this.options.scriptLoading === "module") {
1068
+ attributes.type = "module";
1069
+ } else if (this.options.scriptLoading === "systemjs-module") {
1070
+ attributes.type = "systemjs-module";
799
1071
  }
800
1072
 
801
1073
  attributes.src = src;
802
1074
 
803
1075
  return {
804
- tagName: 'script',
1076
+ tagName: "script",
805
1077
  voidTag: false,
806
- meta: { plugin: 'html-webpack-plugin' },
807
- attributes
1078
+ meta: { plugin: "html-webpack-plugin" },
1079
+ attributes,
808
1080
  };
809
1081
  });
810
1082
  }
@@ -816,15 +1088,15 @@ class HtmlWebpackPlugin {
816
1088
  * @param {Array<string>} cssAssets
817
1089
  * @returns {Array<HtmlTagObject>}
818
1090
  */
819
- generateStyleTags (cssAssets) {
820
- return cssAssets.map(styleAsset => ({
821
- tagName: 'link',
1091
+ generateStyleTags(cssAssets) {
1092
+ return cssAssets.map((styleAsset) => ({
1093
+ tagName: "link",
822
1094
  voidTag: true,
823
- meta: { plugin: 'html-webpack-plugin' },
1095
+ meta: { plugin: "html-webpack-plugin" },
824
1096
  attributes: {
825
1097
  href: styleAsset,
826
- rel: 'stylesheet'
827
- }
1098
+ rel: "stylesheet",
1099
+ },
828
1100
  }));
829
1101
  }
830
1102
 
@@ -834,16 +1106,21 @@ class HtmlWebpackPlugin {
834
1106
  * @param {string | {[attributeName: string]: string}} base
835
1107
  * @returns {Array<HtmlTagObject>}
836
1108
  */
837
- generateBaseTag (base) {
838
- return [{
839
- tagName: 'base',
840
- voidTag: true,
841
- meta: { plugin: 'html-webpack-plugin' },
842
- // attributes e.g. { href:"http://example.com/page.html" target:"_blank" }
843
- attributes: typeof base === 'string' ? {
844
- href: base
845
- } : base
846
- }];
1109
+ generateBaseTag(base) {
1110
+ return [
1111
+ {
1112
+ tagName: "base",
1113
+ voidTag: true,
1114
+ meta: { plugin: "html-webpack-plugin" },
1115
+ // attributes e.g. { href:"http://example.com/page.html" target:"_blank" }
1116
+ attributes:
1117
+ typeof base === "string"
1118
+ ? {
1119
+ href: base,
1120
+ }
1121
+ : base,
1122
+ },
1123
+ ];
847
1124
  }
848
1125
 
849
1126
  /**
@@ -853,7 +1130,7 @@ class HtmlWebpackPlugin {
853
1130
  * @param {false | {[name: string]: false | string | {[attributeName: string]: string|boolean}}} metaOptions
854
1131
  * @returns {Array<HtmlTagObject>}
855
1132
  */
856
- generatedMetaTags (metaOptions) {
1133
+ generatedMetaTags(metaOptions) {
857
1134
  if (metaOptions === false) {
858
1135
  return [];
859
1136
  }
@@ -864,10 +1141,12 @@ class HtmlWebpackPlugin {
864
1141
  const metaTagAttributeObjects = Object.keys(metaOptions)
865
1142
  .map((metaName) => {
866
1143
  const metaTagContent = metaOptions[metaName];
867
- return (typeof metaTagContent === 'string') ? {
868
- name: metaName,
869
- content: metaTagContent
870
- } : metaTagContent;
1144
+ return typeof metaTagContent === "string"
1145
+ ? {
1146
+ name: metaName,
1147
+ content: metaTagContent,
1148
+ }
1149
+ : metaTagContent;
871
1150
  })
872
1151
  .filter((attribute) => attribute !== false);
873
1152
 
@@ -875,13 +1154,13 @@ class HtmlWebpackPlugin {
875
1154
  // the html-webpack-plugin tag structure
876
1155
  return metaTagAttributeObjects.map((metaTagAttributes) => {
877
1156
  if (metaTagAttributes === false) {
878
- throw new Error('Invalid meta tag');
1157
+ throw new Error("Invalid meta tag");
879
1158
  }
880
1159
  return {
881
- tagName: 'meta',
1160
+ tagName: "meta",
882
1161
  voidTag: true,
883
- meta: { plugin: 'html-webpack-plugin' },
884
- attributes: metaTagAttributes
1162
+ meta: { plugin: "html-webpack-plugin" },
1163
+ attributes: metaTagAttributes,
885
1164
  };
886
1165
  });
887
1166
  }
@@ -893,16 +1172,18 @@ class HtmlWebpackPlugin {
893
1172
  * @param {string} favicon
894
1173
  * @returns {Array<HtmlTagObject>}
895
1174
  */
896
- generateFaviconTag (favicon) {
897
- return [{
898
- tagName: 'link',
899
- voidTag: true,
900
- meta: { plugin: 'html-webpack-plugin' },
901
- attributes: {
902
- rel: 'icon',
903
- href: favicon
904
- }
905
- }];
1175
+ generateFaviconTag(favicon) {
1176
+ return [
1177
+ {
1178
+ tagName: "link",
1179
+ voidTag: true,
1180
+ meta: { plugin: "html-webpack-plugin" },
1181
+ attributes: {
1182
+ rel: "icon",
1183
+ href: favicon,
1184
+ },
1185
+ },
1186
+ ];
906
1187
  }
907
1188
 
908
1189
  /**
@@ -919,24 +1200,24 @@ class HtmlWebpackPlugin {
919
1200
  bodyTags: Array<HtmlTagObject>;
920
1201
  }}
921
1202
  */
922
- groupAssetsByElements (assetTags, scriptTarget) {
1203
+ groupAssetsByElements(assetTags, scriptTarget) {
923
1204
  /** @type {{ headTags: Array<HtmlTagObject>; bodyTags: Array<HtmlTagObject>; }} */
924
1205
  const result = {
925
- headTags: [
926
- ...assetTags.meta,
927
- ...assetTags.styles
928
- ],
929
- bodyTags: []
1206
+ headTags: [...assetTags.meta, ...assetTags.styles],
1207
+ bodyTags: [],
930
1208
  };
931
1209
 
932
1210
  // Add script tags to head or body depending on
933
1211
  // the htmlPluginOptions
934
- if (scriptTarget === 'body') {
1212
+ if (scriptTarget === "body") {
935
1213
  result.bodyTags.push(...assetTags.scripts);
936
1214
  } else {
937
1215
  // If script loading is blocking add the scripts to the end of the head
938
1216
  // If script loading is non-blocking add the scripts in front of the css files
939
- const insertPosition = this.options.scriptLoading === 'blocking' ? result.headTags.length : assetTags.meta.length;
1217
+ const insertPosition =
1218
+ this.options.scriptLoading === "blocking"
1219
+ ? result.headTags.length
1220
+ : assetTags.meta.length;
940
1221
 
941
1222
  result.headTags.splice(insertPosition, 0, ...assetTags.scripts);
942
1223
  }
@@ -956,12 +1237,14 @@ class HtmlWebpackPlugin {
956
1237
  * @param {Compilation} compilation
957
1238
  * @returns {{ path: string, info: {} }}
958
1239
  */
959
- replacePlaceholdersInFilename (compiler, filename, fileContent, compilation) {
1240
+ replacePlaceholdersInFilename(compiler, filename, fileContent, compilation) {
960
1241
  if (/\[\\*([\w:]+)\\*\]/i.test(filename) === false) {
961
1242
  return { path: filename, info: {} };
962
1243
  }
963
1244
 
964
- const hash = compiler.webpack.util.createHash(compilation.outputOptions.hashFunction);
1245
+ const hash = compiler.webpack.util.createHash(
1246
+ compilation.outputOptions.hashFunction,
1247
+ );
965
1248
 
966
1249
  hash.update(fileContent);
967
1250
 
@@ -969,18 +1252,20 @@ class HtmlWebpackPlugin {
969
1252
  hash.update(compilation.outputOptions.hashSalt);
970
1253
  }
971
1254
 
972
- const contentHash = hash.digest(compilation.outputOptions.hashDigest).slice(0, compilation.outputOptions.hashDigestLength);
1255
+ const contentHash = /** @type {string} */ (
1256
+ hash
1257
+ .digest(compilation.outputOptions.hashDigest)
1258
+ .slice(0, compilation.outputOptions.hashDigestLength)
1259
+ );
973
1260
 
974
- return compilation.getPathWithInfo(
975
- filename,
976
- {
1261
+ return compilation.getPathWithInfo(filename, {
1262
+ contentHash,
1263
+ chunk: {
1264
+ hash: contentHash,
1265
+ // @ts-ignore
977
1266
  contentHash,
978
- chunk: {
979
- hash: contentHash,
980
- contentHash
981
- }
982
- }
983
- );
1267
+ },
1268
+ });
984
1269
  }
985
1270
 
986
1271
  /**
@@ -995,36 +1280,57 @@ class HtmlWebpackPlugin {
995
1280
  * @param {{ value: string | undefined }} assetJson
996
1281
  * @param {(err?: Error) => void} callback
997
1282
  */
998
- generateHTML (
1283
+ generateHTML(
999
1284
  compiler,
1000
1285
  compilation,
1001
1286
  outputName,
1002
1287
  childCompilerPlugin,
1003
1288
  previousEmittedAssets,
1004
1289
  assetJson,
1005
- callback
1290
+ callback,
1006
1291
  ) {
1007
1292
  // Get all entry point names for this html file
1008
1293
  const entryNames = Array.from(compilation.entrypoints.keys());
1009
- const filteredEntryNames = this.filterEntryChunks(entryNames, this.options.chunks, this.options.excludeChunks);
1010
- const sortedEntryNames = this.sortEntryChunks(filteredEntryNames, this.options.chunksSortMode, compilation);
1294
+ const filteredEntryNames = this.filterEntryChunks(
1295
+ entryNames,
1296
+ this.options.chunks,
1297
+ this.options.excludeChunks,
1298
+ );
1299
+ const sortedEntryNames = this.sortEntryChunks(
1300
+ filteredEntryNames,
1301
+ this.options.chunksSortMode,
1302
+ compilation,
1303
+ );
1011
1304
  const templateResult = this.options.templateContent
1012
1305
  ? { mainCompilationHash: compilation.hash }
1013
1306
  : childCompilerPlugin.getCompilationEntryResult(this.options.template);
1014
1307
 
1015
- if ('error' in templateResult) {
1016
- compilation.errors.push(prettyError(templateResult.error, compiler.context).toString());
1308
+ if ("error" in templateResult) {
1309
+ compilation.errors.push(
1310
+ prettyError(templateResult.error, compiler.context).toString(),
1311
+ );
1017
1312
  }
1018
1313
 
1019
1314
  // If the child compilation was not executed during a previous main compile run
1020
1315
  // it is a cached result
1021
- const isCompilationCached = templateResult.mainCompilationHash !== compilation.hash;
1316
+ const isCompilationCached =
1317
+ templateResult.mainCompilationHash !== compilation.hash;
1022
1318
  /** Generated file paths from the entry point names */
1023
- const assetsInformationByGroups = this.getAssetsInformationByGroups(compilation, outputName, sortedEntryNames);
1319
+ const assetsInformationByGroups = this.getAssetsInformationByGroups(
1320
+ compilation,
1321
+ outputName,
1322
+ sortedEntryNames,
1323
+ );
1024
1324
  // If the template and the assets did not change we don't have to emit the html
1025
- const newAssetJson = JSON.stringify(this.getAssetFiles(assetsInformationByGroups));
1325
+ const newAssetJson = JSON.stringify(
1326
+ this.getAssetFiles(assetsInformationByGroups),
1327
+ );
1026
1328
 
1027
- if (isCompilationCached && this.options.cache && assetJson.value === newAssetJson) {
1329
+ if (
1330
+ isCompilationCached &&
1331
+ this.options.cache &&
1332
+ assetJson.value === newAssetJson
1333
+ ) {
1028
1334
  previousEmittedAssets.forEach(({ name, source, info }) => {
1029
1335
  compilation.emitAsset(name, source, info);
1030
1336
  });
@@ -1037,127 +1343,204 @@ class HtmlWebpackPlugin {
1037
1343
  // The html-webpack plugin uses a object representation for the html-tags which will be injected
1038
1344
  // to allow altering them more easily
1039
1345
  // Just before they are converted a third-party-plugin author might change the order and content
1040
- const assetsPromise = this.generateFavicon(compiler, this.options.favicon, compilation, assetsInformationByGroups.publicPath, previousEmittedAssets)
1041
- .then((faviconPath) => {
1042
- assetsInformationByGroups.favicon = faviconPath;
1043
- return getHtmlWebpackPluginHooks(compilation).beforeAssetTagGeneration.promise({
1044
- assets: assetsInformationByGroups,
1045
- outputName,
1046
- plugin: this
1047
- });
1346
+ const assetsPromise = this.generateFavicon(
1347
+ compiler,
1348
+ this.options.favicon,
1349
+ compilation,
1350
+ assetsInformationByGroups.publicPath,
1351
+ previousEmittedAssets,
1352
+ ).then((faviconPath) => {
1353
+ assetsInformationByGroups.favicon = faviconPath;
1354
+ return HtmlWebpackPlugin.getCompilationHooks(
1355
+ compilation,
1356
+ ).beforeAssetTagGeneration.promise({
1357
+ assets: assetsInformationByGroups,
1358
+ outputName,
1359
+ plugin: this,
1048
1360
  });
1361
+ });
1049
1362
 
1050
1363
  // Turn the js and css paths into grouped HtmlTagObjects
1051
1364
  const assetTagGroupsPromise = assetsPromise
1052
1365
  // And allow third-party-plugin authors to reorder and change the assetTags before they are grouped
1053
- .then(({ assets }) => getHtmlWebpackPluginHooks(compilation).alterAssetTags.promise({
1054
- assetTags: {
1055
- scripts: this.generatedScriptTags(assets.js),
1056
- styles: this.generateStyleTags(assets.css),
1057
- meta: [
1058
- ...(this.options.base !== false ? this.generateBaseTag(this.options.base) : []),
1059
- ...this.generatedMetaTags(this.options.meta),
1060
- ...(assets.favicon ? this.generateFaviconTag(assets.favicon) : [])
1061
- ]
1062
- },
1063
- outputName,
1064
- publicPath: assetsInformationByGroups.publicPath,
1065
- plugin: this
1066
- }))
1366
+ .then(({ assets }) =>
1367
+ HtmlWebpackPlugin.getCompilationHooks(
1368
+ compilation,
1369
+ ).alterAssetTags.promise({
1370
+ assetTags: {
1371
+ scripts: this.generatedScriptTags(assets.js),
1372
+ styles: this.generateStyleTags(assets.css),
1373
+ meta: [
1374
+ ...(this.options.base !== false
1375
+ ? this.generateBaseTag(this.options.base)
1376
+ : []),
1377
+ ...this.generatedMetaTags(this.options.meta),
1378
+ ...(assets.favicon
1379
+ ? this.generateFaviconTag(assets.favicon)
1380
+ : []),
1381
+ ],
1382
+ },
1383
+ outputName,
1384
+ publicPath: assetsInformationByGroups.publicPath,
1385
+ plugin: this,
1386
+ }),
1387
+ )
1067
1388
  .then(({ assetTags }) => {
1068
1389
  // Inject scripts to body unless it set explicitly to head
1069
- const scriptTarget = this.options.inject === 'head' ||
1070
- (this.options.inject !== 'body' && this.options.scriptLoading !== 'blocking') ? 'head' : 'body';
1390
+ const scriptTarget =
1391
+ this.options.inject === "head" ||
1392
+ (this.options.inject !== "body" &&
1393
+ this.options.scriptLoading !== "blocking")
1394
+ ? "head"
1395
+ : "body";
1071
1396
  // Group assets to `head` and `body` tag arrays
1072
1397
  const assetGroups = this.groupAssetsByElements(assetTags, scriptTarget);
1073
1398
  // Allow third-party-plugin authors to reorder and change the assetTags once they are grouped
1074
- return getHtmlWebpackPluginHooks(compilation).alterAssetTagGroups.promise({
1399
+ return HtmlWebpackPlugin.getCompilationHooks(
1400
+ compilation,
1401
+ ).alterAssetTagGroups.promise({
1075
1402
  headTags: assetGroups.headTags,
1076
1403
  bodyTags: assetGroups.bodyTags,
1077
1404
  outputName,
1078
1405
  publicPath: assetsInformationByGroups.publicPath,
1079
- plugin: this
1406
+ plugin: this,
1080
1407
  });
1081
1408
  });
1082
1409
 
1083
1410
  // Turn the compiled template into a nodejs function or into a nodejs string
1084
- const templateEvaluationPromise = Promise.resolve()
1085
- .then(() => {
1086
- if ('error' in templateResult) {
1087
- return this.options.showErrors ? prettyError(templateResult.error, compiler.context).toHtml() : 'ERROR';
1088
- }
1089
-
1090
- // Allow to use a custom function / string instead
1091
- if (this.options.templateContent !== false) {
1092
- return this.options.templateContent;
1093
- }
1094
-
1095
- // Once everything is compiled evaluate the html factory and replace it with its content
1096
- if ('compiledEntry' in templateResult) {
1097
- const compiledEntry = templateResult.compiledEntry;
1098
- const assets = compiledEntry.assets;
1411
+ const templateEvaluationPromise = Promise.resolve().then(() => {
1412
+ if ("error" in templateResult) {
1413
+ return this.options.showErrors
1414
+ ? prettyError(templateResult.error, compiler.context).toHtml()
1415
+ : "ERROR";
1416
+ }
1099
1417
 
1100
- // Store assets from child compiler to reemit them later
1101
- for (const name in assets) {
1102
- previousEmittedAssets.push({ name, source: assets[name].source, info: assets[name].info });
1103
- }
1418
+ // Allow to use a custom function / string instead
1419
+ if (this.options.templateContent !== false) {
1420
+ return this.options.templateContent;
1421
+ }
1104
1422
 
1105
- return this.evaluateCompilationResult(compiledEntry.content, assetsInformationByGroups.publicPath, this.options.template);
1423
+ // Once everything is compiled evaluate the html factory and replace it with its content
1424
+ if ("compiledEntry" in templateResult) {
1425
+ const compiledEntry = templateResult.compiledEntry;
1426
+ const assets = compiledEntry.assets;
1427
+
1428
+ // Store assets from child compiler to re-emit them later
1429
+ for (const name in assets) {
1430
+ previousEmittedAssets.push({
1431
+ name,
1432
+ source: assets[name].source,
1433
+ info: assets[name].info,
1434
+ });
1106
1435
  }
1107
1436
 
1108
- return Promise.reject(new Error('Child compilation contained no compiledEntry'));
1109
- });
1110
- const templateExectutionPromise = Promise.all([assetsPromise, assetTagGroupsPromise, templateEvaluationPromise])
1437
+ return this.evaluateCompilationResult(
1438
+ compiledEntry.content,
1439
+ assetsInformationByGroups.publicPath,
1440
+ this.options.template,
1441
+ );
1442
+ }
1443
+
1444
+ return Promise.reject(
1445
+ new Error("Child compilation contained no compiledEntry"),
1446
+ );
1447
+ });
1448
+ const templateExecutionPromise = Promise.all([
1449
+ assetsPromise,
1450
+ assetTagGroupsPromise,
1451
+ templateEvaluationPromise,
1452
+ ])
1111
1453
  // Execute the template
1112
- .then(([assetsHookResult, assetTags, compilationResult]) => typeof compilationResult !== 'function'
1113
- ? compilationResult
1114
- : this.executeTemplate(compilationResult, assetsHookResult.assets, { headTags: assetTags.headTags, bodyTags: assetTags.bodyTags }, compilation));
1454
+ .then(([assetsHookResult, assetTags, compilationResult]) =>
1455
+ typeof compilationResult !== "function"
1456
+ ? compilationResult
1457
+ : this.executeTemplate(
1458
+ compilationResult,
1459
+ assetsHookResult.assets,
1460
+ { headTags: assetTags.headTags, bodyTags: assetTags.bodyTags },
1461
+ compilation,
1462
+ ),
1463
+ );
1115
1464
 
1116
- const injectedHtmlPromise = Promise.all([assetTagGroupsPromise, templateExectutionPromise])
1465
+ const injectedHtmlPromise = Promise.all([
1466
+ assetTagGroupsPromise,
1467
+ templateExecutionPromise,
1468
+ ])
1117
1469
  // Allow plugins to change the html before assets are injected
1118
1470
  .then(([assetTags, html]) => {
1119
- const pluginArgs = { html, headTags: assetTags.headTags, bodyTags: assetTags.bodyTags, plugin: this, outputName };
1120
- return getHtmlWebpackPluginHooks(compilation).afterTemplateExecution.promise(pluginArgs);
1471
+ const pluginArgs = {
1472
+ html,
1473
+ headTags: assetTags.headTags,
1474
+ bodyTags: assetTags.bodyTags,
1475
+ plugin: this,
1476
+ outputName,
1477
+ };
1478
+ return HtmlWebpackPlugin.getCompilationHooks(
1479
+ compilation,
1480
+ ).afterTemplateExecution.promise(pluginArgs);
1121
1481
  })
1122
1482
  .then(({ html, headTags, bodyTags }) => {
1123
- return this.postProcessHtml(compiler, html, assetsInformationByGroups, { headTags, bodyTags });
1483
+ return this.postProcessHtml(compiler, html, assetsInformationByGroups, {
1484
+ headTags,
1485
+ bodyTags,
1486
+ });
1124
1487
  });
1125
1488
 
1126
1489
  const emitHtmlPromise = injectedHtmlPromise
1127
1490
  // Allow plugins to change the html after assets are injected
1128
1491
  .then((html) => {
1129
1492
  const pluginArgs = { html, plugin: this, outputName };
1130
- return getHtmlWebpackPluginHooks(compilation).beforeEmit.promise(pluginArgs)
1131
- .then(result => result.html);
1493
+ return HtmlWebpackPlugin.getCompilationHooks(compilation)
1494
+ .beforeEmit.promise(pluginArgs)
1495
+ .then((result) => result.html);
1132
1496
  })
1133
- .catch(err => {
1497
+ .catch((err) => {
1134
1498
  // In case anything went wrong the promise is resolved
1135
1499
  // with the error message and an error is logged
1136
1500
  compilation.errors.push(prettyError(err, compiler.context).toString());
1137
- return this.options.showErrors ? prettyError(err, compiler.context).toHtml() : 'ERROR';
1501
+ return this.options.showErrors
1502
+ ? prettyError(err, compiler.context).toHtml()
1503
+ : "ERROR";
1138
1504
  })
1139
- .then(html => {
1140
- const filename = outputName.replace(/\[templatehash([^\]]*)\]/g, require('util').deprecate(
1141
- (match, options) => `[contenthash${options}]`,
1142
- '[templatehash] is now [contenthash]')
1505
+ .then((html) => {
1506
+ const filename = outputName.replace(
1507
+ /\[templatehash([^\]]*)\]/g,
1508
+ require("util").deprecate(
1509
+ (match, options) => `[contenthash${options}]`,
1510
+ "[templatehash] is now [contenthash]",
1511
+ ),
1512
+ );
1513
+ const replacedFilename = this.replacePlaceholdersInFilename(
1514
+ compiler,
1515
+ filename,
1516
+ html,
1517
+ compilation,
1143
1518
  );
1144
- const replacedFilename = this.replacePlaceholdersInFilename(compiler, filename, html, compilation);
1145
1519
  const source = new compiler.webpack.sources.RawSource(html, false);
1146
1520
 
1147
1521
  // Add the evaluated html code to the webpack assets
1148
- compilation.emitAsset(replacedFilename.path, source, replacedFilename.info);
1522
+ compilation.emitAsset(
1523
+ replacedFilename.path,
1524
+ source,
1525
+ replacedFilename.info,
1526
+ );
1149
1527
  previousEmittedAssets.push({ name: replacedFilename.path, source });
1150
1528
 
1151
1529
  return replacedFilename.path;
1152
1530
  })
1153
- .then((finalOutputName) => getHtmlWebpackPluginHooks(compilation).afterEmit.promise({
1154
- outputName: finalOutputName,
1155
- plugin: this
1156
- }).catch(err => {
1157
- /** @type {Logger} */
1158
- (this.logger).error(err);
1159
- return null;
1160
- }).then(() => null));
1531
+ .then((finalOutputName) =>
1532
+ HtmlWebpackPlugin.getCompilationHooks(compilation)
1533
+ .afterEmit.promise({
1534
+ outputName: finalOutputName,
1535
+ plugin: this,
1536
+ })
1537
+ .catch((err) => {
1538
+ /** @type {Logger} */
1539
+ (this.logger).error(err);
1540
+ return null;
1541
+ })
1542
+ .then(() => null),
1543
+ );
1161
1544
 
1162
1545
  // Once all files are added to the webpack compilation
1163
1546
  // let the webpack compiler continue
@@ -1181,15 +1564,15 @@ class HtmlWebpackPlugin {
1181
1564
  * @param {ProcessedHtmlWebpackOptions} options
1182
1565
  * @returns {TemplateParameter}
1183
1566
  */
1184
- function templateParametersGenerator (compilation, assets, assetTags, options) {
1567
+ function templateParametersGenerator(compilation, assets, assetTags, options) {
1185
1568
  return {
1186
1569
  compilation: compilation,
1187
1570
  webpackConfig: compilation.options,
1188
1571
  htmlWebpackPlugin: {
1189
1572
  tags: assetTags,
1190
1573
  files: assets,
1191
- options: options
1192
- }
1574
+ options: options,
1575
+ },
1193
1576
  };
1194
1577
  }
1195
1578
 
@@ -1204,7 +1587,8 @@ HtmlWebpackPlugin.version = 5;
1204
1587
  *
1205
1588
  * Usage: HtmlWebpackPlugin.getHooks(compilation).HOOK_NAME.tapAsync('YourPluginName', () => { ... });
1206
1589
  */
1207
- HtmlWebpackPlugin.getHooks = getHtmlWebpackPluginHooks;
1590
+ // TODO remove me in the next major release in favor getCompilationHooks
1591
+ HtmlWebpackPlugin.getHooks = HtmlWebpackPlugin.getCompilationHooks;
1208
1592
  HtmlWebpackPlugin.createHtmlTagObject = createHtmlTagObject;
1209
1593
 
1210
1594
  module.exports = HtmlWebpackPlugin;