webpack 5.21.0 → 5.23.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.

Potentially problematic release.


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

Files changed (61) hide show
  1. package/lib/ChunkGraph.js +3 -2
  2. package/lib/CodeGenerationResults.js +2 -1
  3. package/lib/Compilation.js +91 -40
  4. package/lib/EvalDevToolModulePlugin.js +4 -0
  5. package/lib/EvalSourceMapDevToolPlugin.js +4 -0
  6. package/lib/ExportsInfo.js +1 -0
  7. package/lib/ExternalModule.js +8 -7
  8. package/lib/FlagDependencyUsagePlugin.js +7 -6
  9. package/lib/JavascriptMetaInfoPlugin.js +62 -0
  10. package/lib/LibManifestPlugin.js +1 -13
  11. package/lib/Module.js +2 -3
  12. package/lib/MultiCompiler.js +170 -77
  13. package/lib/MultiStats.js +9 -6
  14. package/lib/NormalModuleFactory.js +135 -22
  15. package/lib/RuntimeGlobals.js +5 -0
  16. package/lib/RuntimePlugin.js +10 -1
  17. package/lib/Watching.js +70 -27
  18. package/lib/WebpackOptionsApply.js +7 -7
  19. package/lib/config/defaults.js +26 -10
  20. package/lib/config/target.js +1 -1
  21. package/lib/container/ContainerEntryModule.js +2 -1
  22. package/lib/dependencies/AMDDefineDependency.js +1 -1
  23. package/lib/dependencies/AMDDefineDependencyParserPlugin.js +8 -0
  24. package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +2 -1
  25. package/lib/dependencies/HarmonyExportInitFragment.js +2 -3
  26. package/lib/dependencies/HarmonyImportSpecifierDependency.js +9 -2
  27. package/lib/dependencies/LoaderPlugin.js +9 -2
  28. package/lib/dependencies/URLDependency.js +35 -13
  29. package/lib/dependencies/URLPlugin.js +3 -1
  30. package/lib/dependencies/WorkerPlugin.js +7 -1
  31. package/lib/hmr/LazyCompilationPlugin.js +2 -2
  32. package/lib/index.js +1 -0
  33. package/lib/javascript/CommonJsChunkFormatPlugin.js +15 -4
  34. package/lib/javascript/JavascriptModulesPlugin.js +143 -78
  35. package/lib/javascript/JavascriptParser.js +1 -0
  36. package/lib/json/JsonGenerator.js +29 -8
  37. package/lib/library/AbstractLibraryPlugin.js +108 -32
  38. package/lib/library/AmdLibraryPlugin.js +12 -6
  39. package/lib/library/AssignLibraryPlugin.js +137 -26
  40. package/lib/library/EnableLibraryPlugin.js +18 -7
  41. package/lib/library/ExportPropertyLibraryPlugin.js +16 -5
  42. package/lib/library/JsonpLibraryPlugin.js +3 -1
  43. package/lib/library/ModuleLibraryPlugin.js +100 -0
  44. package/lib/library/SystemLibraryPlugin.js +1 -1
  45. package/lib/node/NodeTargetPlugin.js +1 -1
  46. package/lib/optimize/ConcatenatedModule.js +54 -35
  47. package/lib/optimize/InnerGraph.js +5 -4
  48. package/lib/runtime/GetChunkFilenameRuntimeModule.js +2 -3
  49. package/lib/runtime/RelativeUrlRuntimeModule.js +41 -0
  50. package/lib/runtime/StartupChunkDependenciesPlugin.js +1 -0
  51. package/lib/serialization/ObjectMiddleware.js +34 -19
  52. package/lib/stats/DefaultStatsFactoryPlugin.js +1 -12
  53. package/lib/stats/DefaultStatsPrinterPlugin.js +19 -6
  54. package/lib/util/IterableHelpers.js +46 -0
  55. package/lib/util/LazyBucketSortedSet.js +3 -2
  56. package/lib/util/SetHelpers.js +11 -0
  57. package/lib/webpack.js +56 -50
  58. package/package.json +3 -3
  59. package/schemas/WebpackOptions.json +8 -1
  60. package/types.d.ts +38 -7
  61. package/lib/FlagUsingEvalPlugin.js +0 -44
