@depup/webpack 5.109.0-depup.0 → 5.109.2-depup.0

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.
Files changed (62) hide show
  1. package/README.md +4 -4
  2. package/bin/webpack.js +12 -0
  3. package/changes.json +4 -4
  4. package/lib/ChunkGraph.js +17 -15
  5. package/lib/CleanPlugin.js +11 -9
  6. package/lib/CompatibilityPlugin.js +31 -0
  7. package/lib/Compilation.js +21 -5
  8. package/lib/Compiler.js +16 -4
  9. package/lib/DefinePlugin.js +47 -20
  10. package/lib/ExportsInfo.js +22 -5
  11. package/lib/ExternalModule.js +10 -7
  12. package/lib/FileSystemInfo.js +126 -26
  13. package/lib/FlagDependencyUsagePlugin.js +33 -12
  14. package/lib/InitFragment.js +20 -32
  15. package/lib/ModuleFilenameHelpers.js +13 -2
  16. package/lib/NormalModule.js +80 -71
  17. package/lib/NormalModuleFactory.js +8 -2
  18. package/lib/RuntimePlugin.js +40 -113
  19. package/lib/Template.js +23 -3
  20. package/lib/cache/PackFileCacheStrategy.js +259 -5
  21. package/lib/config/defaults.js +21 -2
  22. package/lib/container/HoistContainerReferencesPlugin.js +47 -55
  23. package/lib/container/ModuleFederationPlugin.js +15 -9
  24. package/lib/css/CssGenerator.js +8 -2
  25. package/lib/css/CssLoadingRuntimeModule.js +25 -12
  26. package/lib/css/CssModulesPlugin.js +29 -18
  27. package/lib/css/CssParser.js +135 -50
  28. package/lib/css/syntax.js +862 -765
  29. package/lib/dependencies/CommonJsExportRequireDependency.js +19 -0
  30. package/lib/dependencies/CommonJsFullRequireDependency.js +33 -4
  31. package/lib/dependencies/CommonJsImportsParserPlugin.js +2 -0
  32. package/lib/dependencies/HarmonyEvaluatedImportSpecifierDependency.js +2 -1
  33. package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +17 -9
  34. package/lib/dependencies/HarmonyImportDependency.js +1 -1
  35. package/lib/dependencies/HarmonyImportGuard.js +2 -1
  36. package/lib/dependencies/HarmonyImportSpecifierDependency.js +10 -7
  37. package/lib/esm/ModuleChunkLoadingRuntimeModule.js +15 -9
  38. package/lib/hmr/lazyCompilationBackend.js +19 -4
  39. package/lib/html/HtmlGenerator.js +23 -3
  40. package/lib/html/HtmlModulesPlugin.js +30 -12
  41. package/lib/html/syntax.js +2485 -2399
  42. package/lib/ids/IdHelpers.js +24 -10
  43. package/lib/javascript/JavascriptModulesPlugin.js +83 -49
  44. package/lib/javascript/JavascriptParser.js +49 -13
  45. package/lib/javascript/syntax.js +700 -43
  46. package/lib/node/ReadFileCompileAsyncWasmPlugin.js +10 -2
  47. package/lib/node/ReadFileCompileWasmPlugin.js +10 -2
  48. package/lib/optimize/AggressiveMergingPlugin.js +19 -15
  49. package/lib/optimize/ConcatenatedModule.js +19 -15
  50. package/lib/optimize/ModuleConcatenationPlugin.js +73 -24
  51. package/lib/optimize/RealContentHashPlugin.js +10 -7
  52. package/lib/optimize/SplitChunksPlugin.js +146 -44
  53. package/lib/prefetch/ResourceHintPlugin.js +96 -72
  54. package/lib/serialization/BinaryMiddleware.js +270 -938
  55. package/lib/serialization/FileMiddleware.js +299 -60
  56. package/lib/stats/DefaultStatsFactoryPlugin.js +204 -198
  57. package/lib/stats/DefaultStatsPrinterPlugin.js +24 -166
  58. package/lib/stats/StatsFactory.js +31 -9
  59. package/lib/util/identifier.js +21 -1
  60. package/package.json +10 -10
  61. package/schemas/WebpackOptions.json +110 -55
  62. package/types.d.ts +832 -247
@@ -52,7 +52,7 @@ const {
52
52
  ABSOLUTE_PATH_REGEXP,
53
53
  absolutify,
54
54
  contextify,
55
- makePathsRelative
55
+ contextifySourceUrl
56
56
  } = require("./util/identifier");
