webpack 5.105.2 → 5.105.3

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 (36) hide show
  1. package/lib/CleanPlugin.js +1 -0
  2. package/lib/Compilation.js +8 -6
  3. package/lib/ContextModule.js +14 -8
  4. package/lib/Dependency.js +1 -1
  5. package/lib/EnvironmentNotSupportAsyncWarning.js +1 -0
  6. package/lib/EvalDevToolModulePlugin.js +3 -0
  7. package/lib/EvalSourceMapDevToolPlugin.js +8 -1
  8. package/lib/ExportsInfo.js +0 -30
  9. package/lib/ExternalModule.js +2 -2
  10. package/lib/Module.js +30 -5
  11. package/lib/ModuleGraphConnection.js +0 -9
  12. package/lib/SourceMapDevToolModuleOptionsPlugin.js +1 -0
  13. package/lib/SourceMapDevToolPlugin.js +10 -2
  14. package/lib/WebpackOptionsApply.js +13 -3
  15. package/lib/asset/AssetModulesPlugin.js +16 -1
  16. package/lib/asset/RawDataUrlModule.js +5 -1
  17. package/lib/css/CssGenerator.js +3 -6
  18. package/lib/css/CssModulesPlugin.js +7 -0
  19. package/lib/dependencies/CommonJsExportRequireDependency.js +4 -0
  20. package/lib/dependencies/CommonJsImportsParserPlugin.js +314 -508
  21. package/lib/dependencies/CreateRequireParserPlugin.js +345 -0
  22. package/lib/dependencies/HarmonyExportDependencyParserPlugin.js +4 -8
  23. package/lib/dependencies/HarmonyImportDependency.js +30 -0
  24. package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +8 -20
  25. package/lib/dependencies/HarmonyModulesPlugin.js +4 -0
  26. package/lib/dependencies/ImportParserPlugin.js +1 -11
  27. package/lib/dependencies/ImportPhase.js +4 -0
  28. package/lib/javascript/JavascriptModulesPlugin.js +75 -22
  29. package/lib/javascript/JavascriptParser.js +2 -2
  30. package/lib/performance/AssetsOverSizeLimitWarning.js +1 -0
  31. package/lib/performance/EntrypointsOverSizeLimitWarning.js +1 -0
  32. package/lib/performance/SizeLimitsPlugin.js +1 -0
  33. package/lib/runtime/ToBinaryRuntimeModule.js +14 -6
  34. package/lib/util/findGraphRoots.js +79 -109
  35. package/package.json +12 -9
  36. package/types.d.ts +147 -62
@@ -318,13 +318,13 @@ class VariableInfo {
318
318
  /** @typedef {Literal | string | null | undefined} ImportSource */
319
319
 
320
320
  /**
321
- * @typedef {Omit<ParseOptions, "sourceType"> & { sourceType: "module" | "script" | "auto" }} InternalParseOptions
321
+ * @typedef {Omit<ParseOptions, "sourceType" | "ecmaVersion"> & { sourceType: "module" | "script" | "auto" }} InternalParseOptions
322
322
  */
323
323
 
324
324
  /**
325
325
  * @typedef {object} ParseOptions
326
326
  * @property {"module" | "script"} sourceType
327
- * @property {EcmaVersion=} ecmaVersion
327
+ * @property {EcmaVersion} ecmaVersion
328
328
  * @property {boolean=} locations
329
329
  * @property {boolean=} comments
330
330
  * @property {boolean=} ranges
@@ -28,6 +28,7 @@ Assets: ${assetLists}`);
28
28
 
29
29
  /** @type {string} */
30
30
  this.name = "AssetsOverSizeLimitWarning";
31
+ /** @type {AssetDetails[]} */
31
32
  this.assets = assetsOverSizeLimit;
32
33
  }
33
34
  }