package/lib/ChunkGraph.js CHANGED
@@ -7,6 +7,7 @@
7
7
 
8
8
  const util = require("util");
9
9
  const ModuleGraphConnection = require("./ModuleGraphConnection");
10
+ const { first } = require("./util/SetHelpers");
10
11
  const SortableSet = require("./util/SortableSet");
11
12
  const StringXor = require("./util/StringXor");
12
13
  const {
@@ -1215,7 +1216,7 @@ class ChunkGraph {
1215
1216
  Caller might not support runtime-dependent code generation (opt-out via optimization.usedExports: "global").`
1216
1217
  );
1217
1218
  }
1218
- return hashInfoItems.values().next().value;
1219
+ return first(hashInfoItems);
1219
1220
  } else {
1220
1221
  const hashInfo = hashes.get(runtime);
1221
1222
  if (!hashInfo) {
@@ -1405,7 +1406,7 @@ Caller might not support runtime-dependent code generation (opt-out via optimiza
1405
1406
  true
1406
1407
  );
1407
1408
  if (states.size === 1) {
1408
- const state = states.values().next().value;
1409
+ const state = first(states);
1409
1410
  if (state === false) continue;
1410
1411
  stateInfo = activeStateToString(state);
1411
1412
  }
@@ -6,6 +6,7 @@
6
6
  "use strict";
7
7
 
8
8
  const { provide } = require("./util/MapHelpers");
9
+ const { first } = require("./util/SetHelpers");
9
10
  const createHash = require("./util/createHash");
10
11
  const { runtimeToString, RuntimeSpecMap } = require("./util/runtime");
11
12
 
@@ -47,7 +48,7 @@ class CodeGenerationResults {
47
48
  Caller might not support runtime-dependent code generation (opt-out via optimization.usedExports: "global").`
48
49
  );
49
50
  }
50
- return results.values().next().value;
51
+ return first(results);
51
52
  }
52
53
  return entry.values().next().value;
53
54
  }
@@ -2185,14 +2185,13 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
2185
2185
  ...mapAndSort(includeDependencies)
2186
2186
  ];
2187
2187
 
2188
+ let modulesList = chunkGraphInit.get(entrypoint);
2189
+ if (modulesList === undefined) {
2190
+ chunkGraphInit.set(entrypoint, (modulesList = []));
2191
+ }
2188
2192
  for (const module of includedModules) {
2189
2193
  this.assignDepth(module);
2190
- const modulesList = chunkGraphInit.get(entrypoint);
2191
- if (modulesList === undefined) {
2192
- chunkGraphInit.set(entrypoint, [module]);
2193
- } else {
2194
- modulesList.push(module);
2195
- }
2194
+ modulesList.push(module);
2196
2195
  }
2197
2196
  }
2198
2197
  const runtimeChunks = new Set();
@@ -3136,54 +3135,106 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
3136
3135
  }
3137
3136
 
3138
3137
  this.logger.time("hashing: sort chunks");
3139
- // clone needed as sort below is in place mutation
3140
- const chunks = Array.from(this.chunks);
3141
- /**
3142
- * sort here will bring all "falsy" values to the beginning
3143
- * this is needed as the "hasRuntime()" chunks are dependent on the
3144
- * hashes of the non-runtime chunks.
3138
+ /*
3139
+ * all non-runtime chunks need to be hashes first,
3140
+ * since runtime chunk might use their hashes.
3141
+ * runtime chunks need to be hashed in the correct order
3142
+ * since they may depend on each other (for async entrypoints).
3143
+ * So we put all non-runtime chunks first and hash them in any order.
3144
+ * And order runtime chunks according to referenced between each other.
3145
+ * Chunks need to be in deterministic order since we add hashes to full chunk
3146
+ * during these hashing.
3145
3147
  */
3146
- const runtimeChunks = [];
3148
+ /** @type {Chunk[]} */
3149
+ const unorderedRuntimeChunks = [];
3150
+ /** @type {Chunk[]} */
3147
3151
  const otherChunks = [];