57
57
  const makeSerializable = require("./util/makeSerializable");
58
58
  const memoize = require("./util/memoize");
@@ -391,21 +391,6 @@ const walkSideEffects = (rootMod, moduleGraph, SideEffectDep) => {
391
391
  * @property {string | null=} type
392
392
  */
393
393
 
394
- /**
395
- * @param {string} context absolute context path
396
- * @param {string} source a source path
397
- * @param {AssociatedObjectForCache=} associatedObjectForCache an object to which the cache will be attached
398
- * @returns {string} new source path
399
- */
400
- const contextifySourceUrl = (context, source, associatedObjectForCache) => {
401
- if (source.startsWith("webpack://")) return source;
402
- return `webpack://${makePathsRelative(
403
- context,
404
- source,
405
- associatedObjectForCache
406
- )}`;
407
- };
408
-
409
394
  /**
410
395
  * @param {string} context absolute context path
411
396
  * @param {string | RawSourceMap} sourceMap a source map
@@ -471,16 +456,79 @@ const asBuffer = (input) => {
471
456
  * @typedef {HookMap<FakeHook<AsyncSeriesBailHook<[string, NormalModule], string | Buffer | null>>>} DeprecatedReadResourceForScheme
472
457
  */
473
458
 
459
+ const createCompilationHooks = () => {
460
+ /** @type {HookMap<AsyncSeriesBailHook<[AnyLoaderContext], string | Buffer | null>>} */
461
+ const readResource = new HookMap(
462
+ () => new AsyncSeriesBailHook(["loaderContext"])
463
+ );
464
+ return {
465
+ // TODO webpack 6 deprecate
466
+ /**
467
+ * @deprecated Use the `readResource` hook instead.
468
+ * @type {DeprecatedReadResourceForScheme}
469
+ */
470
+ readResourceForScheme: new HookMap((scheme) => {
471
+ const hook = readResource.for(scheme);
472
+ return createFakeHook(
473
+ /** @type {AsyncSeriesBailHook<[string, NormalModule], string | Buffer | null>} */ ({
474
+ tap: (options, fn) =>
475
+ hook.tap(options, (loaderContext) =>
476
+ fn(
477
+ loaderContext.resource,
478
+ /** @type {NormalModule} */ (loaderContext._module)
479
+ )
480
+ ),
481
+ tapAsync: (options, fn) =>
482
+ hook.tapAsync(options, (loaderContext, callback) =>
483
+ fn(
484
+ loaderContext.resource,
485
+ /** @type {NormalModule} */ (loaderContext._module),
486
+ callback
487
+ )
488
+ ),
489
+ tapPromise: (options, fn) =>
490
+ hook.tapPromise(options, (loaderContext) =>
491
+ fn(
492
+ loaderContext.resource,
493
+ /** @type {NormalModule} */ (loaderContext._module)
494
+ )
495
+ )
496
+ })
497
+ );
498
+ }),
499
+ /**
500
+ * @since 5.58.0
501
+ */
502
+ readResource,
503
+ /** @type {SyncHook<[AnyLoaderContext, NormalModule]>} */
504
+ loader: new SyncHook(["loaderContext", "module"]),
505
+ /** @type {SyncHook<[LoaderItem[], NormalModule, AnyLoaderContext]>} */
506
+ beforeLoaders: new SyncHook(["loaders", "module", "loaderContext"]),
507
+ /**
508
+ * @type {SyncHook<[NormalModule]>}
509
+ * @since 5.59.0
510
+ */
511
+ beforeParse: new SyncHook(["module"]),
512
+ /**
513
+ * @type {SyncHook<[NormalModule]>}
514
+ * @since 5.59.0
515
+ */
516
+ beforeSnapshot: new SyncHook(["module"]),
517
+ /**
518
+ * @type {SyncWaterfallHook<[Result, NormalModule]>}
519
+ * @since 5.99.0
520
+ */
521
+ processResult: new SyncWaterfallHook(["result", "module"]),
522
+ /**
523
+ * @type {AsyncSeriesBailHook<[NormalModule, NeedBuildContext], boolean>}
524
+ * @since 5.49.0
525
+ */
526
+ needBuild: new AsyncSeriesBailHook(["module", "context"])
527
+ };
528
+ };
529
+
474
530
  /**
475
- * @typedef {object} NormalModuleCompilationHooks
476
- * @property {SyncHook<[AnyLoaderContext, NormalModule]>} loader
477
- * @property {SyncHook<[LoaderItem[], NormalModule, AnyLoaderContext]>} beforeLoaders
478
- * @property {SyncHook<[NormalModule]>} beforeParse
479
- * @property {SyncHook<[NormalModule]>} beforeSnapshot
480
- * @property {DeprecatedReadResourceForScheme} readResourceForScheme
481
- * @property {HookMap<AsyncSeriesBailHook<[AnyLoaderContext], string | Buffer | null>>} readResource
482
- * @property {SyncWaterfallHook<[Result, NormalModule]>} processResult
483
- * @property {AsyncSeriesBailHook<[NormalModule, NeedBuildContext], boolean>} needBuild
531
+ * @typedef {ReturnType<typeof createCompilationHooks>} NormalModuleCompilationHooks
484
532
  */
485
533
 
486
534
  /**
@@ -524,52 +572,7 @@ const asBuffer = (input) => {
524
572
 
525
573
  /** @typedef {BuildInfo & KnownNormalModuleBuildInfo} NormalModuleBuildInfo */
526
574
 
527
- const normalModuleHooksRegistry = createHooksRegistry(() => {
528
- // TODO webpack 6 deprecate
529
- /** @type {Partial<NormalModuleCompilationHooks>} */
530
- const hooks = {};
531
- hooks.readResourceForScheme = new HookMap((scheme) => {
532
- const hook =
533
- /** @type {NormalModuleCompilationHooks} */
534
- (hooks).readResource.for(scheme);
535
- return createFakeHook(
536
- /** @type {AsyncSeriesBailHook<[string, NormalModule], string | Buffer | null>} */ ({
537
- tap: (options, fn) =>
538
- hook.tap(options, (loaderContext) =>
539
- fn(
540
- loaderContext.resource,
541
- /** @type {NormalModule} */ (loaderContext._module)
542
- )
543
- ),
544
- tapAsync: (options, fn) =>
545
- hook.tapAsync(options, (loaderContext, callback) =>
546
- fn(
547
- loaderContext.resource,
548
- /** @type {NormalModule} */ (loaderContext._module),
549
- callback
550
- )
551
- ),
552
- tapPromise: (options, fn) =>
553
- hook.tapPromise(options, (loaderContext) =>
554
- fn(
555
- loaderContext.resource,
556
- /** @type {NormalModule} */ (loaderContext._module)
557
- )
558
- )
559
- })
560
- );
561
- });
562
- hooks.readResource = new HookMap(
563
- () => new AsyncSeriesBailHook(["loaderContext"])
564
- );
565
- hooks.loader = new SyncHook(["loaderContext", "module"]);
566
- hooks.beforeLoaders = new SyncHook(["loaders", "module", "loaderContext"]);
567
- hooks.beforeParse = new SyncHook(["module"]);
568
- hooks.beforeSnapshot = new SyncHook(["module"]);
569
- hooks.processResult = new SyncWaterfallHook(["result", "module"]);
570
- hooks.needBuild = new AsyncSeriesBailHook(["module", "context"]);
571
- return /** @type {NormalModuleCompilationHooks} */ (hooks);
572
- });
575
+ const normalModuleHooksRegistry = createHooksRegistry(createCompilationHooks);
573
576
 
574
577
  class NormalModule extends Module {
575
578
  /**
@@ -651,6 +654,12 @@ class NormalModule extends Module {
651
654
  * @type {Source | null}
652
655
  */
653
656
  this._source = null;
657
+ // Set at build time; declared here so the instance shape is fixed at construction
658
+ /**
659
+ * @private
660
+ * @type {PreparsedAst | null}
661
+ */
662
+ this._ast = null;
654
663
  /**
655
664
  * @private
656
665
  * @type {Map<undefined | SourceType, number> | undefined}
@@ -435,7 +435,10 @@ class NormalModuleFactory extends ModuleFactory {
435
435
  resolveForScheme: new HookMap(
436
436
  () => new AsyncSeriesBailHook(["resourceData", "resolveData"])
437
437
  ),
438
- /** @type {HookMap<AsyncSeriesBailHook<[ResourceDataWithData, ResolveData], true | void>>} */
438
+ /**
439
+ * @type {HookMap<AsyncSeriesBailHook<[ResourceDataWithData, ResolveData], true | void>>}
440
+ * @since 5.49.0
441
+ */
439
442
  resolveInScheme: new HookMap(
440
443
  () => new AsyncSeriesBailHook(["resourceData", "resolveData"])
441
444
  ),
@@ -461,7 +464,10 @@ class NormalModuleFactory extends ModuleFactory {
461
464
  generator: new HookMap(
462
465
  () => new SyncHook(["generator", "generatorOptions"])
463
466
  ),
464
- /** @type {HookMap<SyncBailHook<[CreateData, ResolveData], Module | void>>} */
467
+ /**
468
+ * @type {HookMap<SyncBailHook<[CreateData, ResolveData], Module | void>>}
469
+ * @since 5.81.0
470
+ */
465
471
  createModuleClass: new HookMap(
466
472
  () => new SyncBailHook(["createData", "resolveData"])
467
473
  )
@@ -119,6 +119,33 @@ const TREE_DEPENDENCIES = {
119
119
  [RuntimeGlobals.shareScopeMap]: [RuntimeGlobals.hasOwnProperty]
120
120
  };
121
121
 
122
+ // Tree runtime requirements whose only effect is attaching a zero-arg runtime
123
+ // module to the chunk. Conditional / argument-taking ones stay as explicit taps.
124
+ /** @type {[string, (new () => import("./RuntimeModule"))][]} */
125
+ const SIMPLE_TREE_RUNTIME_MODULES = [
126
+ [RuntimeGlobals.definePropertyGetters, DefinePropertyGettersRuntimeModule],
127
+ [RuntimeGlobals.makeNamespaceObject, MakeNamespaceObjectRuntimeModule],
128
+ [
129
+ RuntimeGlobals.createFakeNamespaceObject,
130
+ CreateFakeNamespaceObjectRuntimeModule
131
+ ],
132
+ [RuntimeGlobals.hasOwnProperty, HasOwnPropertyRuntimeModule],
133
+ [RuntimeGlobals.compatGetDefaultExport, CompatGetDefaultExportRuntimeModule],
134
+ [RuntimeGlobals.commonJsWrap, CommonJsWrapRuntimeModule],
135
+ [
136
+ RuntimeGlobals.setAnonymousDefaultName,
137
+ SetAnonymousDefaultNameRuntimeModule
138
+ ],
139
+ [RuntimeGlobals.runtimeId, RuntimeIdRuntimeModule],
140
+ [RuntimeGlobals.global, GlobalRuntimeModule],
141
+ [RuntimeGlobals.shareScopeMap, ShareRuntimeModule],
142
+ [RuntimeGlobals.relativeUrl, RelativeUrlRuntimeModule],
143
+ [RuntimeGlobals.worker, WorkerRuntimeModule],
144
+ [RuntimeGlobals.onChunksLoaded, OnChunksLoadedRuntimeModule],
145
+ [RuntimeGlobals.scriptNonce, NonceRuntimeModule],
146
+ [RuntimeGlobals.toBinary, ToBinaryRuntimeModule]
147
+ ];
148
+
122
149
  /**
123
150
  * @param {string} template path template
124
151
  * @returns {boolean} true when it references the compilation `[fullhash]`/`[hash]`
@@ -198,36 +225,20 @@ class RuntimePlugin {
198
225
  for (const dep of deps) set.add(dep);
199
226
  });
200
227
  }
201
- compilation.hooks.runtimeRequirementInTree
202
- .for(RuntimeGlobals.definePropertyGetters)
203
- .tap(PLUGIN_NAME, (chunk) => {
204
- compilation.addRuntimeModule(
205
- chunk,
206
- new DefinePropertyGettersRuntimeModule()
207
- );
208
- return true;
209
- });
210
- compilation.hooks.runtimeRequirementInTree
211
- .for(RuntimeGlobals.makeNamespaceObject)
212
- .tap(PLUGIN_NAME, (chunk) => {
213
- compilation.addRuntimeModule(
214
- chunk,
215
- new MakeNamespaceObjectRuntimeModule()
216
- );
217
- return true;
218
- });
219
- compilation.hooks.runtimeRequirementInTree
220
- .for(RuntimeGlobals.createFakeNamespaceObject)
221
- .tap(PLUGIN_NAME, (chunk) => {
222
- compilation.addRuntimeModule(
223
- chunk,
224
- new CreateFakeNamespaceObjectRuntimeModule()
225
- );
226
- return true;
227
- });
228
+ for (const [
229
+ runtimeGlobal,
230
+ RuntimeModule
231
+ ] of SIMPLE_TREE_RUNTIME_MODULES) {
232
+ compilation.hooks.runtimeRequirementInTree
233
+ .for(runtimeGlobal)
234
+ .tap(PLUGIN_NAME, (chunk) => {
235
+ compilation.addRuntimeModule(chunk, new RuntimeModule());
236
+ return true;
237
+ });
238
+ }
228
239
  compilation.hooks.runtimeRequirementInTree
229
240
  .for(RuntimeGlobals.makeOptimizedDeferredNamespaceObject)
230
- .tap("RuntimePlugin", (chunk, runtimeRequirement) => {
241
+ .tap(PLUGIN_NAME, (chunk, runtimeRequirement) => {
231
242
  compilation.addRuntimeModule(
232
243
  chunk,
233
244
  new MakeOptimizedDeferredNamespaceObjectRuntimeModule(
@@ -238,7 +249,7 @@ class RuntimePlugin {
238
249
  });
239
250
  compilation.hooks.runtimeRequirementInTree
240
251
  .for(RuntimeGlobals.makeDeferredNamespaceObject)
241
- .tap("RuntimePlugin", (chunk, runtimeRequirement) => {
252
+ .tap(PLUGIN_NAME, (chunk, runtimeRequirement) => {
242
253
  compilation.addRuntimeModule(
243
254
  chunk,
244
255
  new MakeDeferredNamespaceObjectRuntimeModule(
@@ -247,45 +258,6 @@ class RuntimePlugin {
247
258
  );
248
259
  return true;
249
260
  });
250
- compilation.hooks.runtimeRequirementInTree
251
- .for(RuntimeGlobals.hasOwnProperty)
252
- .tap(PLUGIN_NAME, (chunk) => {
253
- compilation.addRuntimeModule(
254
- chunk,
255
- new HasOwnPropertyRuntimeModule()
256
- );
257
- return true;
258
- });
259
- compilation.hooks.runtimeRequirementInTree
260
- .for(RuntimeGlobals.compatGetDefaultExport)
261
- .tap(PLUGIN_NAME, (chunk) => {
262
- compilation.addRuntimeModule(
263
- chunk,
264
- new CompatGetDefaultExportRuntimeModule()
265
- );
266
- return true;
267
- });
268
- compilation.hooks.runtimeRequirementInTree
269
- .for(RuntimeGlobals.commonJsWrap)
270
- .tap(PLUGIN_NAME, (chunk) => {
271
- compilation.addRuntimeModule(chunk, new CommonJsWrapRuntimeModule());
272
- return true;
273
- });
274
- compilation.hooks.runtimeRequirementInTree
275
- .for(RuntimeGlobals.setAnonymousDefaultName)
276
- .tap(PLUGIN_NAME, (chunk) => {
277
- compilation.addRuntimeModule(
278
- chunk,
279
- new SetAnonymousDefaultNameRuntimeModule()
280
- );
281
- return true;
282
- });
283
- compilation.hooks.runtimeRequirementInTree
284
- .for(RuntimeGlobals.runtimeId)
285
- .tap(PLUGIN_NAME, (chunk) => {
286
- compilation.addRuntimeModule(chunk, new RuntimeIdRuntimeModule());
287
- return true;
288
- });
289
261
  compilation.hooks.runtimeRequirementInTree
290
262
  .for(RuntimeGlobals.publicPath)
291
263
  .tap(PLUGIN_NAME, (chunk, set) => {
@@ -321,12 +293,6 @@ class RuntimePlugin {
321
293
  }
322
294
  return true;
323
295
  });
324
- compilation.hooks.runtimeRequirementInTree
325
- .for(RuntimeGlobals.global)
326
- .tap(PLUGIN_NAME, (chunk) => {
327
- compilation.addRuntimeModule(chunk, new GlobalRuntimeModule());
328
- return true;
329
- });
330
296
  compilation.hooks.runtimeRequirementInTree
331
297
  .for(RuntimeGlobals.asyncModule)
332
298
  .tap(PLUGIN_NAME, (chunk) => {
@@ -500,12 +466,6 @@ class RuntimePlugin {
500
466
  .tap(PLUGIN_NAME, (chunk, set) => {
501
467
  set.add(RuntimeGlobals.ensureChunkHandlers);
502
468
  });
503
- compilation.hooks.runtimeRequirementInTree
504
- .for(RuntimeGlobals.shareScopeMap)
505
- .tap(PLUGIN_NAME, (chunk, set) => {
506
- compilation.addRuntimeModule(chunk, new ShareRuntimeModule());
507
- return true;
508
- });
509
469
  compilation.hooks.runtimeRequirementInTree
510
470
  .for(RuntimeGlobals.loadScript)
511
471
  .tap(PLUGIN_NAME, (chunk, set) => {
@@ -552,27 +512,6 @@ class RuntimePlugin {
552
512
  );
553
513
  return true;
554
514
  });
555
- compilation.hooks.runtimeRequirementInTree
556
- .for(RuntimeGlobals.relativeUrl)
557
- .tap(PLUGIN_NAME, (chunk, _set) => {
558
- compilation.addRuntimeModule(chunk, new RelativeUrlRuntimeModule());
559
- return true;
560
- });
561
- compilation.hooks.runtimeRequirementInTree
562
- .for(RuntimeGlobals.worker)
563
- .tap(PLUGIN_NAME, (chunk, _set) => {
564
- compilation.addRuntimeModule(chunk, new WorkerRuntimeModule());
565
- return true;
566
- });
567
- compilation.hooks.runtimeRequirementInTree
568
- .for(RuntimeGlobals.onChunksLoaded)
569
- .tap(PLUGIN_NAME, (chunk, _set) => {
570
- compilation.addRuntimeModule(
571
- chunk,
572
- new OnChunksLoadedRuntimeModule()
573
- );
574
- return true;
575
- });
576
515
  compilation.hooks.runtimeRequirementInTree
577
516
  .for(RuntimeGlobals.baseURI)
578
517
  .tap(PLUGIN_NAME, (chunk) => {
@@ -581,18 +520,6 @@ class RuntimePlugin {
581
520
  return true;
582
521
  }
583
522
  });
584
- compilation.hooks.runtimeRequirementInTree
585
- .for(RuntimeGlobals.scriptNonce)
586
- .tap(PLUGIN_NAME, (chunk) => {
587
- compilation.addRuntimeModule(chunk, new NonceRuntimeModule());
588
- return true;
589
- });
590
- compilation.hooks.runtimeRequirementInTree
591
- .for(RuntimeGlobals.toBinary)
592
- .tap(PLUGIN_NAME, (chunk) => {
593
- compilation.addRuntimeModule(chunk, new ToBinaryRuntimeModule());
594
- return true;
595
- });
596
523
  // TODO webpack 6: remove CompatRuntimeModule
597
524
  compilation.hooks.additionalTreeRuntimeRequirements.tap(
598
525
  PLUGIN_NAME,
package/lib/Template.js CHANGED
@@ -46,6 +46,22 @@ const COMMENT_END_REGEX = /\*\//g;
46
46
  const PATH_NAME_NORMALIZE_REPLACE_REGEX = /[^a-z0-9_!§$()=\-^°]+/gi;
47
47
  const MATCH_PADDED_HYPHENS_REPLACE_REGEX = /^-|-$/g;
48
48
 
49
+ /**
50
+ * Decimal digit count of a non-negative integer, without allocating a string.
51
+ * @param {number} n non-negative integer
52
+ * @returns {number} number of decimal digits
53
+ */
54
+ const numberLength = (n) => {
55
+ if (n < 10) return 1;
56
+ if (n < 100) return 2;
57
+ if (n < 1000) return 3;
58
+ if (n < 10000) return 4;
59
+ if (n < 100000) return 5;
60
+ if (n < 1000000) return 6;
61
+ if (n < 10000000) return 7;
62
+ return String(n).length;
63
+ };
64
+
49
65
  /**
50
66
  * Defines the render manifest options type used by this module.
51
67
  * @typedef {object} RenderManifestOptions
@@ -296,11 +312,15 @@ class Template {
296
312
  // start with -1 because the first module needs no comma
297
313
  let objectOverhead = -1;
298
314
  for (const module of modules) {
299
- // module id + colon + comma
300
- objectOverhead += `${module.id}`.length + 2;
315
+ // module id digits + colon + comma; ids are non-negative integers here
316
+ // (non-number ids already returned false above), so count digits
317
+ // arithmetically instead of allocating a string per module.
318
+ const id = /** @type {number} */ (module.id);
319
+ objectOverhead += numberLength(id) + 2;
301
320
  }
302
321
  // number of commas, or when starting non-zero the length of Array(minId).concat()
303
- const arrayOverhead = minId === 0 ? maxId : 16 + `${minId}`.length + maxId;
322
+ const arrayOverhead =
323
+ minId === 0 ? maxId : 16 + numberLength(minId) + maxId;
304
324
  return arrayOverhead < objectOverhead ? [minId, maxId] : false;
305
325
  }
306
326