@@ -31,6 +31,7 @@ Entrypoints:${entrypointList}\n`);
31
31
 
32
32
  /** @type {string} */
33
33
  this.name = "EntrypointsOverSizeLimitWarning";
34
+ /** @type {EntrypointDetails[]} */
34
35
  this.entrypoints = entrypoints;
35
36
  }
36
37
  }
@@ -46,6 +46,7 @@ module.exports = class SizeLimitsPlugin {
46
46
  * @param {PerformanceOptions} options the plugin options
47
47
  */
48
48
  constructor(options) {
49
+ /** @type {PerformanceOptions["hints"]} */
49
50
  this.hints = options.hints;
50
51
  /** @type {number | undefined} */
51
52
  this.maxAssetSize = options.maxAssetSize;
@@ -29,30 +29,38 @@ class ToBinaryRuntimeModule extends RuntimeModule {
29
29
  const isNodePlatform = compilation.compiler.platform.node;
30
30
  const isWebPlatform = compilation.compiler.platform.web;
31
31
  const isNeutralPlatform = runtimeTemplate.isNeutralPlatform();
32
+ const toImmutableBytes = runtimeTemplate.basicFunction("value", [
33
+ runtimeTemplate.destructureObject(["buffer"], "value"),
34
+ `${runtimeTemplate.renderConst()} throwErr = ${runtimeTemplate.basicFunction("", ["throw new TypeError('ArrayBuffer is immutable');"])};`,
35
+ "Object.defineProperties(buffer, { immutable: { value: true }, resize: { value: throwErr }, transfer: { value: throwErr }, transferToFixedLength: { value: throwErr } });",
36
+ "Object.freeze(buffer);",
37
+ "return value;"
38
+ ]);
32
39
 
33
40
  return Template.asString([
34
41
  "// define to binary helper",
42
+ `${runtimeTemplate.renderConst()} toImmutableBytes = ${toImmutableBytes}`,
35
43
  `${fn} = ${isNeutralPlatform ? "typeof Buffer !== 'undefined' ? " : ""}${
36
44
  isNodePlatform || isNeutralPlatform
37
- ? `${runtimeTemplate.returningFunction("new Uint8Array(Buffer.from(base64, 'base64'))", "base64")}`
45
+ ? `${runtimeTemplate.returningFunction("toImmutableBytes(new Uint8Array(Buffer.from(base64, 'base64')))", "base64")}`
38
46
  : ""
39
47
  } ${isNeutralPlatform ? ": " : ""}${
40
48
  isWebPlatform || isNeutralPlatform
41
49
  ? `(${runtimeTemplate.basicFunction("", [
42
- "var table = new Uint8Array(128);",
50
+ `${runtimeTemplate.renderConst()} table = new Uint8Array(128);`,
43
51
  "for (var i = 0; i < 64; i++) table[i < 26 ? i + 65 : i < 52 ? i + 71 : i < 62 ? i - 4 : i * 4 - 205] = i;",
44
52
  `return ${runtimeTemplate.basicFunction("base64", [
45
- "var n = base64.length, bytes = new Uint8Array((n - (base64[n - 1] == '=') - (base64[n - 2] == '=')) * 3 / 4 | 0);",
53
+ `${runtimeTemplate.renderConst()} n = base64.length, bytes = new Uint8Array((n - (base64[n - 1] == '=') - (base64[n - 2] == '=')) * 3 / 4 | 0);`,
46
54
  "for (var i = 0, j = 0; i < n;) {",
47
55
  Template.indent([
48
- "var c0 = table[base64.charCodeAt(i++)], c1 = table[base64.charCodeAt(i++)];",
49
- "var c2 = table[base64.charCodeAt(i++)], c3 = table[base64.charCodeAt(i++)];",
56
+ `${runtimeTemplate.renderConst()} c0 = table[base64.charCodeAt(i++)], c1 = table[base64.charCodeAt(i++)];`,
57
+ `${runtimeTemplate.renderConst()} c2 = table[base64.charCodeAt(i++)], c3 = table[base64.charCodeAt(i++)];`,
50
58
  "bytes[j++] = (c0 << 2) | (c1 >> 4);",
51
59
  "bytes[j++] = (c1 << 4) | (c2 >> 2);",
52
60
  "bytes[j++] = (c2 << 6) | c3;"
53
61
  ]),
54
62
  "}",
55
- "return bytes"
63
+ "return toImmutableBytes(bytes)"
56
64
  ])}`
57
65
  ])})();`
58
66
  : ""
@@ -8,19 +8,13 @@
8
8
  const NO_MARKER = 0;
9
9
  const IN_PROGRESS_MARKER = 1;
10
10
  const DONE_MARKER = 2;
11
- const DONE_MAYBE_ROOT_CYCLE_MARKER = 3;
12
- const DONE_AND_ROOT_MARKER = 4;
11
+ const CANDIDATE_MARKER = 3;
13
12
 
14
13
  /**
15
14
  * @template T
16
15
  * @typedef {Set<Node<T>>} Nodes
17
16
  */
18
17
 
19
- /**
20
- * @template T
21
- * @typedef {Set<Cycle<T>>} Cycles
22
- */
23
-
24
18
  /**
25
19
  * @template T
26
20
  */
@@ -32,20 +26,24 @@ class Node {
32
26
  this.item = item;
33
27
  /** @type {Nodes<T>} */
34
28
  this.dependencies = new Set();
35
- this.marker = NO_MARKER;
36
- /** @type {Cycle<T> | undefined} */
37
- this.cycle = undefined;
29
+ /** @type {SCC<T>} */
30
+ this.scc = new SCC();
31
+ // Each node starts as a single-node SCC
32
+ this.scc.nodes.add(this);
33
+ /** @type {number} */
38
34
  this.incoming = 0;
39
35
  }
40
36
  }
