html-webpack-plugin 5.5.4 → 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') {
82
- /** @type {Logger} */
83
- (this.logger).error('The "scriptLoading" option need to be set to "defer", "blocking" or "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,24 +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';
1067
+ } else if (this.options.scriptLoading === "module") {
1068
+ attributes.type = "module";
1069
+ } else if (this.options.scriptLoading === "systemjs-module") {
1070
+ attributes.type = "systemjs-module";
797
1071
  }
798
1072
 
799
1073
  attributes.src = src;
800
1074
 
801
1075
  return {
802
- tagName: 'script',
1076
+ tagName: "script",
803
1077
  voidTag: false,
804
- meta: { plugin: 'html-webpack-plugin' },
805
- attributes
1078
+ meta: { plugin: "html-webpack-plugin" },
1079
+ attributes,
806
1080
  };
807
1081
  });
808
1082
  }
@@ -814,15 +1088,15 @@ class HtmlWebpackPlugin {
814
1088
  * @param {Array<string>} cssAssets
815
1089
  * @returns {Array<HtmlTagObject>}
816
1090
  */
817
- generateStyleTags (cssAssets) {
818
- return cssAssets.map(styleAsset => ({
819
- tagName: 'link',
1091
+ generateStyleTags(cssAssets) {
1092
+ return cssAssets.map((styleAsset) => ({
1093
+ tagName: "link",
820
1094
  voidTag: true,
821
- meta: { plugin: 'html-webpack-plugin' },
1095
+ meta: { plugin: "html-webpack-plugin" },
822
1096
  attributes: {
823
1097
  href: styleAsset,
824
- rel: 'stylesheet'
825
- }
1098
+ rel: "stylesheet",
1099
+ },
826
1100
  }));
827
1101
  }
828
1102
 
@@ -832,16 +1106,21 @@ class HtmlWebpackPlugin {
832
1106
  * @param {string | {[attributeName: string]: string}} base
833
1107
  * @returns {Array<HtmlTagObject>}
834
1108
  */
835
- generateBaseTag (base) {
836
- return [{
837
- tagName: 'base',
838
- voidTag: true,
839
- meta: { plugin: 'html-webpack-plugin' },
840
- // attributes e.g. { href:"http://example.com/page.html" target:"_blank" }
841
- attributes: typeof base === 'string' ? {
842
- href: base
843
- } : base
844
- }];
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
+ ];
845
1124
  }
846
1125
 
847
1126
  /**
@@ -851,7 +1130,7 @@ class HtmlWebpackPlugin {
851
1130
  * @param {false | {[name: string]: false | string | {[attributeName: string]: string|boolean}}} metaOptions
852
1131
  * @returns {Array<HtmlTagObject>}
853
1132
  */
854
- generatedMetaTags (metaOptions) {
1133
+ generatedMetaTags(metaOptions) {
855
1134
  if (metaOptions === false) {
856
1135
  return [];
857
1136
  }
@@ -862,10 +1141,12 @@ class HtmlWebpackPlugin {
862
1141
  const metaTagAttributeObjects = Object.keys(metaOptions)
863
1142
  .map((metaName) => {
864
1143
  const metaTagContent = metaOptions[metaName];
865
- return (typeof metaTagContent === 'string') ? {
866
- name: metaName,
867
- content: metaTagContent
868
- } : metaTagContent;
1144
+ return typeof metaTagContent === "string"
1145
+ ? {
1146
+ name: metaName,
1147
+ content: metaTagContent,
1148
+ }
1149
+ : metaTagContent;
869
1150
  })
870
1151
  .filter((attribute) => attribute !== false);
871
1152
 
@@ -873,13 +1154,13 @@ class HtmlWebpackPlugin {
873
1154
  // the html-webpack-plugin tag structure
874
1155
  return metaTagAttributeObjects.map((metaTagAttributes) => {
875
1156
  if (metaTagAttributes === false) {
876
- throw new Error('Invalid meta tag');
1157
+ throw new Error("Invalid meta tag");
877
1158
  }
878
1159
  return {
879
- tagName: 'meta',
1160
+ tagName: "meta",
880
1161
  voidTag: true,
881
- meta: { plugin: 'html-webpack-plugin' },
882
- attributes: metaTagAttributes
1162
+ meta: { plugin: "html-webpack-plugin" },
1163
+ attributes: metaTagAttributes,
883
1164
  };
884
1165
  });
885
1166
  }
@@ -891,16 +1172,18 @@ class HtmlWebpackPlugin {
891
1172
  * @param {string} favicon
892
1173
  * @returns {Array<HtmlTagObject>}
893
1174
  */
894
- generateFaviconTag (favicon) {
895
- return [{
896
- tagName: 'link',
897
- voidTag: true,
898
- meta: { plugin: 'html-webpack-plugin' },
899
- attributes: {
900
- rel: 'icon',
901
- href: favicon
902
- }
903
- }];
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
+ ];
904
1187
  }
905
1188
 
906
1189
  /**
@@ -917,24 +1200,24 @@ class HtmlWebpackPlugin {
917
1200
  bodyTags: Array<HtmlTagObject>;
918
1201
  }}
919
1202
  */
920
- groupAssetsByElements (assetTags, scriptTarget) {
1203
+ groupAssetsByElements(assetTags, scriptTarget) {
921
1204
  /** @type {{ headTags: Array<HtmlTagObject>; bodyTags: Array<HtmlTagObject>; }} */
922
1205
  const result = {
923
- headTags: [
924
- ...assetTags.meta,
925
- ...assetTags.styles
926
- ],
927
- bodyTags: []
1206
+ headTags: [...assetTags.meta, ...assetTags.styles],
1207
+ bodyTags: [],
928
1208
  };
929
1209
 
930
1210
  // Add script tags to head or body depending on
931
1211
  // the htmlPluginOptions
932
- if (scriptTarget === 'body') {
1212
+ if (scriptTarget === "body") {
933
1213
  result.bodyTags.push(...assetTags.scripts);
934
1214
  } else {
935
1215
  // If script loading is blocking add the scripts to the end of the head
936
1216
  // If script loading is non-blocking add the scripts in front of the css files
937
- 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;
938
1221
 
939
1222
  result.headTags.splice(insertPosition, 0, ...assetTags.scripts);
940
1223
  }
@@ -954,12 +1237,14 @@ class HtmlWebpackPlugin {
954
1237
  * @param {Compilation} compilation
955
1238
  * @returns {{ path: string, info: {} }}
956
1239
  */
957
- replacePlaceholdersInFilename (compiler, filename, fileContent, compilation) {
1240
+ replacePlaceholdersInFilename(compiler, filename, fileContent, compilation) {
958
1241
  if (/\[\\*([\w:]+)\\*\]/i.test(filename) === false) {
959
1242
  return { path: filename, info: {} };
960
1243
  }
961
1244
 
962
- const hash = compiler.webpack.util.createHash(compilation.outputOptions.hashFunction);
1245
+ const hash = compiler.webpack.util.createHash(
1246
+ compilation.outputOptions.hashFunction,
1247
+ );
963
1248
 
964
1249
  hash.update(fileContent);
965
1250
 
@@ -967,18 +1252,20 @@ class HtmlWebpackPlugin {
967
1252
  hash.update(compilation.outputOptions.hashSalt);
968
1253
  }
969
1254
 
970
- 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
+ );
971
1260
 
972
- return compilation.getPathWithInfo(
973
- filename,
974
- {
1261
+ return compilation.getPathWithInfo(filename, {
1262
+ contentHash,
1263
+ chunk: {
1264
+ hash: contentHash,
1265
+ // @ts-ignore
975
1266
  contentHash,
976
- chunk: {
977
- hash: contentHash,
978
- contentHash
979
- }
980
- }
981
- );
1267
+ },
1268
+ });
982
1269
  }
983
1270
 
984
1271
  /**
@@ -993,36 +1280,57 @@ class HtmlWebpackPlugin {
993
1280
  * @param {{ value: string | undefined }} assetJson
994
1281
  * @param {(err?: Error) => void} callback
995
1282
  */
996
- generateHTML (
1283
+ generateHTML(
997
1284
  compiler,
998
1285
  compilation,
999
1286
  outputName,
1000
1287
  childCompilerPlugin,
1001
1288
  previousEmittedAssets,
1002
1289
  assetJson,
1003
- callback
1290
+ callback,
1004
1291
  ) {
1005
1292
  // Get all entry point names for this html file
1006
1293
  const entryNames = Array.from(compilation.entrypoints.keys());
1007
- const filteredEntryNames = this.filterEntryChunks(entryNames, this.options.chunks, this.options.excludeChunks);
1008
- 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
+ );
1009
1304
  const templateResult = this.options.templateContent
1010
1305
  ? { mainCompilationHash: compilation.hash }
1011
1306
  : childCompilerPlugin.getCompilationEntryResult(this.options.template);
1012
1307
 
1013
- if ('error' in templateResult) {
1014
- 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
+ );
1015
1312
  }
1016
1313
 
1017
1314
  // If the child compilation was not executed during a previous main compile run
1018
1315
  // it is a cached result
1019
- const isCompilationCached = templateResult.mainCompilationHash !== compilation.hash;
1316
+ const isCompilationCached =
1317
+ templateResult.mainCompilationHash !== compilation.hash;
1020
1318
  /** Generated file paths from the entry point names */
1021
- const assetsInformationByGroups = this.getAssetsInformationByGroups(compilation, outputName, sortedEntryNames);
1319
+ const assetsInformationByGroups = this.getAssetsInformationByGroups(
1320
+ compilation,
1321
+ outputName,
1322
+ sortedEntryNames,
1323
+ );
1022
1324
  // If the template and the assets did not change we don't have to emit the html
1023
- const newAssetJson = JSON.stringify(this.getAssetFiles(assetsInformationByGroups));
1325
+ const newAssetJson = JSON.stringify(
1326
+ this.getAssetFiles(assetsInformationByGroups),
1327
+ );
1024
1328
 
1025
- if (isCompilationCached && this.options.cache && assetJson.value === newAssetJson) {
1329
+ if (
1330
+ isCompilationCached &&
1331
+ this.options.cache &&
1332
+ assetJson.value === newAssetJson
1333
+ ) {
1026
1334
  previousEmittedAssets.forEach(({ name, source, info }) => {
1027
1335
  compilation.emitAsset(name, source, info);
1028
1336
  });
@@ -1035,127 +1343,204 @@ class HtmlWebpackPlugin {
1035
1343
  // The html-webpack plugin uses a object representation for the html-tags which will be injected
1036
1344
  // to allow altering them more easily
1037
1345
  // Just before they are converted a third-party-plugin author might change the order and content
1038
- const assetsPromise = this.generateFavicon(compiler, this.options.favicon, compilation, assetsInformationByGroups.publicPath, previousEmittedAssets)
1039
- .then((faviconPath) => {
1040
- assetsInformationByGroups.favicon = faviconPath;
1041
- return getHtmlWebpackPluginHooks(compilation).beforeAssetTagGeneration.promise({
1042
- assets: assetsInformationByGroups,
1043
- outputName,
1044
- plugin: this
1045
- });
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,
1046
1360
  });
1361
+ });
1047
1362
 
1048
1363
  // Turn the js and css paths into grouped HtmlTagObjects
1049
1364
  const assetTagGroupsPromise = assetsPromise
1050
1365
  // And allow third-party-plugin authors to reorder and change the assetTags before they are grouped
1051
- .then(({ assets }) => getHtmlWebpackPluginHooks(compilation).alterAssetTags.promise({
1052
- assetTags: {
1053
- scripts: this.generatedScriptTags(assets.js),
1054
- styles: this.generateStyleTags(assets.css),
1055
- meta: [
1056
- ...(this.options.base !== false ? this.generateBaseTag(this.options.base) : []),
1057
- ...this.generatedMetaTags(this.options.meta),
1058
- ...(assets.favicon ? this.generateFaviconTag(assets.favicon) : [])
1059
- ]
1060
- },
1061
- outputName,
1062
- publicPath: assetsInformationByGroups.publicPath,
1063
- plugin: this
1064
- }))
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
+ )
1065
1388
  .then(({ assetTags }) => {
1066
1389
  // Inject scripts to body unless it set explicitly to head
1067
- const scriptTarget = this.options.inject === 'head' ||
1068
- (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";
1069
1396
  // Group assets to `head` and `body` tag arrays
1070
1397
  const assetGroups = this.groupAssetsByElements(assetTags, scriptTarget);
1071
1398
  // Allow third-party-plugin authors to reorder and change the assetTags once they are grouped
1072
- return getHtmlWebpackPluginHooks(compilation).alterAssetTagGroups.promise({
1399
+ return HtmlWebpackPlugin.getCompilationHooks(
1400
+ compilation,
1401
+ ).alterAssetTagGroups.promise({
1073
1402
  headTags: assetGroups.headTags,
1074
1403
  bodyTags: assetGroups.bodyTags,
1075
1404
  outputName,
1076
1405
  publicPath: assetsInformationByGroups.publicPath,
1077
- plugin: this
1406
+ plugin: this,
1078
1407
  });
1079
1408
  });
1080
1409
 
1081
1410
  // Turn the compiled template into a nodejs function or into a nodejs string
1082
- const templateEvaluationPromise = Promise.resolve()
1083
- .then(() => {
1084
- if ('error' in templateResult) {
1085
- return this.options.showErrors ? prettyError(templateResult.error, compiler.context).toHtml() : 'ERROR';
1086
- }
1087
-
1088
- // Allow to use a custom function / string instead
1089
- if (this.options.templateContent !== false) {
1090
- return this.options.templateContent;
1091
- }
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;
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
+ }
1097
1417
 
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
- }
1418
+ // Allow to use a custom function / string instead
1419
+ if (this.options.templateContent !== false) {
1420
+ return this.options.templateContent;
1421
+ }
1102
1422
 
1103
- 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
+ });
1104
1435
  }
1105
1436
 
1106
- return Promise.reject(new Error('Child compilation contained no compiledEntry'));
1107
- });
1108
- 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
+ ])
1109
1453
  // Execute the template
1110
- .then(([assetsHookResult, assetTags, compilationResult]) => typeof compilationResult !== 'function'
1111
- ? compilationResult
1112
- : 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
+ );
1113
1464
 
1114
- const injectedHtmlPromise = Promise.all([assetTagGroupsPromise, templateExectutionPromise])
1465
+ const injectedHtmlPromise = Promise.all([
1466
+ assetTagGroupsPromise,
1467
+ templateExecutionPromise,
1468
+ ])
1115
1469
  // Allow plugins to change the html before assets are injected
1116
1470
  .then(([assetTags, html]) => {
1117
- const pluginArgs = { html, headTags: assetTags.headTags, bodyTags: assetTags.bodyTags, plugin: this, outputName };
1118
- 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);
1119
1481
  })
1120
1482
  .then(({ html, headTags, bodyTags }) => {
1121
- return this.postProcessHtml(compiler, html, assetsInformationByGroups, { headTags, bodyTags });
1483
+ return this.postProcessHtml(compiler, html, assetsInformationByGroups, {
1484
+ headTags,
1485
+ bodyTags,
1486
+ });
1122
1487
  });
1123
1488
 
1124
1489
  const emitHtmlPromise = injectedHtmlPromise
1125
1490
  // Allow plugins to change the html after assets are injected
1126
1491
  .then((html) => {
1127
1492
  const pluginArgs = { html, plugin: this, outputName };
1128
- return getHtmlWebpackPluginHooks(compilation).beforeEmit.promise(pluginArgs)
1129
- .then(result => result.html);
1493
+ return HtmlWebpackPlugin.getCompilationHooks(compilation)
1494
+ .beforeEmit.promise(pluginArgs)
1495
+ .then((result) => result.html);
1130
1496
  })
1131
- .catch(err => {
1497
+ .catch((err) => {
1132
1498
  // In case anything went wrong the promise is resolved
1133
1499
  // with the error message and an error is logged
1134
1500
  compilation.errors.push(prettyError(err, compiler.context).toString());
1135
- return this.options.showErrors ? prettyError(err, compiler.context).toHtml() : 'ERROR';
1501
+ return this.options.showErrors
1502
+ ? prettyError(err, compiler.context).toHtml()
1503
+ : "ERROR";
1136
1504
  })
1137
- .then(html => {
1138
- const filename = outputName.replace(/\[templatehash([^\]]*)\]/g, require('util').deprecate(
1139
- (match, options) => `[contenthash${options}]`,
1140
- '[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,
1141
1518
  );
1142
- const replacedFilename = this.replacePlaceholdersInFilename(compiler, filename, html, compilation);
1143
1519
  const source = new compiler.webpack.sources.RawSource(html, false);
1144
1520
 
1145
1521
  // Add the evaluated html code to the webpack assets
1146
- compilation.emitAsset(replacedFilename.path, source, replacedFilename.info);
1522
+ compilation.emitAsset(
1523
+ replacedFilename.path,
1524
+ source,
1525
+ replacedFilename.info,
1526
+ );
1147
1527
  previousEmittedAssets.push({ name: replacedFilename.path, source });
1148
1528
 
1149
1529
  return replacedFilename.path;
1150
1530
  })
1151
- .then((finalOutputName) => getHtmlWebpackPluginHooks(compilation).afterEmit.promise({
1152
- outputName: finalOutputName,
1153
- plugin: this
1154
- }).catch(err => {
1155
- /** @type {Logger} */
1156
- (this.logger).error(err);
1157
- return null;
1158
- }).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
+ );
1159
1544
 
1160
1545
  // Once all files are added to the webpack compilation
1161
1546
  // let the webpack compiler continue
@@ -1179,15 +1564,15 @@ class HtmlWebpackPlugin {
1179
1564
  * @param {ProcessedHtmlWebpackOptions} options
1180
1565
  * @returns {TemplateParameter}
1181
1566
  */
1182
- function templateParametersGenerator (compilation, assets, assetTags, options) {
1567
+ function templateParametersGenerator(compilation, assets, assetTags, options) {
1183
1568
  return {
1184
1569
  compilation: compilation,
1185
1570
  webpackConfig: compilation.options,
1186
1571
  htmlWebpackPlugin: {
1187
1572
  tags: assetTags,
1188
1573
  files: assets,
1189
- options: options
1190
- }
1574
+ options: options,
1575
+ },
1191
1576
  };
1192
1577
  }
1193
1578
 
@@ -1202,7 +1587,8 @@ HtmlWebpackPlugin.version = 5;
1202
1587
  *
1203
1588
  * Usage: HtmlWebpackPlugin.getHooks(compilation).HOOK_NAME.tapAsync('YourPluginName', () => { ... });
1204
1589
  */
1205
- HtmlWebpackPlugin.getHooks = getHtmlWebpackPluginHooks;
1590
+ // TODO remove me in the next major release in favor getCompilationHooks
1591
+ HtmlWebpackPlugin.getHooks = HtmlWebpackPlugin.getCompilationHooks;
1206
1592
  HtmlWebpackPlugin.createHtmlTagObject = createHtmlTagObject;
1207
1593
 
1208
1594
  module.exports = HtmlWebpackPlugin;