webpack 5.88.1 → 5.89.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.

@@ -7,6 +7,7 @@
7
7
 
8
8
  const Template = require("../Template");
9
9
  const { equals } = require("../util/ArrayHelpers");
10
+ const { getTrimmedIdsAndRange } = require("../util/chainedImports");
10
11
  const makeSerializable = require("../util/makeSerializable");
11
12
  const propertyAccess = require("../util/propertyAccess");
12
13
  const ModuleDependency = require("./ModuleDependency");
@@ -26,11 +27,18 @@ class CommonJsFullRequireDependency extends ModuleDependency {
26
27
  * @param {string} request the request string
27
28
  * @param {Range} range location in source code
28
29
  * @param {string[]} names accessed properties on module
30
+ * @param {Range[]=} idRanges ranges for members of ids; the two arrays are right-aligned
29
31
  */
30
- constructor(request, range, names) {
32
+ constructor(
33
+ request,
34
+ range,
35
+ names,
36
+ idRanges /* TODO webpack 6 make this non-optional. It must always be set to properly trim ids. */
37
+ ) {
31
38
  super(request);
32
39
  this.range = range;
33
40
  this.names = names;
41
+ this.idRanges = idRanges;
34
42
  this.call = false;
35
43
  this.asiSafe = undefined;
36
44
  }
@@ -60,6 +68,7 @@ class CommonJsFullRequireDependency extends ModuleDependency {
60
68
  serialize(context) {
61
69
  const { write } = context;
62
70
  write(this.names);
71
+ write(this.idRanges);
63
72
  write(this.call);
64
73
  write(this.asiSafe);
65
74
  super.serialize(context);
@@ -71,6 +80,7 @@ class CommonJsFullRequireDependency extends ModuleDependency {
71
80
  deserialize(context) {
72
81
  const { read } = context;
73
82
  this.names = read();
83
+ this.idRanges = read();
74
84
  this.call = read();
75
85
  this.asiSafe = read();
76
86
  super.deserialize(context);
@@ -117,15 +127,26 @@ CommonJsFullRequireDependency.Template = class CommonJsFullRequireDependencyTemp
117
127
  weak: dep.weak,
118
128
  runtimeRequirements
119
129
  });
130
+
131
+ const {
132
+ trimmedRange: [trimmedRangeStart, trimmedRangeEnd],
133
+ trimmedIds
134
+ } = getTrimmedIdsAndRange(
135
+ dep.names,
136
+ dep.range,
137
+ dep.idRanges,
138
+ moduleGraph,
139
+ dep
140
+ );
141
+
120
142
  if (importedModule) {
121
- const ids = dep.names;
122
143
  const usedImported = moduleGraph
123
144
  .getExportsInfo(importedModule)
124
- .getUsedName(ids, runtime);
145
+ .getUsedName(trimmedIds, runtime);
125
146
  if (usedImported) {
126
- const comment = equals(usedImported, ids)
147
+ const comment = equals(usedImported, trimmedIds)
127
148
  ? ""
128
- : Template.toNormalComment(propertyAccess(ids)) + " ";
149
+ : Template.toNormalComment(propertyAccess(trimmedIds)) + " ";
129
150
  const access = `${comment}${propertyAccess(usedImported)}`;
130
151
  requireExpr =
131
152
  dep.asiSafe === true
@@ -133,7 +154,7 @@ CommonJsFullRequireDependency.Template = class CommonJsFullRequireDependencyTemp
133
154
  : `${requireExpr}${access}`;
134
155
  }
135
156
  }
136
- source.replace(dep.range[0], dep.range[1] - 1, requireExpr);
157
+ source.replace(trimmedRangeStart, trimmedRangeEnd - 1, requireExpr);
137
158
  }
138
159
  };
139
160
 
@@ -379,9 +379,16 @@ class CommonJsImportsParserPlugin {
379
379
  * @param {string[]} calleeMembers callee members
380
380
  * @param {CallExpression} callExpr call expression
381
381
  * @param {string[]} members members
382
+ * @param {Range[]} memberRanges member ranges
382
383
  * @returns {boolean | void} true when handled
383
384
  */
384
- const chainHandler = (expr, calleeMembers, callExpr, members) => {
385
+ const chainHandler = (
386
+ expr,
387
+ calleeMembers,
388
+ callExpr,
389
+ members,
390
+ memberRanges
391
+ ) => {
385
392
  if (callExpr.arguments.length !== 1) return;
386
393
  const param = parser.evaluateExpression(callExpr.arguments[0]);
387
394
  if (
@@ -391,7 +398,8 @@ class CommonJsImportsParserPlugin {
391
398
  const dep = new CommonJsFullRequireDependency(
392
399
  /** @type {string} */ (param.string),
393
400
  /** @type {Range} */ (expr.range),
394
- members
401
+ members,
402
+ /** @type {Range[]} */ memberRanges
395
403
  );
396
404
  dep.asiSafe = !parser.isAsiPosition(
397
405
  /** @type {Range} */ (expr.range)[0]
@@ -407,9 +415,16 @@ class CommonJsImportsParserPlugin {
407
415
  * @param {string[]} calleeMembers callee members
408
416
  * @param {CallExpression} callExpr call expression
409
417
  * @param {string[]} members members
418
+ * @param {Range[]} memberRanges member ranges
410
419
  * @returns {boolean | void} true when handled
411
420
  */
412
- const callChainHandler = (expr, calleeMembers, callExpr, members) => {
421
+ const callChainHandler = (
422
+ expr,
423
+ calleeMembers,
424
+ callExpr,
425
+ members,
426
+ memberRanges
427
+ ) => {
413
428
  if (callExpr.arguments.length !== 1) return;
414
429
  const param = parser.evaluateExpression(callExpr.arguments[0]);
415
430
  if (
@@ -419,7 +434,8 @@ class CommonJsImportsParserPlugin {
419
434
  const dep = new CommonJsFullRequireDependency(
420
435
  /** @type {string} */ (param.string),
421
436
  /** @type {Range} */ (expr.callee.range),
422
- members
437
+ members,
438
+ /** @type {Range[]} */ memberRanges
423
439
  );
424
440
  dep.call = true;
425
441
  dep.asiSafe = !parser.isAsiPosition(
@@ -109,6 +109,9 @@ CssLocalIdentifierDependency.Template = class CssLocalIdentifierDependencyTempla
109
109
  const used = moduleGraph
110
110
  .getExportInfo(module, dep.name)
111
111
  .getUsedName(dep.name, runtime);
112
+
113
+ if (!used) return;
114
+
112
115
  const moduleId = chunkGraph.getModuleId(module);
113
116
  const identifier =
114
117
  dep.prefix +
@@ -9,6 +9,7 @@ const Dependency = require("../Dependency");
9
9
  const {
10
10
  getDependencyUsedByExportsCondition
11
11
  } = require("../optimize/InnerGraph");
12
+ const { getTrimmedIdsAndRange } = require("../util/chainedImports");
12
13
  const makeSerializable = require("../util/makeSerializable");
13
14
  const propertyAccess = require("../util/propertyAccess");
14
15
  const HarmonyImportDependency = require("./HarmonyImportDependency");
@@ -324,30 +325,16 @@ HarmonyImportSpecifierDependency.Template = class HarmonyImportSpecifierDependen
324
325
  // Skip rendering depending when dependency is conditional
325
326
  if (connection && !connection.isTargetActive(runtime)) return;
326
327
 
327
- const ids = dep.getIds(moduleGraph); // determine minimal set of IDs.
328
- let trimmedIds = this._trimIdsToThoseImported(ids, moduleGraph, dep);
329
-
330
- let [rangeStart, rangeEnd] = dep.range;
331
- if (trimmedIds.length !== ids.length) {
332
- // The array returned from dep.idRanges is right-aligned with the array returned from dep.getIds.
333
- // Meaning, the two arrays may not always have the same number of elements, but the last element of
334
- // dep.idRanges corresponds to [the expression fragment to the left of] the last element of dep.getIds.
335
- // Use this to find the correct replacement range based on the number of ids that were trimmed.
336
- const idx =
337
- dep.idRanges === undefined
338
- ? -1 /* trigger failure case below */
339
- : dep.idRanges.length + (trimmedIds.length - ids.length);
340
- if (idx < 0 || idx >= dep.idRanges.length) {
341
- // cspell:ignore minifiers
342
- // Should not happen but we can't throw an error here because of backward compatibility with
343
- // external plugins in wp5. Instead, we just disable trimming for now. This may break some minifiers.
344
- trimmedIds = ids;
345
- // TODO webpack 6 remove the "trimmedIds = ids" above and uncomment the following line instead.
346
- // throw new Error("Missing range starts data for id replacement trimming.");
347
- } else {
348
- [rangeStart, rangeEnd] = dep.idRanges[idx];
349
- }
350
- }
328
+ const {
329
+ trimmedRange: [trimmedRangeStart, trimmedRangeEnd],
330
+ trimmedIds
331
+ } = getTrimmedIdsAndRange(
332
+ dep.getIds(moduleGraph),
333
+ dep.range,
334
+ dep.idRanges,
335
+ moduleGraph,
336
+ dep
337
+ );
351
338
 
352
339
  const exportExpr = this._getCodeForIds(
353
340
  dep,
@@ -356,47 +343,10 @@ HarmonyImportSpecifierDependency.Template = class HarmonyImportSpecifierDependen
356
343
  trimmedIds
357
344
  );
358
345
  if (dep.shorthand) {
359
- source.insert(rangeEnd, `: ${exportExpr}`);
346
+ source.insert(trimmedRangeEnd, `: ${exportExpr}`);
360
347
  } else {
361
- source.replace(rangeStart, rangeEnd - 1, exportExpr);
362
- }
363
- }
364
-
365
- /**
366
- * @summary Determine which IDs in the id chain are actually referring to namespaces or imports,
367
- * and which are deeper member accessors on the imported object. Only the former should be re-rendered.
368
- * @param {string[]} ids ids
369
- * @param {ModuleGraph} moduleGraph moduleGraph
370
- * @param {HarmonyImportSpecifierDependency} dependency dependency
371
- * @returns {string[]} generated code
372
- */
373
- _trimIdsToThoseImported(ids, moduleGraph, dependency) {
374
- /** @type {string[]} */
375
- let trimmedIds = [];
376
- const exportsInfo = moduleGraph.getExportsInfo(
377
- /** @type {Module} */ (moduleGraph.getModule(dependency))
378
- );
379
- let currentExportsInfo = /** @type {ExportsInfo=} */ exportsInfo;
380
- for (let i = 0; i < ids.length; i++) {
381
- if (i === 0 && ids[i] === "default") {
382
- continue; // ExportInfo for the next level under default is still at the root ExportsInfo, so don't advance currentExportsInfo
383
- }
384
- const exportInfo = currentExportsInfo.getExportInfo(ids[i]);
385
- if (exportInfo.provided === false) {
386
- // json imports have nested ExportInfo for elements that things that are not actually exported, so check .provided
387
- trimmedIds = ids.slice(0, i);
388
- break;
389
- }
390
- const nestedInfo = exportInfo.getNestedExportsInfo();
391
- if (!nestedInfo) {
392
- // once all nested exports are traversed, the next item is the actual import so stop there
393
- trimmedIds = ids.slice(0, i + 1);
394
- break;
395
- }
396
- currentExportsInfo = nestedInfo;
348
+ source.replace(trimmedRangeStart, trimmedRangeEnd - 1, exportExpr);
397
349
  }
398
- // Never trim to nothing. This can happen for invalid imports (e.g. import { notThere } from "./module", or import { anything } from "./missingModule")
399
- return trimmedIds.length ? trimmedIds : ids;
400
350
  }
401
351
 
402
352
  /**
@@ -363,25 +363,27 @@ class JavascriptParser extends Parser {
363
363
  ])
364
364
  ),
365
365
  /** Something like "a.b().c.d" */
366
- /** @type {HookMap<SyncBailHook<[Expression, string[], CallExpression, string[]], boolean | void>>} */
366
+ /** @type {HookMap<SyncBailHook<[Expression, string[], CallExpression, string[], Range[]], boolean | void>>} */
367
367
  memberChainOfCallMemberChain: new HookMap(
368
368
  () =>
369
369
  new SyncBailHook([
370
370
  "expression",
371
371
  "calleeMembers",
372
372
  "callExpression",
373
- "members"
373
+ "members",
374
+ "memberRanges"
374
375
  ])
375
376
  ),
376
377
  /** Something like "a.b().c.d()"" */
377
- /** @type {HookMap<SyncBailHook<[CallExpression, string[], CallExpression, string[]], boolean | void>>} */
378
+ /** @type {HookMap<SyncBailHook<[CallExpression, string[], CallExpression, string[], Range[]], boolean | void>>} */
378
379
  callMemberChainOfCallMemberChain: new HookMap(
379
380
  () =>
380
381
  new SyncBailHook([
381
382
  "expression",
382
383
  "calleeMembers",
383
384
  "innerCallExpression",
384
- "members"
385
+ "members",
386
+ "memberRanges"
385
387
  ])
386
388
  ),
387
389
  /** @type {SyncBailHook<[ChainExpression], boolean | void>} */
@@ -3274,7 +3276,8 @@ class JavascriptParser extends Parser {
3274
3276
  expression,
3275
3277
  exprInfo.getCalleeMembers(),
3276
3278
  exprInfo.call,
3277
- exprInfo.getMembers()
3279
+ exprInfo.getMembers(),
3280
+ exprInfo.getMemberRanges()
3278
3281
  );
3279
3282
  if (result === true) return;
3280
3283
  }
@@ -3365,7 +3368,8 @@ class JavascriptParser extends Parser {
3365
3368
  expression,
3366
3369
  exprInfo.getCalleeMembers(),
3367
3370
  exprInfo.call,
3368
- exprInfo.getMembers()
3371
+ exprInfo.getMembers(),
3372
+ exprInfo.getMemberRanges()
3369
3373
  );
3370
3374
  if (result === true) return;
3371
3375
  // Fast skip over the member chain as we already called memberChainOfCallMemberChain
@@ -0,0 +1,96 @@
1
+ /*
2
+ MIT License http://www.opensource.org/licenses/mit-license.php
3
+ Author Tobias Koppers @sokra
4
+ */
5
+
6
+ "use strict";
7
+
8
+ /** @typedef {import("../Dependency")} Dependency */
9
+ /** @typedef {import("../ModuleGraph")} ModuleGraph */
10
+ /** @typedef {import("../javascript/JavascriptParser").Range} Range */
11
+
12
+ /**
13
+ * @summary Get the subset of ids and their corresponding range in an id chain that should be re-rendered by webpack.
14
+ * Only those in the chain that are actually referring to namespaces or imports should be re-rendered.
15
+ * Deeper member accessors on the imported object should not be re-rendered. If deeper member accessors are re-rendered,
16
+ * there is a potential loss of meaning with rendering a quoted accessor as an unquoted accessor, or vice versa,
17
+ * because minifiers treat quoted accessors differently. e.g. import { a } from "./module"; a["b"] vs a.b
18
+ * @param {string[]} untrimmedIds chained ids
19
+ * @param {Range} untrimmedRange range encompassing allIds
20
+ * @param {Range[]} ranges cumulative range of ids for each of allIds
21
+ * @param {ModuleGraph} moduleGraph moduleGraph
22
+ * @param {Dependency} dependency dependency
23
+ * @returns {{trimmedIds: string[], trimmedRange: Range}} computed trimmed ids and cumulative range of those ids
24
+ */
25
+ exports.getTrimmedIdsAndRange = (
26
+ untrimmedIds,
27
+ untrimmedRange,
28
+ ranges,
29
+ moduleGraph,
30
+ dependency
31
+ ) => {
32
+ let trimmedIds = trimIdsToThoseImported(
33
+ untrimmedIds,
34
+ moduleGraph,
35
+ dependency
36
+ );
37
+ let trimmedRange = untrimmedRange;
38
+ if (trimmedIds.length !== untrimmedIds.length) {
39
+ // The array returned from dep.idRanges is right-aligned with the array returned from dep.names.
40
+ // Meaning, the two arrays may not always have the same number of elements, but the last element of
41
+ // dep.idRanges corresponds to [the expression fragment to the left of] the last element of dep.names.
42
+ // Use this to find the correct replacement range based on the number of ids that were trimmed.
43
+ const idx =
44
+ ranges === undefined
45
+ ? -1 /* trigger failure case below */
46
+ : ranges.length + (trimmedIds.length - untrimmedIds.length);
47
+ if (idx < 0 || idx >= ranges.length) {
48
+ // cspell:ignore minifiers
49
+ // Should not happen but we can't throw an error here because of backward compatibility with
50
+ // external plugins in wp5. Instead, we just disable trimming for now. This may break some minifiers.
51
+ trimmedIds = untrimmedIds;
52
+ // TODO webpack 6 remove the "trimmedIds = ids" above and uncomment the following line instead.
53
+ // throw new Error("Missing range starts data for id replacement trimming.");
54
+ } else {
55
+ trimmedRange = ranges[idx];
56
+ }
57
+ }
58
+
59
+ return { trimmedIds, trimmedRange };
60
+ };
61
+
62
+ /**
63
+ * @summary Determine which IDs in the id chain are actually referring to namespaces or imports,
64
+ * and which are deeper member accessors on the imported object.
65
+ * @param {string[]} ids untrimmed ids
66
+ * @param {ModuleGraph} moduleGraph moduleGraph
67
+ * @param {Dependency} dependency dependency
68
+ * @returns {string[]} trimmed ids
69
+ */
70
+ function trimIdsToThoseImported(ids, moduleGraph, dependency) {
71
+ let trimmedIds = [];
72
+ const exportsInfo = moduleGraph.getExportsInfo(
73
+ moduleGraph.getModule(dependency)
74
+ );
75
+ let currentExportsInfo = /** @type {ExportsInfo=} */ exportsInfo;
76
+ for (let i = 0; i < ids.length; i++) {
77
+ if (i === 0 && ids[i] === "default") {
78
+ continue; // ExportInfo for the next level under default is still at the root ExportsInfo, so don't advance currentExportsInfo
79
+ }
80
+ const exportInfo = currentExportsInfo.getExportInfo(ids[i]);
81
+ if (exportInfo.provided === false) {
82
+ // json imports have nested ExportInfo for elements that things that are not actually exported, so check .provided
83
+ trimmedIds = ids.slice(0, i);
84
+ break;
85
+ }
86
+ const nestedInfo = exportInfo.getNestedExportsInfo();
87
+ if (!nestedInfo) {
88
+ // once all nested exports are traversed, the next item is the actual import so stop there
89
+ trimmedIds = ids.slice(0, i + 1);
90
+ break;
91
+ }
92
+ currentExportsInfo = nestedInfo;
93
+ }
94
+ // Never trim to nothing. This can happen for invalid imports (e.g. import { notThere } from "./module", or import { anything } from "./missingModule")
95
+ return trimmedIds.length ? trimmedIds : ids;
96
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webpack",
3
- "version": "5.88.1",
3
+ "version": "5.89.0",
4
4
  "author": "Tobias Koppers @sokra",
5
5
  "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.",
6
6
  "license": "MIT",
package/types.d.ts CHANGED
@@ -5521,13 +5521,19 @@ declare class JavascriptParser extends Parser {
5521
5521
  >;
5522
5522
  memberChainOfCallMemberChain: HookMap<
5523
5523
  SyncBailHook<
5524
- [Expression, string[], CallExpression, string[]],
5524
+ [Expression, string[], CallExpression, string[], [number, number][]],
5525
5525
  boolean | void
5526
5526
  >
5527
5527
  >;
5528
5528
  callMemberChainOfCallMemberChain: HookMap<
5529
5529
  SyncBailHook<
5530
- [CallExpression, string[], CallExpression, string[]],
5530
+ [
5531
+ CallExpression,
5532
+ string[],
5533
+ CallExpression,
5534
+ string[],
5535
+ [number, number][]
5536
+ ],
5531
5537
  boolean | void
5532
5538
  >
5533
5539
  >;