41
37
 
42
38
  /**
39
+ * SCC (strongly connected component)
43
40
  * @template T
44
41
  */
45
- class Cycle {
42
+ class SCC {
46
43
  constructor() {
47
44
  /** @type {Nodes<T>} */
48
45
  this.nodes = new Set();
46
+ this.marker = NO_MARKER;
49
47
  }
50
48
  }
51
49
 
@@ -70,10 +68,10 @@ module.exports = (items, getDependencies) => {
70
68
  itemToNode.set(item, node);
71
69
  }
72
70
 
73
- // early exit when there is only a single item
71
+ // Early exit when there is only one node
74
72
  if (itemToNode.size <= 1) return items;
75
73
 
76
- // grab all the dependencies
74
+ // Build graph edges
77
75
  for (const node of itemToNode.values()) {
78
76
  for (const dep of getDependencies(node.item)) {
79
77
  const depNode = itemToNode.get(dep);
@@ -83,27 +81,16 @@ module.exports = (items, getDependencies) => {
83
81
  }
84
82
  }
85
83
 
86
- // Set of current root modules
87
- // items will be removed if a new reference to it has been found
88
- /** @type {Nodes<T>} */
89
- const roots = new Set();
90
-
91
- // Set of current cycles without references to it
92
- // cycles will be removed if a new reference to it has been found
93
- // that is not part of the cycle
94
- /** @type {Cycles<T>} */
95
- const rootCycles = new Set();
84
+ // All candidate root SCCs, they will be removed once an incoming edge is found
85
+ /** @type {Set<SCC<T>>} */
86
+ const rootSCCs = new Set();
96
87
 
97
- // For all non-marked nodes
98
88
  for (const selectedNode of itemToNode.values()) {
99
- if (selectedNode.marker === NO_MARKER) {
100
- // deep-walk all referenced modules
101
- // in a non-recursive way
89
+ // DFS walk only once per unseen SCC
90
+ if (selectedNode.scc.marker === NO_MARKER) {
91
+ selectedNode.scc.marker = IN_PROGRESS_MARKER;
102
92
 
103
- // start by entering the selected node
104
- selectedNode.marker = IN_PROGRESS_MARKER;
105
-
106
- // keep a stack to avoid recursive walk
93
+ // Keep a stack to avoid recursive walk
107
94
  /** @type {StackEntry<T>[]} */
108
95
  const stack = [
109
96
  {
@@ -112,130 +99,113 @@ module.exports = (items, getDependencies) => {
112
99
  }
113
100
  ];
114
101
 
115
- // process the top item until stack is empty
116
102
  while (stack.length > 0) {
117
103
  const topOfStack = stack[stack.length - 1];
118
104
 
119
- // Are there still edges unprocessed in the current node?
105
+ // Process one unvisited outgoing edge if available
120
106
  if (topOfStack.openEdges.length > 0) {
121
- // Process one dependency
122
107
  const dependency =
123
108
  /** @type {Node<T>} */
124
109
  (topOfStack.openEdges.pop());
125
- switch (dependency.marker) {
110
+ const depSCC = dependency.scc;
111
+ switch (depSCC.marker) {
126
112
  case NO_MARKER:
127
- // dependency has not be visited yet
128
- // mark it as in-progress and recurse
113
+ // First time we see this SCC: enter it
129
114
  stack.push({
130
115
  node: dependency,
131
116
  openEdges: [...dependency.dependencies]
132
117
  });
133
- dependency.marker = IN_PROGRESS_MARKER;
118
+ depSCC.marker = IN_PROGRESS_MARKER;
134
119
  break;
135
120
  case IN_PROGRESS_MARKER: {
136
- // It's a in-progress cycle
137
- let cycle = dependency.cycle;
138
- if (!cycle) {
139
- cycle = new Cycle();
140
- cycle.nodes.add(dependency);
141
- dependency.cycle = cycle;
142
- }
143
- // set cycle property for each node in the cycle
144
- // if nodes are already part of a cycle
145
- // we merge the cycles to a shared cycle
121
+ // Back-edge to an SCC that is still on the stack
122
+ // Example:
123
+ // A -> B -> C -> D
124
+ // ^ |
125
+ // |_________|
126
+ // If we are at `D` and traverse `D` -> `B`, then `B/C/D` must be in one SCC
127
+ /** @type {Set<SCC<T>>} */
128
+ const sccsToMerge = new Set();
146
129
  for (
147
130
  let i = stack.length - 1;
148
- stack[i].node !== dependency;
131
+ stack[i].node.scc !== depSCC;
149
132
  i--
150
133
  ) {
151
- const node = stack[i].node;
152
- if (node.cycle) {
153
- if (node.cycle !== cycle) {
154
- // merge cycles
155
- for (const cycleNode of node.cycle.nodes) {
156
- cycleNode.cycle = cycle;
157
- cycle.nodes.add(cycleNode);
158
- }
159
- }
160
- } else {
161
- node.cycle = cycle;
162
- cycle.nodes.add(node);
134
+ sccsToMerge.add(stack[i].node.scc);
135
+ }
136
+ for (const sccToMerge of sccsToMerge) {
137
+ for (const nodeInMergedSCC of sccToMerge.nodes) {
138
+ nodeInMergedSCC.scc = depSCC;
139
+ depSCC.nodes.add(nodeInMergedSCC);
163
140
  }
164
141
  }
165
- // don't recurse into dependencies
166
- // these are already on the stack
167
142
  break;
168
143
  }
169
- case DONE_AND_ROOT_MARKER:
170
- // This node has be visited yet and is currently a root node
171
- // But as this is a new reference to the node
172
- // it's not really a root
173
- // so we have to convert it to a normal node
174
- dependency.marker = DONE_MARKER;
175
- roots.delete(dependency);
144
+ case CANDIDATE_MARKER:
145
+ // This finished SCC was previously considered as root SCC
146
+ // We just found a new incoming edge, so it is no longer a candidate
147
+ rootSCCs.delete(/** @type {SCC<T>} */ (depSCC));
148
+ depSCC.marker = DONE_MARKER;
176
149
  break;
177
- case DONE_MAYBE_ROOT_CYCLE_MARKER:
178
- // This node has be visited yet and
179
- // is maybe currently part of a completed root cycle
180
- // we found a new reference to the cycle
181
- // so it's not really a root cycle
182
- // remove the cycle from the root cycles
183
- // and convert it to a normal node
184
- rootCycles.delete(/** @type {Cycle<T>} */ (dependency.cycle));
185
- dependency.marker = DONE_MARKER;
150
+ case DONE_MARKER:
151
+ // Already finalized and not a candidate
186
152
  break;
187
- // DONE_MARKER: nothing to do, don't recurse into dependencies
188
153
  }
189
154
  } else {
190
- // All dependencies of the current node has been visited
191
- // we leave the node
155
+ // All dependencies of the current node have been processed
156
+ // So we leave the node
192
157
  stack.pop();
193
- topOfStack.node.marker = DONE_MARKER;
194
- }
195
- }
196
- const cycle = selectedNode.cycle;
197
- if (cycle) {
198
- for (const node of cycle.nodes) {
199
- node.marker = DONE_MAYBE_ROOT_CYCLE_MARKER;
158
+ // Mark an SCC as DONE only when the popped node is the last
159
+ // node from that SCC remaining on the current stack.
160
+ // A -> B -> C -> D
161
+ // ^ |
162
+ // |_________|
163
+ // If `B` is popped and the new stack top is `A`, they are in
164
+ // different SCCs, so B's SCC can be finalized.
165
+ if (
166
+ stack.length &&
167
+ topOfStack.node.scc !== stack[stack.length - 1].node.scc
168
+ ) {
169
+ topOfStack.node.scc.marker = DONE_MARKER;
170
+ }
200
171
  }
201
- rootCycles.add(cycle);
202
- } else {
203
- selectedNode.marker = DONE_AND_ROOT_MARKER;
204
- roots.add(selectedNode);
205
172
  }
173
+ const scc = selectedNode.scc;
174
+ // This SCC is complete and currently has no known incoming edge
175
+ scc.marker = CANDIDATE_MARKER;
176
+ rootSCCs.add(scc);
206
177
  }
207
178
  }
208
179
 
209
- // Extract roots from root cycles
210
- // We take the nodes with most incoming edges
211
- // inside of the cycle
212
- for (const cycle of rootCycles) {
180
+ /** @type {Set<T>} */
181
+ const rootNodes = new Set();
182
+
183
+ // For each root SCC, we select node with the most incoming edges
184
+ // from within the same SCC
185
+ for (const scc of rootSCCs) {
213
186
  let max = 0;
214
187
  /** @type {Nodes<T>} */
215
- const cycleRoots = new Set();
216
- const nodes = cycle.nodes;
217
- for (const node of nodes) {
188
+ const nodes = new Set(scc.nodes);
189
+ for (const node of scc.nodes) {
218
190
  for (const dep of node.dependencies) {
219
- if (nodes.has(dep)) {
191
+ if (scc.nodes.has(dep)) {
220
192
  dep.incoming++;
221
193
  if (dep.incoming < max) continue;
222
194
  if (dep.incoming > max) {
223
- cycleRoots.clear();
195
+ nodes.clear();
224
196
  max = dep.incoming;
225
197
  }
226
- cycleRoots.add(dep);
198
+ nodes.add(dep);
227
199
  }
228
200
  }
229
201
  }
230
- for (const cycleRoot of cycleRoots) {
231
- roots.add(cycleRoot);
202
+ for (const node of nodes) {
203
+ rootNodes.add(node.item);
232
204
  }
233
205
  }
234
206
 
235
- // When roots were found, return them
236
- if (roots.size > 0) {
237
- return Array.from(roots, (r) => r.item);
238
- }
207
+ // When root nodes were found, return them
208
+ if (rootNodes.size > 0) return rootNodes;
239
209
 
240
210
  throw new Error("Implementation of findGraphRoots is broken");
241
211
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webpack",
3
- "version": "5.105.2",
3
+ "version": "5.105.3",
4
4
  "description": "Packs ECMAScript/CommonJs/AMD modules for the browser. Allows you to split your codebase into multiple bundles, which can be loaded on demand. Supports loaders to preprocess files, i.e. json, jsx, es7, css, less, ... and your custom stuff.",
5
5
  "homepage": "https://github.com/webpack/webpack",
6
6
  "bugs": "https://github.com/webpack/webpack/issues",
@@ -57,6 +57,7 @@
57
57
  "test:basic:deno": "yarn test:base:deno --testMatch \"<rootDir>/test/*.basictest.js\"",
58
58
  "test:unit": "yarn test:base --testMatch \"<rootDir>/test/*.unittest.js\"",
59
59
  "test:integration": "yarn test:base --testMatch \"<rootDir>/test/*.{basictest,longtest,test}.js\"",
60
+ "test:test262": "yarn test:base --testMatch \"<rootDir>/test/*.spectest.js\"",
60
61
  "test:base:deno": "deno --allow-read --allow-env --allow-sys --allow-ffi --allow-write --allow-run --v8-flags='--max-old-space-size=4096' ./node_modules/jest-cli/bin/jest.js --logHeapUsage",
61
62
  "test:update-snapshots": "yarn test:base -u",
62
63
  "report:cover": "nyc report --reporter=lcov --reporter=text -t coverage",
@@ -71,7 +72,8 @@
71
72
  "cover:basic": "yarn cover:base --testMatch \"<rootDir>/test/*.basictest.js\" --coverage",
72
73
  "cover:integration": "yarn cover:base --testMatch \"<rootDir>/test/*.{basictest,longtest,test}.js\" --coverage",
73
74
  "cover:integration:a": "yarn cover:base --testMatch \"<rootDir>/test/*.{basictest,test}.js\" --coverage",
74
- "cover:integration:b": "yarn cover:base --testMatch \"<rootDir>/test/*.longtest.js\" --coverage"
75
+ "cover:integration:b": "yarn cover:base --testMatch \"<rootDir>/test/*.longtest.js\" --coverage",
76
+ "cover:test262": "yarn cover:base --testMatch \"<rootDir>/test/*.spectest.js\" --coverage"
75
77
  },
76
78
  "lint-staged": {
77
79
  "*.{js,cjs,mjs}": [
@@ -89,7 +91,7 @@
89
91
  "@webassemblyjs/ast": "^1.14.1",
90
92
  "@webassemblyjs/wasm-edit": "^1.14.1",
91
93
  "@webassemblyjs/wasm-parser": "^1.14.1",
92
- "acorn": "^8.15.0",
94
+ "acorn": "^8.16.0",
93
95
  "acorn-import-phases": "^1.0.3",
94
96
  "browserslist": "^4.28.1",
95
97
  "chrome-trace-event": "^1.0.2",
@@ -107,14 +109,14 @@
107
109
  "tapable": "^2.3.0",
108
110
  "terser-webpack-plugin": "^5.3.16",
109
111
  "watchpack": "^2.5.1",
110
- "webpack-sources": "^3.3.3"
112
+ "webpack-sources": "^3.3.4"
111
113
  },
112
114
  "devDependencies": {
113
115
  "@babel/core": "^7.27.1",
114
116
  "@babel/preset-react": "^7.27.1",
115
117
  "@changesets/cli": "^2.29.8",
116
118
  "@changesets/get-github-info": "^0.7.0",
117
- "@codspeed/core": "^5.1.0",
119
+ "@codspeed/core": "^5.2.0",
118
120
  "@types/glob-to-regexp": "^0.4.4",
119
121
  "@types/graceful-fs": "^4.1.9",
120
122
  "@types/jest": "^30.0.0",
@@ -134,7 +136,7 @@
134
136
  "es5-ext": "^0.10.53",
135
137
  "es6-promise-polyfill": "^1.2.0",
136
138
  "eslint": "^9.39.2",
137
- "eslint-config-webpack": "^4.9.1",
139
+ "eslint-config-webpack": "^4.9.3",
138
140
  "file-loader": "^6.0.0",
139
141
  "fork-ts-checker-webpack-plugin": "^9.0.2",
140
142
  "globals": "^17.0.0",
@@ -160,8 +162,9 @@
160
162
  "mini-css-extract-plugin": "^2.9.0",
161
163
  "mini-svg-data-uri": "^1.2.3",
162
164
  "node-gyp": "^12.1.0",
163
- "nyc": "^17.1.0",
165
+ "nyc": "^18.0.0",
164
166
  "open-cli": "^8.0.0",
167
+ "oxc-parser": "^0.115.0",
165
168
  "pkg-pr-new": "^0.0.63",
166
169
  "prettier": "^3.7.4",
167
170
  "prettier-2": "npm:prettier@^2",
@@ -183,10 +186,10 @@
183
186
  "strip-ansi": "^6.0.0",
184
187
  "style-loader": "^4.0.0",
185
188
  "terser": "^5.43.1",
186
- "three": "^0.182.0",
189
+ "three": "^0.183.1",
187
190
  "tinybench": "^6.0.0",
188
191
  "toml": "^3.0.0",
189
- "tooling": "webpack/tooling#v1.24.5",
192
+ "tooling": "webpack/tooling#v1.24.6",
190
193
  "ts-loader": "^9.5.4",
191
194
  "typescript": "^5.9.3",
192
195
  "unified": "^11.0.5",