webpack 5.66.0 → 5.69.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.

Potentially problematic release.


This version of webpack might be problematic. Click here for more details.

Files changed (97) hide show
  1. package/README.md +1 -1
  2. package/lib/APIPlugin.js +33 -0
  3. package/lib/Cache.js +1 -1
  4. package/lib/CacheFacade.js +2 -2
  5. package/lib/ChunkGraph.js +1 -2
  6. package/lib/CleanPlugin.js +1 -1
  7. package/lib/Compilation.js +14 -9
  8. package/lib/Compiler.js +57 -3
  9. package/lib/ContextModule.js +21 -17
  10. package/lib/DelegatedModule.js +1 -1
  11. package/lib/DependencyTemplates.js +1 -1
  12. package/lib/DllModule.js +1 -1
  13. package/lib/EvalDevToolModulePlugin.js +16 -1
  14. package/lib/EvalSourceMapDevToolPlugin.js +18 -1
  15. package/lib/ExportsInfo.js +4 -4
  16. package/lib/ExternalModule.js +1 -1
  17. package/lib/ExternalModuleFactoryPlugin.js +1 -1
  18. package/lib/FileSystemInfo.js +29 -25
  19. package/lib/HookWebpackError.js +1 -1
  20. package/lib/Module.js +1 -3
  21. package/lib/MultiCompiler.js +1 -1
  22. package/lib/MultiWatching.js +1 -1
  23. package/lib/NormalModule.js +6 -4
  24. package/lib/NormalModuleFactory.js +25 -27
  25. package/lib/ProgressPlugin.js +1 -1
  26. package/lib/RawModule.js +1 -1
  27. package/lib/RuntimeGlobals.js +18 -0
  28. package/lib/RuntimeModule.js +1 -1
  29. package/lib/RuntimePlugin.js +28 -3
  30. package/lib/RuntimeTemplate.js +1 -1
  31. package/lib/TemplatedPathPlugin.js +48 -23
  32. package/lib/Watching.js +1 -1
  33. package/lib/WebpackOptionsApply.js +1 -1
  34. package/lib/asset/AssetGenerator.js +65 -26
  35. package/lib/asset/AssetModulesPlugin.js +3 -0
  36. package/lib/asset/RawDataUrlModule.js +8 -5
  37. package/lib/async-modules/AwaitDependenciesInitFragment.js +4 -4
  38. package/lib/buildChunkGraph.js +1 -1
  39. package/lib/cache/ResolverCachePlugin.js +1 -1
  40. package/lib/cli.js +44 -3
  41. package/lib/config/defaults.js +30 -7
  42. package/lib/config/normalization.js +5 -0
  43. package/lib/container/ContainerEntryModule.js +4 -2
  44. package/lib/container/FallbackModule.js +4 -4
  45. package/lib/container/RemoteModule.js +4 -2
  46. package/lib/css/CssExportsGenerator.js +139 -0
  47. package/lib/css/CssGenerator.js +3 -0
  48. package/lib/css/CssLoadingRuntimeModule.js +201 -154
  49. package/lib/css/CssModulesPlugin.js +22 -4
  50. package/lib/debug/ProfilingPlugin.js +15 -14
  51. package/lib/dependencies/ContextElementDependency.js +8 -2
  52. package/lib/dependencies/CreateScriptUrlDependency.js +12 -0
  53. package/lib/dependencies/ExportsInfoDependency.js +6 -0
  54. package/lib/dependencies/HarmonyCompatibilityDependency.js +5 -5
  55. package/lib/dependencies/ImportMetaPlugin.js +22 -3
  56. package/lib/dependencies/LoaderPlugin.js +2 -2
  57. package/lib/hmr/LazyCompilationPlugin.js +45 -21
  58. package/lib/hmr/lazyCompilationBackend.js +1 -1
  59. package/lib/ids/DeterministicModuleIdsPlugin.js +55 -35
  60. package/lib/ids/HashedModuleIdsPlugin.js +9 -12
  61. package/lib/ids/IdHelpers.js +24 -10
  62. package/lib/ids/NamedModuleIdsPlugin.js +6 -9
  63. package/lib/ids/NaturalModuleIdsPlugin.js +10 -13
  64. package/lib/ids/OccurrenceModuleIdsPlugin.js +13 -10
  65. package/lib/ids/SyncModuleIdsPlugin.js +140 -0
  66. package/lib/index.js +10 -0
  67. package/lib/javascript/JavascriptModulesPlugin.js +27 -2
  68. package/lib/javascript/StartupHelpers.js +3 -2
  69. package/lib/library/AssignLibraryPlugin.js +8 -2
  70. package/lib/node/NodeTargetPlugin.js +1 -0
  71. package/lib/optimize/ConcatenatedModule.js +11 -5
  72. package/lib/runtime/AsyncModuleRuntimeModule.js +25 -15
  73. package/lib/runtime/CreateScriptRuntimeModule.js +36 -0
  74. package/lib/runtime/CreateScriptUrlRuntimeModule.js +9 -34
  75. package/lib/runtime/GetTrustedTypesPolicyRuntimeModule.js +76 -0
  76. package/lib/schemes/HttpUriPlugin.js +32 -11
  77. package/lib/serialization/FileMiddleware.js +44 -9
  78. package/lib/sharing/ConsumeSharedModule.js +4 -2
  79. package/lib/sharing/ProvideSharedModule.js +4 -2
  80. package/lib/sharing/utils.js +1 -1
  81. package/lib/stats/DefaultStatsFactoryPlugin.js +112 -67
  82. package/lib/stats/DefaultStatsPrinterPlugin.js +88 -23
  83. package/lib/util/ArrayHelpers.js +18 -4
  84. package/lib/util/AsyncQueue.js +1 -1
  85. package/lib/util/compileBooleanMatcher.js +1 -1
  86. package/lib/util/deterministicGrouping.js +1 -1
  87. package/lib/util/identifier.js +65 -44
  88. package/lib/util/nonNumericOnlyHash.js +22 -0
  89. package/lib/util/semver.js +17 -10
  90. package/lib/wasm-async/AsyncWebAssemblyJavascriptGenerator.js +9 -3
  91. package/lib/webworker/ImportScriptsChunkLoadingPlugin.js +3 -11
  92. package/package.json +14 -21
  93. package/schemas/WebpackOptions.check.js +1 -1
  94. package/schemas/WebpackOptions.json +47 -6
  95. package/schemas/plugins/asset/AssetGeneratorOptions.check.js +1 -1
  96. package/schemas/plugins/asset/AssetResourceGeneratorOptions.check.js +1 -1
  97. package/types.d.ts +207 -60