3148
- for (const c of chunks) {
3152
+ for (const c of this.chunks) {
3149
3153
  if (c.hasRuntime()) {
3150
- runtimeChunks.push({
3151
- chunk: c,
3152
- referencedChunks: new Set(
3153
- Array.from(c.getAllReferencedAsyncEntrypoints()).map(
3154
- e => e.chunks[e.chunks.length - 1]
3155
- )
3156
- )
3157
- });
3154
+ unorderedRuntimeChunks.push(c);
3158
3155
  } else {
3159
3156
  otherChunks.push(c);
3160
3157
  }
3161
3158
  }
3159
+ unorderedRuntimeChunks.sort(byId);
3162
3160
  otherChunks.sort(byId);
3163
- runtimeChunks.sort((a, b) => {
3164
- const aDependOnB = a.referencedChunks.has(b.chunk);
3165
- const bDependOnA = b.referencedChunks.has(a.chunk);
3166
- if (aDependOnB && bDependOnA) {
3167
- const err = new WebpackError(
3168
- `Circular dependency between chunks with runtime (${
3169
- a.chunk.name || a.chunk.id
3170
- } and ${b.chunk.name || b.chunk.id}).
3171
- This prevents using hashes of each other and should be avoided.`
3172
- );
3173
- err.chunk = a.chunk;
3174
- this.warnings.push(err);
3175
- return byId(a.chunk, b.chunk);
3161
+
3162
+ /** @typedef {{ chunk: Chunk, referencedBy: RuntimeChunkInfo[], remaining: number }} RuntimeChunkInfo */
3163
+ /** @type {Map<Chunk, RuntimeChunkInfo>} */
3164
+ const runtimeChunksMap = new Map();
3165
+ for (const chunk of unorderedRuntimeChunks) {
3166
+ runtimeChunksMap.set(chunk, {
3167
+ chunk,
3168
+ referencedBy: [],
3169
+ remaining: 0
3170
+ });
3171
+ }
3172
+ let remaining = 0;
3173
+ for (const info of runtimeChunksMap.values()) {
3174
+ for (const other of new Set(
3175
+ Array.from(info.chunk.getAllReferencedAsyncEntrypoints()).map(
3176
+ e => e.chunks[e.chunks.length - 1]
3177
+ )
3178
+ )) {
3179
+ const otherInfo = runtimeChunksMap.get(other);
3180
+ otherInfo.referencedBy.push(info);
3181
+ info.remaining++;
3182
+ remaining++;
3176
3183
  }
3177
- if (aDependOnB) return 1;
3178
- if (bDependOnA) return -1;
3179
- return byId(a.chunk, b.chunk);
3180
- });
3184
+ }
3185
+ /** @type {Chunk[]} */
3186
+ const runtimeChunks = [];
3187
+ for (const info of runtimeChunksMap.values()) {
3188
+ if (info.remaining === 0) {
3189
+ runtimeChunks.push(info.chunk);
3190
+ }
3191
+ }
3192
+ // If there are any references between chunks
3193
+ // make sure to follow these chains
3194
+ if (remaining > 0) {
3195
+ const readyChunks = [];
3196
+ for (const chunk of runtimeChunks) {
3197
+ const info = runtimeChunksMap.get(chunk);
3198
+ for (const otherInfo of info.referencedBy) {
3199
+ remaining--;
3200
+ if (--otherInfo.remaining === 0) {
3201
+ readyChunks.push(otherInfo.chunk);
3202
+ }
3203
+ }
3204
+ if (readyChunks.length > 0) {
3205
+ // This ensures deterministic ordering, since referencedBy is non-deterministic
3206
+ readyChunks.sort(byId);
3207
+ for (const c of readyChunks) runtimeChunks.push(c);
3208
+ readyChunks.length = 0;
3209
+ }
3210
+ }
3211
+ }
3212
+ // If there are still remaining references we have cycles and want to create a warning
3213
+ if (remaining > 0) {
3214
+ let circularRuntimeChunkInfo = [];
3215
+ for (const info of runtimeChunksMap.values()) {
3216
+ if (info.remaining !== 0) {
3217
+ circularRuntimeChunkInfo.push(info);
3218
+ }
3219
+ }
3220
+ circularRuntimeChunkInfo.sort(compareSelect(i => i.chunk, byId));
3221
+ const err = new WebpackError(`Circular dependency between chunks with runtime (${Array.from(
3222
+ circularRuntimeChunkInfo,
3223
+ c => c.chunk.name || c.chunk.id
3224
+ ).join(", ")})
3225
+ This prevents using hashes of each other and should be avoided.`);
3226
+ err.chunk = circularRuntimeChunkInfo[0].chunk;
3227
+ this.warnings.push(err);
3228
+ for (const i of circularRuntimeChunkInfo) runtimeChunks.push(i.chunk);
3229
+ }
3181
3230
  this.logger.timeEnd("hashing: sort chunks");
3231
+
3182
3232
  const fullHashChunks = new Set();
3183
3233
  /** @type {{module: Module, hash: string, runtime: RuntimeSpec, runtimes: RuntimeSpec[]}[]} */
3184
3234
  const codeGenerationJobs = [];
3185
3235
  /** @type {Map<string, Map<Module, {module: Module, hash: string, runtime: RuntimeSpec, runtimes: RuntimeSpec[]}>>} */
3186
3236
  const codeGenerationJobsMap = new Map();
3237
+
3187
3238
  const processChunk = chunk => {
3188
3239
  // Last minute module hash generation for modules that depend on chunk hashes
3189
3240
  this.logger.time("hashing: hash runtime modules");
@@ -3253,7 +3304,7 @@ This prevents using hashes of each other and should be avoided.`
3253
3304
  this.logger.timeAggregate("hashing: hash chunks");
3254
3305
  };
3255
3306
  otherChunks.forEach(processChunk);
3256
- for (const { chunk } of runtimeChunks) processChunk(chunk);
3307
+ for (const chunk of runtimeChunks) processChunk(chunk);
3257
3308
 
3258
3309
  this.logger.timeAggregateEnd("hashing: hash runtime modules");
3259
3310
  this.logger.timeAggregateEnd("hashing: hash chunks");
@@ -82,6 +82,10 @@ class EvalDevToolModulePlugin {
82
82
  return result;
83
83
  }
84
84
  );
85
+ hooks.inlineInRuntimeBailout.tap(
86
+ "EvalDevToolModulePlugin",
87
+ () => "the eval devtool is used."
88
+ );
85
89
  hooks.render.tap(
86
90
  "EvalDevToolModulePlugin",
87
91
  source => new ConcatSource(devtoolWarning, source)
@@ -166,6 +166,10 @@ class EvalSourceMapDevToolPlugin {
166
166
  );
167
167
  }
168
168
  );
169
+ hooks.inlineInRuntimeBailout.tap(
170
+ "EvalDevToolModulePlugin",
171
+ () => "the eval-source-map devtool is used."
172
+ );
169
173
  hooks.render.tap(
170
174
  "EvalSourceMapDevToolPlugin",
171
175
  source => new ConcatSource(devtoolWarning, source)
@@ -395,6 +395,7 @@ class ExportsInfo {
395
395
  setAllKnownExportsUsed(runtime) {
396
396
  let changed = false;
397
397
  for (const exportInfo of this._exports.values()) {
398
+ if (!exportInfo.provided) continue;
398
399
  if (exportInfo.setUsed(UsageState.Used, runtime)) {
399
400
  changed = true;
400
401
  }
@@ -124,7 +124,7 @@ const getSourceForScriptExternal = (urlAndGlobal, runtimeTemplate) => {
124
124
  const url = urlAndGlobal[0];
125
125
  const globalName = urlAndGlobal[1];
126
126
  return {
127
- init: "var error = new Error();",
127
+ init: "var __webpack_error__ = new Error();",
128
128
  expression: `new Promise(${runtimeTemplate.basicFunction(
129
129
  "resolve, reject",
130
130
  [
@@ -135,11 +135,11 @@ const getSourceForScriptExternal = (urlAndGlobal, runtimeTemplate) => {
135
135
  `if(typeof ${globalName} !== "undefined") return resolve();`,
136
136
  "var errorType = event && (event.type === 'load' ? 'missing' : event.type);",
137
137
  "var realSrc = event && event.target && event.target.src;",
138
- "error.message = 'Loading script failed.\\n(' + errorType + ': ' + realSrc + ')';",
139
- "error.name = 'ScriptExternalLoadError';",
140
- "error.type = errorType;",
141
- "error.request = realSrc;",
142
- "reject(error);"
138
+ "__webpack_error__.message = 'Loading script failed.\\n(' + errorType + ': ' + realSrc + ')';",
139
+ "__webpack_error__.name = 'ScriptExternalLoadError';",
140
+ "__webpack_error__.type = errorType;",
141
+ "__webpack_error__.request = realSrc;",
142
+ "reject(__webpack_error__);"
143
143
  ])}, ${JSON.stringify(globalName)});`
144
144
  ]
145
145
  )}).then(${runtimeTemplate.returningFunction(
@@ -293,7 +293,8 @@ class ExternalModule extends Module {
293
293
  exportsType: undefined
294
294
  };
295
295
  this.buildInfo = {
296
- strict: this.externalType !== "this"
296
+ strict: this.externalType !== "this",
297
+ topLevelDeclarations: new Set()
297
298
  };
298
299
  this.buildMeta.exportsType = "dynamic";
299
300
  let canMangle = false;
@@ -161,9 +161,10 @@ class FlagDependencyUsagePlugin {
161
161
  /**
162
162
  * @param {DependenciesBlock} module the module
163
163
  * @param {RuntimeSpec} runtime part of which runtime
164
+ * @param {boolean} forceSideEffects always apply side effects
164
165
  * @returns {void}
165
166
  */
166
- const processModule = (module, runtime) => {
167
+ const processModule = (module, runtime, forceSideEffects) => {
167
168
  /** @type {Map<Module, (string[] | ReferencedExport)[] | Map<string, string[] | ReferencedExport>>} */
168
169
  const map = new Map();
169
170
 
@@ -179,7 +180,7 @@ class FlagDependencyUsagePlugin {
179
180
  b.groupOptions &&
180
181
  b.groupOptions.entryOptions
181
182
  ) {
182
- processModule(b, b.groupOptions.entryOptions.runtime);
183
+ processModule(b, b.groupOptions.entryOptions.runtime, true);
183
184
  } else {
184
185
  queue.enqueue(b);
185
186
  }
@@ -193,7 +194,7 @@ class FlagDependencyUsagePlugin {
193
194
  if (activeState === false) continue;
194
195
  const { module } = connection;
195
196
  if (activeState === ModuleGraphConnection.TRANSITIVE_ONLY) {
196
- processModule(module, runtime);
197
+ processModule(module, runtime, false);
197
198
  continue;
198
199
  }
199
200
  const oldReferencedExports = map.get(module);
@@ -263,14 +264,14 @@ class FlagDependencyUsagePlugin {
263
264
  module,
264
265
  referencedExports,
265
266
  runtime,
266
- false
267
+ forceSideEffects
267
268
  );
268
269
  } else {
269
270
  processReferencedModule(
270
271
  module,
271
272
  Array.from(referencedExports.values()),
272
273
  runtime,
273
- false
274
+ forceSideEffects
274
275
  );
275
276
  }
276
277
  }
@@ -327,7 +328,7 @@ class FlagDependencyUsagePlugin {
327
328
 
328
329
  while (queue.length) {
329
330
  const [module, runtime] = queue.dequeue();
330
- processModule(module, runtime);
331
+ processModule(module, runtime, false);
331
332
  }
332
333
  logger.timeEnd("trace exports usage in graph");
333
334
  }
@@ -0,0 +1,62 @@
1
+ /*
2
+ MIT License http://www.opensource.org/licenses/mit-license.php
3
+ Author Sergey Melyukov @smelukov
4
+ */
5
+
6
+ "use strict";
7
+
8
+ const InnerGraph = require("./optimize/InnerGraph");
9
+
10
+ /** @typedef {import("./Compiler")} Compiler */
11
+ /** @typedef {import("./javascript/JavascriptParser")} JavascriptParser */
12
+
13
+ class JavascriptMetaInfoPlugin {
14
+ /**
15
+ * Apply the plugin
16
+ * @param {Compiler} compiler the compiler instance
17
+ * @returns {void}
18
+ */
19
+ apply(compiler) {
20
+ compiler.hooks.compilation.tap(
21
+ "JavascriptMetaInfoPlugin",
22
+ (compilation, { normalModuleFactory }) => {
23
+ /**
24
+ * @param {JavascriptParser} parser the parser
25
+ * @returns {void}
26
+ */
27
+ const handler = parser => {
28
+ parser.hooks.call.for("eval").tap("JavascriptMetaInfoPlugin", () => {
29
+ parser.state.module.buildInfo.moduleConcatenationBailout = "eval()";
30
+ parser.state.module.buildInfo.usingEval = true;
31
+ InnerGraph.bailout(parser.state);
32
+ });
33
+ parser.hooks.finish.tap("JavascriptMetaInfoPlugin", () => {
34
+ let topLevelDeclarations =
35
+ parser.state.module.buildInfo.topLevelDeclarations;
36
+ if (topLevelDeclarations === undefined) {
37
+ topLevelDeclarations = parser.state.module.buildInfo.topLevelDeclarations = new Set();
38
+ }
39
+ for (const name of parser.scope.definitions.asSet()) {
40
+ const freeInfo = parser.getFreeInfoFromVariable(name);
41
+ if (freeInfo === undefined) {
42
+ topLevelDeclarations.add(name);
43
+ }
44
+ }
45
+ });
46
+ };
47
+
48
+ normalModuleFactory.hooks.parser
49
+ .for("javascript/auto")
50
+ .tap("JavascriptMetaInfoPlugin", handler);
51
+ normalModuleFactory.hooks.parser
52
+ .for("javascript/dynamic")
53
+ .tap("JavascriptMetaInfoPlugin", handler);
54
+ normalModuleFactory.hooks.parser
55
+ .for("javascript/esm")
56
+ .tap("JavascriptMetaInfoPlugin", handler);
57
+ }
58
+ );
59
+ }
60
+ }
61
+
62
+ module.exports = JavascriptMetaInfoPlugin;
@@ -7,6 +7,7 @@
7
7
 
8
8
  const asyncLib = require("neo-async");
9
9
  const EntryDependency = require("./dependencies/EntryDependency");
10
+ const { someInIterable } = require("./util/IterableHelpers");
10
11
  const { compareModulesById } = require("./util/comparators");
11
12
  const { dirname, mkdirp } = require("./util/fs");
12
13
 
@@ -19,19 +20,6 @@ const { dirname, mkdirp } = require("./util/fs");
19
20
  * @property {boolean | string[]} exports
20
21
  */
21
22
 
22
- /**
23
- * @template T
24
- * @param {Iterable<T>} iterable iterable
25
- * @param {function(T): boolean} filter predicate
26
- * @returns {boolean} true, if some items match the filter predicate
27
- */
28
- const someInIterable = (iterable, filter) => {
29
- for (const item of iterable) {
30
- if (filter(item)) return true;
31
- }
32
- return false;
33
- };
34
-
35
23
  class LibManifestPlugin {
36
24
  constructor(options) {
37
25
  this.options = options;
package/lib/Module.js CHANGED
@@ -10,6 +10,7 @@ const ChunkGraph = require("./ChunkGraph");
10
10
  const DependenciesBlock = require("./DependenciesBlock");
11
11
  const ModuleGraph = require("./ModuleGraph");
12
12
  const RuntimeGlobals = require("./RuntimeGlobals");
13
+ const { first } = require("./util/SetHelpers");
13
14
  const { compareChunksById } = require("./util/comparators");
14
15
  const makeSerializable = require("./util/makeSerializable");
15
16
 
@@ -796,9 +797,7 @@ class Module extends DependenciesBlock {
796
797
  runtime: undefined
797
798
  };
798
799
  const sources = this.codeGeneration(codeGenContext).sources;
799
- return type
800
- ? sources.get(type)
801
- : sources.get(this.getSourceTypes().values().next().value);
800
+ return type ? sources.get(type) : sources.get(first(this.getSourceTypes()));
802
801
  }
803
802
 
804
803
  /* istanbul ignore next */