@@ -10,7 +10,7 @@ const HelperRuntimeModule = require("./HelperRuntimeModule");
10
10
 
11
11
  class CreateScriptUrlRuntimeModule extends HelperRuntimeModule {
12
12
  constructor() {
13
- super("trusted types");
13
+ super("trusted types script url");
14
14
  }
15
15
 
16
16
  /**
@@ -22,39 +22,14 @@ class CreateScriptUrlRuntimeModule extends HelperRuntimeModule {
22
22
  const { trustedTypes } = outputOptions;
23
23
  const fn = RuntimeGlobals.createScriptUrl;
24
24
 
25
- if (!trustedTypes) {
26
- // Skip Trusted Types logic.
27
- return Template.asString([
28
- `${fn} = ${runtimeTemplate.returningFunction("url", "url")};`
29
- ]);
30
- }
31
-
32
- return Template.asString([
33
- "var policy;",
34
- `${fn} = ${runtimeTemplate.basicFunction("url", [
35
- "// Create Trusted Type policy if Trusted Types are available and the policy doesn't exist yet.",
36
- "if (policy === undefined) {",
37
- Template.indent([
38
- "policy = {",
39
- Template.indent([
40
- `createScriptURL: ${runtimeTemplate.returningFunction(
41
- "url",
42
- "url"
43
- )}`
44
- ]),
45
- "};",
46
- 'if (typeof trustedTypes !== "undefined" && trustedTypes.createPolicy) {',
47
- Template.indent([
48
- `policy = trustedTypes.createPolicy(${JSON.stringify(
49
- trustedTypes.policyName
50
- )}, policy);`
51
- ]),
52
- "}"
53
- ]),
54
- "}",
55
- "return policy.createScriptURL(url);"
56
- ])};`
57
- ]);
25
+ return Template.asString(
26
+ `${fn} = ${runtimeTemplate.returningFunction(
27
+ trustedTypes
28
+ ? `${RuntimeGlobals.getTrustedTypesPolicy}().createScriptURL(url)`
29
+ : "url",
30
+ "url"
31
+ )};`
32
+ );
58
33
  }
59
34
  }
60
35
 
@@ -0,0 +1,76 @@
1
+ /*
2
+ MIT License http://www.opensource.org/licenses/mit-license.php
3
+ */
4
+
5
+ "use strict";
6
+
7
+ const RuntimeGlobals = require("../RuntimeGlobals");
8
+ const Template = require("../Template");
9
+ const HelperRuntimeModule = require("./HelperRuntimeModule");
10
+
11
+ class GetTrustedTypesPolicyRuntimeModule extends HelperRuntimeModule {
12
+ /**
13
+ * @param {Set<string>} runtimeRequirements runtime requirements
14
+ */
15
+ constructor(runtimeRequirements) {
16
+ super("trusted types policy");
17
+ this.runtimeRequirements = runtimeRequirements;
18
+ }
19
+
20
+ /**
21
+ * @returns {string} runtime code
22
+ */
23
+ generate() {
24
+ const { compilation } = this;
25
+ const { runtimeTemplate, outputOptions } = compilation;
26
+ const { trustedTypes } = outputOptions;
27
+ const fn = RuntimeGlobals.getTrustedTypesPolicy;
28
+
29
+ return Template.asString([
30
+ "var policy;",
31
+ `${fn} = ${runtimeTemplate.basicFunction("", [
32
+ "// Create Trusted Type policy if Trusted Types are available and the policy doesn't exist yet.",
33
+ "if (policy === undefined) {",
34
+ Template.indent([
35
+ "policy = {",
36
+ Template.indent(
37
+ [
38
+ ...(this.runtimeRequirements.has(RuntimeGlobals.createScript)
39
+ ? [
40
+ `createScript: ${runtimeTemplate.returningFunction(
41
+ "script",
42
+ "script"
43
+ )}`
44
+ ]
45
+ : []),
46
+ ...(this.runtimeRequirements.has(RuntimeGlobals.createScriptUrl)
47
+ ? [
48
+ `createScriptURL: ${runtimeTemplate.returningFunction(
49
+ "url",
50
+ "url"
51
+ )}`
52
+ ]
53
+ : [])
54
+ ].join(",\n")
55
+ ),
56
+ "};",
57
+ ...(trustedTypes
58
+ ? [
59
+ 'if (typeof trustedTypes !== "undefined" && trustedTypes.createPolicy) {',
60
+ Template.indent([
61
+ `policy = trustedTypes.createPolicy(${JSON.stringify(
62
+ trustedTypes.policyName
63
+ )}, policy);`
64
+ ]),
65
+ "}"
66
+ ]
67
+ : [])
68
+ ]),
69
+ "}",
70
+ "return policy;"
71
+ ])};`
72
+ ]);
73
+ }
74
+ }
75
+
76
+ module.exports = GetTrustedTypesPolicyRuntimeModule;
@@ -166,7 +166,7 @@ class Lockfile {
166
166
  /**
167
167
  * @template R
168
168
  * @param {function(function(Error=, R=): void): void} fn function
169
- * @returns {function(function(Error=, R=): void): void} cached function
169
+ * @returns {function(function((Error | null)=, R=): void): void} cached function
170
170
  */
171
171
  const cachedWithoutKey = fn => {
172
172
  let inFlight = false;
@@ -201,10 +201,10 @@ const cachedWithoutKey = fn => {
201
201
  * @template R
202
202
  * @param {function(T, function(Error=, R=): void): void} fn function
203
203
  * @param {function(T, function(Error=, R=): void): void=} forceFn function for the second try
204
- * @returns {(function(T, function(Error=, R=): void): void) & { force: function(T, function(Error=, R=): void): void }} cached function
204
+ * @returns {(function(T, function((Error | null)=, R=): void): void) & { force: function(T, function((Error | null)=, R=): void): void }} cached function
205
205
  */
206
206
  const cachedWithKey = (fn, forceFn = fn) => {
207
- /** @typedef {{ result?: R, error?: Error, callbacks?: (function(Error=, R=): void)[], force?: true }} CacheEntry */
207
+ /** @typedef {{ result?: R, error?: Error, callbacks?: (function((Error | null)=, R=): void)[], force?: true }} CacheEntry */
208
208
  /** @type {Map<T, CacheEntry>} */
209
209
  const cache = new Map();
210
210
  const resultFn = (arg, callback) => {
@@ -358,7 +358,7 @@ class HttpUriPlugin {
358
358
 
359
359
  const getLockfile = cachedWithoutKey(
360
360
  /**
361
- * @param {function(Error=, Lockfile=): void} callback callback
361
+ * @param {function((Error | null)=, Lockfile=): void} callback callback
362
362
  * @returns {void}
363
363
  */
364
364
  callback => {
@@ -465,7 +465,7 @@ class HttpUriPlugin {
465
465
  *
466
466
  * @param {string} url URL
467
467
  * @param {string} integrity integrity
468
- * @param {function(Error=, { entry: LockfileEntry, content: Buffer, storeLock: boolean }=): void} callback callback
468
+ * @param {function((Error | null)=, { entry: LockfileEntry, content: Buffer, storeLock: boolean }=): void} callback callback
469
469
  */
470
470
  const resolveContent = (url, integrity, callback) => {
471
471
  const handleResult = (err, result) => {
@@ -509,8 +509,8 @@ class HttpUriPlugin {
509
509
 
510
510
  /**
511
511
  * @param {string} url URL
512
- * @param {FetchResult} cachedResult result from cache
513
- * @param {function(Error=, FetchResult=): void} callback callback
512
+ * @param {FetchResult | RedirectFetchResult} cachedResult result from cache
513
+ * @param {function((Error | null)=, FetchResult=): void} callback callback
514
514
  * @returns {void}
515
515
  */
516
516
  const fetchContentRaw = (url, cachedResult, callback) => {
@@ -603,9 +603,30 @@ class HttpUriPlugin {
603
603
  res.statusCode >= 301 &&
604
604
  res.statusCode <= 308
605
605
  ) {
606
- return finishWith({
606
+ const result = {
607
607
  location: new URL(location, url).href
608
- });
608
+ };
609
+ if (
610
+ !cachedResult ||
611
+ !("location" in cachedResult) ||
612
+ cachedResult.location !== result.location ||
613
+ cachedResult.validUntil < validUntil ||
614
+ cachedResult.storeLock !== storeLock ||
615
+ cachedResult.storeCache !== storeCache ||
616
+ cachedResult.etag !== etag
617
+ ) {
618
+ return finishWith(result);
619
+ } else {
620
+ logger.debug(`GET ${url} [${res.statusCode}] (unchanged)`);
621
+ return callback(null, {
622
+ ...result,
623
+ fresh: true,
624
+ storeLock,
625
+ storeCache,
626
+ validUntil,
627
+ etag
628
+ });
629
+ }
609
630
  }
610
631
  const contentType = res.headers["content-type"] || "";
611
632
  const bufferArr = [];
@@ -662,7 +683,7 @@ class HttpUriPlugin {
662
683
  const fetchContent = cachedWithKey(
663
684
  /**
664
685
  * @param {string} url URL
665
- * @param {function(Error=, { validUntil: number, etag?: string, entry: LockfileEntry, content: Buffer, fresh: boolean } | { validUntil: number, etag?: string, location: string, fresh: boolean }=): void} callback callback
686
+ * @param {function((Error | null)=, { validUntil: number, etag?: string, entry: LockfileEntry, content: Buffer, fresh: boolean } | { validUntil: number, etag?: string, location: string, fresh: boolean }=): void} callback callback
666
687
  * @returns {void}
667
688
  */ (url, callback) => {
668
689
  cache.get(url, null, (err, cachedResult) => {
@@ -693,7 +714,7 @@ class HttpUriPlugin {
693
714
  const getInfo = cachedWithKey(
694
715
  /**
695
716
  * @param {string} url the url
696
- * @param {function(Error=, { entry: LockfileEntry, content: Buffer }=): void} callback callback
717
+ * @param {function((Error | null)=, { entry: LockfileEntry, content: Buffer }=): void} callback callback
697
718
  * @returns {void}
698
719
  */
699
720
  (url, callback) => {
@@ -40,6 +40,8 @@ Section -> Buffer
40
40
 
41
41
  // "wpc" + 1 in little-endian
42
42
  const VERSION = 0x01637077;
43
+ const WRITE_LIMIT_TOTAL = 0x7fff0000;
44
+ const WRITE_LIMIT_CHUNK = 511 * 1024 * 1024;
43
45
 
44
46
  /**
45
47
  * @param {Buffer[]} buffers buffers
@@ -87,7 +89,7 @@ const readUInt64LE = Buffer.prototype.readBigUInt64LE
87
89
  * @param {FileMiddleware} middleware this
88
90
  * @param {BufferSerializableType[] | Promise<BufferSerializableType[]>} data data to be serialized
89
91
  * @param {string | boolean} name file base name
90
- * @param {function(string | false, Buffer[]): Promise<void>} writeFile writes a file
92
+ * @param {function(string | false, Buffer[], number): Promise<void>} writeFile writes a file
91
93
  * @param {string | Hash} hashFunction hash function to use
92
94
  * @returns {Promise<SerializeResult>} resulting file pointer and promise
93
95
  */
@@ -212,9 +214,9 @@ const serialize = async (
212
214
  if (name === true) {
213
215
  name = hashForName(buf, hashFunction);
214
216
  }
215
- backgroundJobs.push(writeFile(name, buf));
216
217
  let size = 0;
217
218
  for (const b of buf) size += b.length;
219
+ backgroundJobs.push(writeFile(name, buf, size));
218
220
  return {
219
221
  size,
220
222
  name,
@@ -422,7 +424,7 @@ class FileMiddleware extends SerializerMiddleware {
422
424
  // It's important that we don't touch existing files during serialization
423
425
  // because serialize may read existing files (when deserializing)
424
426
  const allWrittenFiles = new Set();
425
- const writeFile = async (name, content) => {
427
+ const writeFile = async (name, content, size) => {
426
428
  const file = name
427
429
  ? join(this.fs, filename, `../${name}${extension}`)
428
430
  : filename;
@@ -441,10 +443,7 @@ class FileMiddleware extends SerializerMiddleware {
441
443
  [zConstants.BROTLI_PARAM_MODE]: zConstants.BROTLI_MODE_TEXT,
442
444
  [zConstants.BROTLI_PARAM_QUALITY]: 2,
443
445
  [zConstants.BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING]: true,
444
- [zConstants.BROTLI_PARAM_SIZE_HINT]: content.reduce(
445
- (size, b) => size + b.length,
446
- 0
447
- )
446
+ [zConstants.BROTLI_PARAM_SIZE_HINT]: size
448
447
  }
449
448
  });
450
449
  }
@@ -456,8 +455,44 @@ class FileMiddleware extends SerializerMiddleware {
456
455
  stream.on("error", err => reject(err));
457
456
  stream.on("finish", () => resolve());
458
457
  }
459
- for (const b of content) stream.write(b);
460
- stream.end();
458
+ // split into chunks for WRITE_LIMIT_CHUNK size
459
+ const chunks = [];
460
+ for (const b of content) {
461
+ if (b.length < WRITE_LIMIT_CHUNK) {
462
+ chunks.push(b);
463
+ } else {
464
+ for (let i = 0; i < b.length; i += WRITE_LIMIT_CHUNK) {
465
+ chunks.push(b.slice(i, i + WRITE_LIMIT_CHUNK));
466
+ }
467
+ }
468
+ }
469
+
470
+ const len = chunks.length;
471
+ let i = 0;
472
+ const batchWrite = err => {
473
+ // will be handled in "on" error handler
474
+ if (err) return;
475
+
476
+ if (i === len) {
477
+ stream.end();
478
+ return;
479
+ }
480
+
481
+ // queue up a batch of chunks up to the write limit
482
+ // end is exclusive
483
+ let end = i;
484
+ let sum = chunks[end++].length;
485
+ while (end < len) {
486
+ sum += chunks[end].length;
487
+ if (sum > WRITE_LIMIT_TOTAL) break;
488
+ end++;
489
+ }
490
+ while (i < end - 1) {
491
+ stream.write(chunks[i++]);
492
+ }
493
+ stream.write(chunks[i++], batchWrite);
494
+ };
495
+ batchWrite();
461
496
  });
462
497
  if (name) allWrittenFiles.add(file);
463
498
  };
@@ -101,14 +101,16 @@ class ConsumeSharedModule extends Module {
101
101
  */
102
102
  libIdent(options) {
103
103
  const { shareKey, shareScope, import: request } = this.options;
104
- return `webpack/sharing/consume/${shareScope}/${shareKey}${
104
+ return `${
105
+ this.layer ? `(${this.layer})/` : ""
106
+ }webpack/sharing/consume/${shareScope}/${shareKey}${
105
107
  request ? `/${request}` : ""
106
108
  }`;
107
109
  }
108
110
 
109
111
  /**
110
112
  * @param {NeedBuildContext} context context info
111
- * @param {function(WebpackError=, boolean=): void} callback callback function, returns true, if the module needs a rebuild
113
+ * @param {function((WebpackError | null)=, boolean=): void} callback callback function, returns true, if the module needs a rebuild
112
114
  * @returns {void}
113
115
  */
114
116
  needBuild(context, callback) {
@@ -67,12 +67,14 @@ class ProvideSharedModule extends Module {
67
67
  * @returns {string | null} an identifier for library inclusion
68
68
  */
69
69
  libIdent(options) {
70
- return `webpack/sharing/provide/${this._shareScope}/${this._name}`;
70
+ return `${this.layer ? `(${this.layer})/` : ""}webpack/sharing/provide/${
71
+ this._shareScope
72
+ }/${this._name}`;
71
73
  }
72
74
 
73
75
  /**
74
76
  * @param {NeedBuildContext} context context info
75
- * @param {function(WebpackError=, boolean=): void} callback callback function, returns true, if the module needs a rebuild
77
+ * @param {function((WebpackError | null)=, boolean=): void} callback callback function, returns true, if the module needs a rebuild
76
78
  * @returns {void}
77
79
  */
78
80
  needBuild(context, callback) {
@@ -22,7 +22,7 @@ exports.isRequiredVersion = str => {
22
22
  * @param {InputFileSystem} fs file system
23
23
  * @param {string} directory directory to start looking into
24
24
  * @param {string[]} descriptionFiles possible description filenames
25
- * @param {function(Error=, {data: object, path: string}=): void} callback callback
25
+ * @param {function((Error | null)=, {data: object, path: string}=): void} callback callback
26
26
  */
27
27
  const getDescriptionFile = (fs, directory, descriptionFiles, callback) => {
28
28
  let i = 0;
@@ -1658,84 +1658,121 @@ const collapse = children => {
1658
1658
  return newChildren;
1659
1659
  };
1660
1660
 
1661
- const spaceLimited = (itemsAndGroups, max) => {
1661
+ const spaceLimited = (
1662
+ itemsAndGroups,
1663
+ max,
1664
+ filteredChildrenLineReserved = false
1665
+ ) => {
1666
+ if (max < 1) {
1667
+ return {
1668
+ children: undefined,
1669
+ filteredChildren: getTotalItems(itemsAndGroups)
1670
+ };
1671
+ }
1662
1672
  /** @type {any[] | undefined} */
1663
1673
  let children = undefined;
1664
1674
  /** @type {number | undefined} */
1665
1675
  let filteredChildren = undefined;
1666
1676
  // This are the groups, which take 1+ lines each
1667
- const groups = itemsAndGroups.filter(c => c.children || c.filteredChildren);
1677
+ const groups = [];
1668
1678
  // The sizes of the groups are stored in groupSizes
1669
- const groupSizes = groups.map(g => getItemSize(g));
1679
+ const groupSizes = [];
1670
1680
  // This are the items, which take 1 line each
1671
- const items = itemsAndGroups.filter(c => !c.children && !c.filteredChildren);
1681
+ const items = [];
1672
1682
  // The total of group sizes
1673
- let groupsSize = groupSizes.reduce((a, b) => a + b, 0);
1683
+ let groupsSize = 0;
1684
+
1685
+ for (const itemOrGroup of itemsAndGroups) {
1686
+ // is item
1687
+ if (!itemOrGroup.children && !itemOrGroup.filteredChildren) {
1688
+ items.push(itemOrGroup);
1689
+ } else {
1690
+ groups.push(itemOrGroup);
1691
+ const size = getItemSize(itemOrGroup);
1692
+ groupSizes.push(size);
1693
+ groupsSize += size;
1694
+ }
1695
+ }
1696
+
1674
1697
  if (groupsSize + items.length <= max) {
1675
1698
  // The total size in the current state fits into the max
1676
1699
  // keep all
1677
- children = groups.concat(items);
1678
- } else if (
1679
- groups.length > 0 &&
1680
- groups.length + Math.min(1, items.length) < max
1681
- ) {
1682
- // If each group would take 1 line the total would be below the maximum
1683
- // collapse some groups, keep items
1684
- while (groupsSize + items.length + (filteredChildren ? 1 : 0) > max) {
1700
+ children = groups.length > 0 ? groups.concat(items) : items;
1701
+ } else if (groups.length === 0) {
1702
+ // slice items to max
1703
+ // inner space marks that lines for filteredChildren already reserved
1704
+ const limit = max - (filteredChildrenLineReserved ? 0 : 1);
1705
+ filteredChildren = items.length - limit;
1706
+ items.length = limit;
1707
+ children = items;
1708
+ } else {
1709
+ // limit is the size when all groups are collapsed
1710
+ const limit =
1711
+ groups.length +
1712
+ (filteredChildrenLineReserved || items.length === 0 ? 0 : 1);
1713
+ if (limit < max) {
1685
1714
  // calculate how much we are over the size limit
1686
1715
  // this allows to approach the limit faster
1687
- // it's always > 1
1688
- const oversize =
1689
- items.length + groupsSize + (filteredChildren ? 1 : 0) - max;
1690
- // Find the maximum group and process only this one
1691
- const maxGroupSize = Math.max(...groupSizes);
1692
- if (maxGroupSize < items.length) {
1693
- filteredChildren = items.length;
1694
- items.length = 0;
1695
- continue;
1696
- }
1697
- for (let i = 0; i < groups.length; i++) {
1698
- if (groupSizes[i] === maxGroupSize) {
1699
- const group = groups[i];
1700
- // run this algorithm recursively and limit the size of the children to
1701
- // current size - oversize / number of groups
1702
- // So it should always end up being smaller
1703
- const headerSize = !group.children
1704
- ? 0
1705
- : group.filteredChildren
1706
- ? 2
1707
- : 1;
1708
- const limited = spaceLimited(
1709
- group.children,
1710
- groupSizes[i] - headerSize - oversize / groups.length
1711
- );
1712
- groups[i] = {
1713
- ...group,
1714
- children: limited.children,
1715
- filteredChildren:
1716
- (group.filteredChildren || 0) + limited.filteredChildren
1717
- };
1718
- const newSize = getItemSize(groups[i]);
1719
- groupsSize -= groupSizes[i] - newSize;
1720
- groupSizes[i] = newSize;
1721
- break;
1716
+ let oversize;
1717
+ // If each group would take 1 line the total would be below the maximum
1718
+ // collapse some groups, keep items
1719
+ while (
1720
+ (oversize =
1721
+ groupsSize +
1722
+ items.length +
1723
+ (filteredChildren && !filteredChildrenLineReserved ? 1 : 0) -
1724
+ max) > 0
1725
+ ) {
1726
+ // Find the maximum group and process only this one
1727
+ const maxGroupSize = Math.max(...groupSizes);
1728
+ if (maxGroupSize < items.length) {
1729
+ filteredChildren = items.length;
1730
+ items.length = 0;
1731
+ continue;
1732
+ }
1733
+ for (let i = 0; i < groups.length; i++) {
1734
+ if (groupSizes[i] === maxGroupSize) {
1735
+ const group = groups[i];
1736
+ // run this algorithm recursively and limit the size of the children to
1737
+ // current size - oversize / number of groups
1738
+ // So it should always end up being smaller
1739
+ const headerSize = group.filteredChildren ? 2 : 1;
1740
+ const limited = spaceLimited(
1741
+ group.children,
1742
+ maxGroupSize -
1743
+ // we should use ceil to always feet in max
1744
+ Math.ceil(oversize / groups.length) -
1745
+ // we substitute size of group head
1746
+ headerSize,
1747
+ headerSize === 2
1748
+ );
1749
+ groups[i] = {
1750
+ ...group,
1751
+ children: limited.children,
1752
+ filteredChildren: limited.filteredChildren
1753
+ ? (group.filteredChildren || 0) + limited.filteredChildren
1754
+ : group.filteredChildren
1755
+ };
1756
+ const newSize = getItemSize(groups[i]);
1757
+ groupsSize -= maxGroupSize - newSize;
1758
+ groupSizes[i] = newSize;
1759
+ break;
1760
+ }
1722
1761
  }
1723
1762
  }
1763
+ children = groups.concat(items);
1764
+ } else if (limit === max) {
1765
+ // If we have only enough space to show one line per group and one line for the filtered items
1766
+ // collapse all groups and items
1767
+ children = collapse(groups);
1768
+ filteredChildren = items.length;
1769
+ } else {
1770
+ // If we have no space
1771
+ // collapse complete group
1772
+ filteredChildren = getTotalItems(itemsAndGroups);
1724
1773
  }
1725
- children = groups.concat(items);
1726
- } else if (
1727
- groups.length > 0 &&
1728
- groups.length + Math.min(1, items.length) <= max
1729
- ) {
1730
- // If we have only enough space to show one line per group and one line for the filtered items
1731
- // collapse all groups and items
1732
- children = groups.length ? collapse(groups) : undefined;
1733
- filteredChildren = items.length;
1734
- } else {
1735
- // If we have no space
1736
- // collapse complete group
1737
- filteredChildren = getTotalItems(itemsAndGroups);
1738
1774
  }
1775
+
1739
1776
  return {
1740
1777
  children,
1741
1778
  filteredChildren
@@ -1777,6 +1814,9 @@ const reasonGroup = (children, reasons) => {
1777
1814
  };
1778
1815
  };
1779
1816
 
1817
+ const GROUP_EXTENSION_REGEXP = /(\.[^.]+?)(?:\?|(?: \+ \d+ modules?)?$)/;
1818
+ const GROUP_PATH_REGEXP = /(.+)[/\\][^/\\]+?(?:\?|(?: \+ \d+ modules?)?$)/;
1819
+
1780
1820
  /** @type {Record<string, (groupConfigs: GroupConfig[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void>} */
1781
1821
  const ASSETS_GROUPERS = {
1782
1822
  _: (groupConfigs, context, options) => {
@@ -1825,10 +1865,10 @@ const ASSETS_GROUPERS = {
1825
1865
  groupConfigs.push({
1826
1866
  getKeys: asset => {
1827
1867
  const extensionMatch =
1828
- groupAssetsByExtension && /(\.[^.]+)(?:\?.*|$)/.exec(asset.name);
1868
+ groupAssetsByExtension && GROUP_EXTENSION_REGEXP.exec(asset.name);
1829
1869
  const extension = extensionMatch ? extensionMatch[1] : "";
1830
1870
  const pathMatch =
1831
- groupAssetsByPath && /(.+)[/\\][^/\\]+(?:\?.*|$)/.exec(asset.name);
1871
+ groupAssetsByPath && GROUP_PATH_REGEXP.exec(asset.name);
1832
1872
  const path = pathMatch ? pathMatch[1].split(/[/\\]/) : [];
1833
1873
  const keys = [];
1834
1874
  if (groupAssetsByPath) {
@@ -2022,11 +2062,13 @@ const MODULES_GROUPERS = type => ({
2022
2062
  getKeys: module => {
2023
2063
  if (!module.name) return;
2024
2064
  const resource = parseResource(module.name.split("!").pop()).path;
2065
+ const dataUrl = /^data:[^,;]+/.exec(resource);
2066
+ if (dataUrl) return [dataUrl[0]];
2025
2067
  const extensionMatch =
2026
- groupModulesByExtension && /(\.[^.]+)(?:\?.*|$)/.exec(resource);
2068
+ groupModulesByExtension && GROUP_EXTENSION_REGEXP.exec(resource);
2027
2069
  const extension = extensionMatch ? extensionMatch[1] : "";
2028
2070
  const pathMatch =
2029
- groupModulesByPath && /(.+)[/\\][^/\\]+(?:\?.*|$)/.exec(resource);
2071
+ groupModulesByPath && GROUP_PATH_REGEXP.exec(resource);
2030
2072
  const path = pathMatch ? pathMatch[1].split(/[/\\]/) : [];
2031
2073
  const keys = [];
2032
2074
  if (groupModulesByPath) {
@@ -2046,11 +2088,14 @@ const MODULES_GROUPERS = type => ({
2046
2088
  return keys;
2047
2089
  },
2048
2090
  createGroup: (key, children, modules) => {
2091
+ const isDataUrl = key.startsWith("data:");
2049
2092
  return {
2050
- type: groupModulesByPath
2093
+ type: isDataUrl
2094
+ ? "modules by mime type"
2095
+ : groupModulesByPath
2051
2096
  ? "modules by path"
2052
2097
  : "modules by extension",
2053
- name: key,
2098
+ name: isDataUrl ? key.slice(/* 'data:'.length */ 5) : key,
2054
2099
  children,
2055
2100
  ...moduleGroup(children, modules)
2056
2101
  };