webpack 5.110.2 → 5.110.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.
- package/README.md +0 -2
- package/lib/ChunkGraph.js +20 -18
- package/lib/Compilation.js +1 -1
- package/lib/ConcatenationScope.js +25 -35
- package/lib/DotenvPlugin.js +41 -13
- package/lib/FlagDependencyUsagePlugin.js +8 -2
- package/lib/NormalModule.js +13 -20
- package/lib/RuntimePlugin.js +3 -0
- package/lib/RuntimeTemplate.js +14 -2
- package/lib/async-modules/AsyncModuleHelpers.js +10 -4
- package/lib/config/defaults.js +26 -16
- package/lib/config/normalization.js +18 -8
- package/lib/dependencies/CommonJsRequireDependency.js +18 -4
- package/lib/dependencies/ContextDependencyTemplateAsRequireCall.js +20 -7
- package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +100 -19
- package/lib/dependencies/HarmonyImportDependency.js +94 -41
- package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +12 -2
- package/lib/dependencies/HtmlEntryDependency.js +12 -2
- package/lib/dependencies/ImportContextDependency.js +43 -3
- package/lib/dependencies/ImportDependency.js +8 -29
- package/lib/dependencies/ImportParserPlugin.js +24 -14
- package/lib/dependencies/RequireHeaderDependency.js +20 -21
- package/lib/dependencies/importOptionsCheck.js +47 -0
- package/lib/errors/DotenvFileError.js +29 -0
- package/lib/errors/ImportedBindingAssignmentError.js +30 -0
- package/lib/html/HtmlModulesPlugin.js +29 -22
- package/lib/html/syntax.js +304 -143
- package/lib/javascript/JavascriptModulesPlugin.js +2 -0
- package/lib/optimize/ConcatenatedModule.js +38 -7
- package/lib/prefetch/ResourceHintPlugin.js +6 -1
- package/lib/runtime/AsyncModuleRuntimeModule.js +5 -1
- package/lib/runtime/MakeDeferredNamespaceObjectRuntime.js +11 -1
- package/lib/schemes/HttpUriPlugin.js +22 -5
- package/lib/serialization/FileMiddleware.js +15 -2
- package/lib/util/ArrayQueue.js +3 -3
- package/lib/util/URLAbsoluteSpecifier.js +3 -1
- package/lib/util/conventions.js +5 -1
- package/lib/util/internalSerializables.js +2 -0
- package/package.json +1 -1
- package/schemas/WebpackOptions.check.js +1 -1
- package/schemas/WebpackOptions.json +9 -10
- package/types.d.ts +26 -17
|
@@ -22,11 +22,9 @@ class ContextDependencyTemplateAsRequireCall
|
|
|
22
22
|
* @param {DependencyTemplateContext} templateContext the context object
|
|
23
23
|
* @returns {void}
|
|
24
24
|
*/
|
|
25
|
-
apply(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
{ runtimeTemplate, moduleGraph, chunkGraph, runtimeRequirements }
|
|
29
|
-
) {
|
|
25
|
+
apply(dependency, source, templateContext) {
|
|
26
|
+
const { runtimeTemplate, moduleGraph, chunkGraph, runtimeRequirements } =
|
|
27
|
+
templateContext;
|
|
30
28
|
const dep = /** @type {ContextDependency} */ (dependency);
|
|
31
29
|
let moduleExports = runtimeTemplate.moduleExports({
|
|
32
30
|
module: moduleGraph.getModule(dep),
|
|
@@ -49,8 +47,7 @@ class ContextDependencyTemplateAsRequireCall
|
|
|
49
47
|
source.replace(rep.range[0], rep.range[1] - 1, rep.value);
|
|
50
48
|
}
|
|
51
49
|
}
|
|
52
|
-
|
|
53
|
-
source.replace(range[0], dep.valueRange[0] - 1, `${moduleExports}(`);
|
|
50
|
+
this.replaceCall(dep, source, moduleExports, templateContext);
|
|
54
51
|
} else {
|
|
55
52
|
source.replace(range[0], range[1] - 1, moduleExports);
|
|
56
53
|
}
|
|
@@ -58,6 +55,22 @@ class ContextDependencyTemplateAsRequireCall
|
|
|
58
55
|
source.replace(range[0], range[1] - 1, moduleExports);
|
|
59
56
|
}
|
|
60
57
|
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Rewrites the call around its request, dropping anything the original one
|
|
61
|
+
* carried after it. Overridden where a later argument must be kept.
|
|
62
|
+
* @param {ContextDependency} dep the dependency
|
|
63
|
+
* @param {ReplaceSource} source the current replace source which can be modified
|
|
64
|
+
* @param {string} moduleExports the expression the request is passed to
|
|
65
|
+
* @param {DependencyTemplateContext} templateContext the context object
|
|
66
|
+
* @returns {void}
|
|
67
|
+
*/
|
|
68
|
+
replaceCall(dep, source, moduleExports, templateContext) {
|
|
69
|
+
const range = /** @type {Range} */ (dep.range);
|
|
70
|
+
const valueRange = /** @type {Range} */ (dep.valueRange);
|
|
71
|
+
source.replace(valueRange[1], range[1] - 1, ")");
|
|
72
|
+
source.replace(range[0], valueRange[0] - 1, `${moduleExports}(`);
|
|
73
|
+
}
|
|
61
74
|
}
|
|
62
75
|
|
|
63
76
|
module.exports = ContextDependencyTemplateAsRequireCall;
|
|
@@ -237,12 +237,28 @@ const isStarReexportBackToParent = (moduleGraph, exportInfo, parentModule) => {
|
|
|
237
237
|
}
|
|
238
238
|
};
|
|
239
239
|
|
|
240
|
+
/**
|
|
241
|
+
* Two `export *` sources are ambiguous for a name when they resolve to
|
|
242
|
+
* different bindings; a diamond re-export of the same binding is not.
|
|
243
|
+
* @param {ModuleGraph} moduleGraph module graph
|
|
244
|
+
* @param {InstanceType<ExportInfo>} previous export info of the star source that first provided the name
|
|
245
|
+
* @param {InstanceType<ExportInfo>} exportInfo export info of a later star source providing the same name
|
|
246
|
+
* @returns {boolean} true when the two sources provide different bindings
|
|
247
|
+
*/
|
|
248
|
+
const isAmbiguousWith = (moduleGraph, previous, exportInfo) => {
|
|
249
|
+
const previousBinding = previous.getTerminalBinding(moduleGraph);
|
|
250
|
+
if (!previousBinding) return false;
|
|
251
|
+
const binding = exportInfo.getTerminalBinding(moduleGraph);
|
|
252
|
+
if (!binding) return false;
|
|
253
|
+
return previousBinding !== binding;
|
|
254
|
+
};
|
|
255
|
+
|
|
240
256
|
/**
|
|
241
257
|
* Determine export assignments.
|
|
242
258
|
* @param {ModuleGraph} moduleGraph module graph
|
|
243
259
|
* @param {HarmonyExportImportedSpecifierDependency[]} dependencies dependencies
|
|
244
260
|
* @param {HarmonyExportImportedSpecifierDependency=} additionalDependency additional dependency
|
|
245
|
-
* @returns {{ names: ExportInfoName[], dependencyIndices: DependencyIndices }} result
|
|
261
|
+
* @returns {{ names: ExportInfoName[], dependencyIndices: DependencyIndices, conflicting: Set<ExportInfoName> | undefined }} result
|
|
246
262
|
*/
|
|
247
263
|
const determineExportAssignments = (
|
|
248
264
|
moduleGraph,
|
|
@@ -253,6 +269,10 @@ const determineExportAssignments = (
|
|
|
253
269
|
const names = new Set();
|
|
254
270
|
/** @type {DependencyIndices} */
|
|
255
271
|
const dependencyIndices = [];
|
|
272
|
+
/** @type {Map<ExportInfoName, InstanceType<ExportInfo>>} */
|
|
273
|
+
const firstProvider = new Map();
|
|
274
|
+
/** @type {Set<ExportInfoName> | undefined} */
|
|
275
|
+
let conflicting;
|
|
256
276
|
|
|
257
277
|
if (additionalDependency) {
|
|
258
278
|
dependencies = [...dependencies, additionalDependency];
|
|
@@ -270,24 +290,42 @@ const determineExportAssignments = (
|
|
|
270
290
|
if (otherImportedModule) {
|
|
271
291
|
const exportsInfo = moduleGraph.getExportsInfo(otherImportedModule);
|
|
272
292
|
for (const exportInfo of exportsInfo.exports) {
|
|
293
|
+
if (exportInfo.provided !== true || exportInfo.name === "default") {
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
if (names.has(exportInfo.name)) {
|
|
297
|
+
const previous =
|
|
298
|
+
/** @type {InstanceType<ExportInfo>} */
|
|
299
|
+
(firstProvider.get(exportInfo.name));
|
|
300
|
+
if (
|
|
301
|
+
isAmbiguousWith(moduleGraph, previous, exportInfo) &&
|
|
302
|
+
// A cyclic contribution resolves to nothing, so it never competes
|
|
303
|
+
// with the binding a sibling `export *` provides.
|
|
304
|
+
!(
|
|
305
|
+
parentModule &&
|
|
306
|
+
isStarReexportBackToParent(moduleGraph, exportInfo, parentModule)
|
|
307
|
+
)
|
|
308
|
+
) {
|
|
309
|
+
if (conflicting === undefined) conflicting = new Set();
|
|
310
|
+
conflicting.add(exportInfo.name);
|
|
311
|
+
}
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
273
314
|
if (
|
|
274
|
-
|
|
275
|
-
exportInfo
|
|
276
|
-
!names.has(exportInfo.name) &&
|
|
277
|
-
!(
|
|
278
|
-
parentModule &&
|
|
279
|
-
isStarReexportBackToParent(moduleGraph, exportInfo, parentModule)
|
|
280
|
-
)
|
|
315
|
+
parentModule &&
|
|
316
|
+
isStarReexportBackToParent(moduleGraph, exportInfo, parentModule)
|
|
281
317
|
) {
|
|
282
|
-
|
|
283
|
-
dependencyIndices[i] = names.size;
|
|
318
|
+
continue;
|
|
284
319
|
}
|
|
320
|
+
names.add(exportInfo.name);
|
|
321
|
+
firstProvider.set(exportInfo.name, exportInfo);
|
|
322
|
+
dependencyIndices[i] = names.size;
|
|
285
323
|
}
|
|
286
324
|
}
|
|
287
325
|
}
|
|
288
326
|
dependencyIndices.push(names.size);
|
|
289
327
|
|
|
290
|
-
return { names: [...names], dependencyIndices };
|
|
328
|
+
return { names: [...names], dependencyIndices, conflicting };
|
|
291
329
|
};
|
|
292
330
|
|
|
293
331
|
/**
|
|
@@ -666,6 +704,12 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
|
|
|
666
704
|
/** @type {IgnoredExports} */
|
|
667
705
|
const ignoredExports = new Set(this.activeExports);
|
|
668
706
|
ignoredExports.add("default");
|
|
707
|
+
// An ambiguous name resolves to no binding at all, so no `export *` in this
|
|
708
|
+
// module may contribute it — not even the first one.
|
|
709
|
+
const conflicting = this._getConflictingStarExportNames(moduleGraph);
|
|
710
|
+
if (conflicting !== undefined) {
|
|
711
|
+
for (const name of conflicting) ignoredExports.add(name);
|
|
712
|
+
}
|
|
669
713
|
|
|
670
714
|
/** @type {Hidden | undefined} */
|
|
671
715
|
let hiddenExports;
|
|
@@ -871,6 +915,21 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
|
|
|
871
915
|
}
|
|
872
916
|
}
|
|
873
917
|
|
|
918
|
+
/**
|
|
919
|
+
* Names this module's `export *` sources provide with conflicting bindings.
|
|
920
|
+
* @param {ModuleGraph} moduleGraph the module graph
|
|
921
|
+
* @returns {Set<ExportInfoName> | undefined} ambiguous names, or nothing when there are none
|
|
922
|
+
*/
|
|
923
|
+
_getConflictingStarExportNames(moduleGraph) {
|
|
924
|
+
// Every `export *` carries the module's full star list; a lone one has
|
|
925
|
+
// nothing to be ambiguous with, so skip the walk.
|
|
926
|
+
if (!this.allStarExports) return;
|
|
927
|
+
const { dependencies } = this.allStarExports;
|
|
928
|
+
if (dependencies.length < 2) return;
|
|
929
|
+
return moduleGraph.cached(determineExportAssignments, dependencies)
|
|
930
|
+
.conflicting;
|
|
931
|
+
}
|
|
932
|
+
|
|
874
933
|
/**
|
|
875
934
|
* Discover active exports from other star exports.
|
|
876
935
|
* @param {ModuleGraph} moduleGraph the module graph
|
|
@@ -1072,7 +1131,10 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
|
|
|
1072
1131
|
*/
|
|
1073
1132
|
getWarnings(moduleGraph) {
|
|
1074
1133
|
const exportsPresence = this._getEffectiveExportPresenceLevel(moduleGraph);
|
|
1075
|
-
const circular =
|
|
1134
|
+
const circular =
|
|
1135
|
+
this._getCircularReexportPresenceLevel() === ExportPresenceModes.WARN
|
|
1136
|
+
? this._getCircularReexportErrors(moduleGraph)
|
|
1137
|
+
: undefined;
|
|
1076
1138
|
if (exportsPresence === ExportPresenceModes.WARN) {
|
|
1077
1139
|
const errors = this._getErrors(moduleGraph);
|
|
1078
1140
|
if (!circular) return errors;
|
|
@@ -1082,12 +1144,23 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
|
|
|
1082
1144
|
}
|
|
1083
1145
|
|
|
1084
1146
|
/**
|
|
1085
|
-
*
|
|
1086
|
-
*
|
|
1147
|
+
* Reporting level for a circular reexport chain. It skips the promotion to
|
|
1148
|
+
* an error that AUTO gives a strict harmony module — a cycle warns by
|
|
1149
|
+
* default — but an explicit setting still says whether and how to report.
|
|
1150
|
+
* @returns {ExportPresenceMode} effective mode
|
|
1151
|
+
*/
|
|
1152
|
+
_getCircularReexportPresenceLevel() {
|
|
1153
|
+
return this.exportPresenceMode === ExportPresenceModes.AUTO
|
|
1154
|
+
? ExportPresenceModes.WARN
|
|
1155
|
+
: this.exportPresenceMode;
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
/**
|
|
1159
|
+
* Returns errors for a name resolving through a circular reexport chain.
|
|
1087
1160
|
* @param {ModuleGraph} moduleGraph module graph
|
|
1088
|
-
* @returns {WebpackError[] | undefined}
|
|
1161
|
+
* @returns {WebpackError[] | undefined} errors
|
|
1089
1162
|
*/
|
|
1090
|
-
|
|
1163
|
+
_getCircularReexportErrors(moduleGraph) {
|
|
1091
1164
|
const ids = this.getIds(moduleGraph);
|
|
1092
1165
|
if (ids.length === 0 || !this.name) return;
|
|
1093
1166
|
const parentModule = /** @type {Module} */ (
|
|
@@ -1115,10 +1188,18 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
|
|
|
1115
1188
|
*/
|
|
1116
1189
|
getErrors(moduleGraph) {
|
|
1117
1190
|
const exportsPresence = this._getEffectiveExportPresenceLevel(moduleGraph);
|
|
1118
|
-
|
|
1119
|
-
|
|
1191
|
+
const errors =
|
|
1192
|
+
exportsPresence === ExportPresenceModes.ERROR
|
|
1193
|
+
? this._getErrors(moduleGraph)
|
|
1194
|
+
: null;
|
|
1195
|
+
if (
|
|
1196
|
+
this._getCircularReexportPresenceLevel() !== ExportPresenceModes.ERROR
|
|
1197
|
+
) {
|
|
1198
|
+
return errors;
|
|
1120
1199
|
}
|
|
1121
|
-
|
|
1200
|
+
const circular = this._getCircularReexportErrors(moduleGraph);
|
|
1201
|
+
if (!circular) return errors;
|
|
1202
|
+
return errors ? [...errors, ...circular] : circular;
|
|
1122
1203
|
}
|
|
1123
1204
|
|
|
1124
1205
|
/**
|
|
@@ -11,11 +11,14 @@ const InitFragment = require("../InitFragment");
|
|
|
11
11
|
const Template = require("../Template");
|
|
12
12
|
const AwaitDependenciesInitFragment = require("../async-modules/AwaitDependenciesInitFragment");
|
|
13
13
|
const isGeneratorLowered = require("../async-modules/isGeneratorLowered");
|
|
14
|
+
const memoize = require("../util/memoize");
|
|
14
15
|
const { filterRuntime, mergeRuntime } = require("../util/runtime");
|
|
15
16
|
const HarmonyLinkingError = require("./HarmonyLinkingError");
|
|
16
17
|
const { ImportPhase, ImportPhaseUtils } = require("./ImportPhase");
|
|
17
18
|
const ModuleDependency = require("./ModuleDependency");
|
|
18
19
|
|
|
20
|
+
const getExternalModule = memoize(() => require("../ExternalModule"));
|
|
21
|
+
|
|
19
22
|
/** @import { ReplaceSource } from "webpack-sources" */
|
|
20
23
|
/**
|
|
21
24
|
* @import {
|
|
@@ -97,6 +100,31 @@ const getNonOptionalPart = (members, membersOptionals) => {
|
|
|
97
100
|
|
|
98
101
|
/** @typedef {string[]} Ids */
|
|
99
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Export names a lazy barrel still defers, so they are missing from its provided
|
|
105
|
+
* exports without being absent from the module.
|
|
106
|
+
* @param {Module} module the imported module
|
|
107
|
+
* @returns {Set<string> | true | undefined} deferred names, true when a deferred star re-export may provide any name, undefined when none
|
|
108
|
+
*/
|
|
109
|
+
const getDeferredExports = (module) => {
|
|
110
|
+
const factoryMeta = module.factoryMeta;
|
|
111
|
+
if (factoryMeta === undefined || !factoryMeta.sideEffectFree) return;
|
|
112
|
+
/** @type {Set<string> | undefined} */
|
|
113
|
+
let names;
|
|
114
|
+
for (const dep of module.dependencies) {
|
|
115
|
+
// TODO remove in webpack 6
|
|
116
|
+
// These may be missing on custom dependency types not extending the base Dependency
|
|
117
|
+
if (!("getLazyUntil" in dep) || !("isLazy" in dep)) continue;
|
|
118
|
+
if (!dep.isLazy()) continue;
|
|
119
|
+
const until = dep.getLazyUntil();
|
|
120
|
+
if (until === Dependency.LAZY_UNTIL_FALLBACK) return true;
|
|
121
|
+
if (until !== Dependency.LAZY_UNTIL_ID) continue;
|
|
122
|
+
if (names === undefined) names = new Set();
|
|
123
|
+
names.add(/** @type {string} */ (dep.getLazyName()));
|
|
124
|
+
}
|
|
125
|
+
return names;
|
|
126
|
+
};
|
|
127
|
+
|
|
100
128
|
class HarmonyImportDependency extends ModuleDependency {
|
|
101
129
|
/**
|
|
102
130
|
* Creates an instance of HarmonyImportDependency.
|
|
@@ -185,9 +213,14 @@ class HarmonyImportDependency extends ModuleDependency {
|
|
|
185
213
|
const importedModule = /** @type {Module} */ (moduleGraph.getModule(this));
|
|
186
214
|
const meta = moduleGraph.getMeta(module);
|
|
187
215
|
|
|
216
|
+
// An async external is a promise webpack awaits, not a module record with
|
|
217
|
+
// an evaluating state, so deferring its namespace would never throw.
|
|
188
218
|
const isDeferred =
|
|
189
219
|
ImportPhaseUtils.isDefer(this.phase) &&
|
|
190
|
-
!(
|
|
220
|
+
!(
|
|
221
|
+
/** @type {BuildMeta} */ (importedModule.buildMeta).async &&
|
|
222
|
+
importedModule instanceof getExternalModule()
|
|
223
|
+
);
|
|
191
224
|
|
|
192
225
|
const metaKey = isDeferred ? "deferredImportVarMap" : "importVarMap";
|
|
193
226
|
let importVarMap = meta[metaKey];
|
|
@@ -283,48 +316,63 @@ class HarmonyImportDependency extends ModuleDependency {
|
|
|
283
316
|
(exportsType !== "default-with-named" || ids[0] !== "default") &&
|
|
284
317
|
moduleGraph.isExportProvided(importedModule, ids) === false
|
|
285
318
|
) {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
319
|
+
const deferredExports = getDeferredExports(importedModule);
|
|
320
|
+
|
|
321
|
+
if (
|
|
322
|
+
deferredExports !== true &&
|
|
323
|
+
(deferredExports === undefined || !deferredExports.has(ids[0]))
|
|
324
|
+
) {
|
|
325
|
+
// We are sure that it's not provided
|
|
326
|
+
|
|
327
|
+
// Try to provide detailed info in the error message
|
|
328
|
+
let pos = 0;
|
|
329
|
+
let exportsInfo = moduleGraph.getExportsInfo(importedModule);
|
|
330
|
+
while (pos < ids.length && exportsInfo) {
|
|
331
|
+
const id = ids[pos++];
|
|
332
|
+
const exportInfo = exportsInfo.getReadOnlyExportInfo(id);
|
|
333
|
+
if (exportInfo.provided === false) {
|
|
334
|
+
// We are sure that it's not provided
|
|
335
|
+
let providedExports = exportsInfo.getProvidedExports();
|
|
336
|
+
// only the first level names the imported module itself
|
|
337
|
+
if (
|
|
338
|
+
pos === 1 &&
|
|
339
|
+
deferredExports !== undefined &&
|
|
340
|
+
Array.isArray(providedExports)
|
|
341
|
+
) {
|
|
342
|
+
providedExports = [...providedExports, ...deferredExports];
|
|
343
|
+
}
|
|
344
|
+
const moreInfo = !Array.isArray(providedExports)
|
|
345
|
+
? " (possible exports unknown)"
|
|
346
|
+
: providedExports.length === 0
|
|
347
|
+
? " (module has no exports)"
|
|
348
|
+
: ` (possible exports: ${providedExports.join(", ")})`;
|
|
349
|
+
return [
|
|
350
|
+
new HarmonyLinkingError(
|
|
351
|
+
`export ${ids
|
|
352
|
+
.slice(0, pos)
|
|
353
|
+
.map((id) => `'${id}'`)
|
|
354
|
+
.join(".")} ${additionalMessage} was not found in '${
|
|
355
|
+
this.userRequest
|
|
356
|
+
}'${moreInfo}`
|
|
357
|
+
)
|
|
358
|
+
];
|
|
359
|
+
}
|
|
360
|
+
exportsInfo =
|
|
361
|
+
/** @type {ExportsInfo} */
|
|
362
|
+
(exportInfo.getNestedExportsInfo());
|
|
312
363
|
}
|
|
313
|
-
exportsInfo =
|
|
314
|
-
/** @type {ExportsInfo} */
|
|
315
|
-
(exportInfo.getNestedExportsInfo());
|
|
316
|
-
}
|
|
317
364
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
365
|
+
// General error message
|
|
366
|
+
return [
|
|
367
|
+
new HarmonyLinkingError(
|
|
368
|
+
`export ${ids
|
|
369
|
+
.map((id) => `'${id}'`)
|
|
370
|
+
.join(".")} ${additionalMessage} was not found in '${
|
|
371
|
+
this.userRequest
|
|
372
|
+
}'`
|
|
373
|
+
)
|
|
374
|
+
];
|
|
375
|
+
}
|
|
328
376
|
}
|
|
329
377
|
}
|
|
330
378
|
switch (exportsType) {
|
|
@@ -468,8 +516,13 @@ HarmonyImportDependency.Template = class HarmonyImportDependencyTemplate extends
|
|
|
468
516
|
}
|
|
469
517
|
|
|
470
518
|
const importStatement = dep.getImportStatement(false, templateContext);
|
|
519
|
+
// A module deferring itself is already evaluating: awaiting it would probe
|
|
520
|
+
// the deferred namespace and force the evaluation it must not trigger.
|
|
521
|
+
const isSelfDeferred =
|
|
522
|
+
ImportPhaseUtils.isDefer(dep.phase) && referencedModule === module;
|
|
471
523
|
if (
|
|
472
524
|
referencedModule &&
|
|
525
|
+
!isSelfDeferred &&
|
|
473
526
|
templateContext.moduleGraph.isAsync(referencedModule)
|
|
474
527
|
) {
|
|
475
528
|
templateContext.initFragments.push(
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
"use strict";
|
|
7
7
|
|
|
8
|
+
const ImportedBindingAssignmentError = require("../errors/ImportedBindingAssignmentError");
|
|
8
9
|
const WebpackError = require("../errors/WebpackError");
|
|
9
10
|
const getParserHooks = require("../hmr/parserHooks");
|
|
10
11
|
const {
|
|
@@ -393,11 +394,20 @@ class HarmonyImportDependencyParserPlugin {
|
|
|
393
394
|
);
|
|
394
395
|
// Concatenation would turn the binding into a plain local, losing the
|
|
395
396
|
// getter-only property whose write throws.
|
|
396
|
-
parser.hooks.assign.for(harmonySpecifierTag).tap(PLUGIN_NAME, () => {
|
|
397
|
-
|
|
397
|
+
parser.hooks.assign.for(harmonySpecifierTag).tap(PLUGIN_NAME, (expr) => {
|
|
398
|
+
const settings = /** @type {HarmonySettings} */ (parser.currentTagData);
|
|
399
|
+
markUsed(settings);
|
|
398
400
|
/** @type {JavascriptModuleBuildInfo} */
|
|
399
401
|
(parser.state.module.buildInfo).moduleConcatenationBailout =
|
|
400
402
|
"assignment to an imported binding";
|
|
403
|
+
// A named import is written through the namespace's getter-only
|
|
404
|
+
// property, which throws on its own. A namespace one is the binding
|
|
405
|
+
// itself, and nothing webpack can emit for it throws, so report it.
|
|
406
|
+
if (settings.ids.length === 0) {
|
|
407
|
+
const error = new ImportedBindingAssignmentError(settings.name);
|
|
408
|
+
error.loc = parser.getLocation(expr);
|
|
409
|
+
parser.state.module.addError(error);
|
|
410
|
+
}
|
|
401
411
|
});
|
|
402
412
|
parser.hooks.expression
|
|
403
413
|
.for(harmonySpecifierTag)
|
|
@@ -194,7 +194,12 @@ const getEntrypointChunksInLoadOrder = (entrypoint) => {
|
|
|
194
194
|
const chunksLoadedByAncestorTags = new Set();
|
|
195
195
|
/** @type {Set<import("../ChunkGroup")>} */
|
|
196
196
|
const visitedGroups = new Set();
|
|
197
|
-
|
|
197
|
+
/**
|
|
198
|
+
* Collects the chunks an ancestor entry's own tags already load.
|
|
199
|
+
* @param {import("../ChunkGroup")} group chunk group to walk up from
|
|
200
|
+
* @returns {void}
|
|
201
|
+
*/
|
|
202
|
+
const walk = (group) => {
|
|
198
203
|
if (visitedGroups.has(group)) return;
|
|
199
204
|
visitedGroups.add(group);
|
|
200
205
|
for (const parent of group.parentsIterable) {
|
|
@@ -220,7 +225,12 @@ const getEntrypointChunksInLoadOrder = (entrypoint) => {
|
|
|
220
225
|
const ordered = [];
|
|
221
226
|
/** @type {Set<Chunk>} */
|
|
222
227
|
const seen = new Set();
|
|
223
|
-
|
|
228
|
+
/**
|
|
229
|
+
* Appends a chunk once, skipping the ones an ancestor entry already loads.
|
|
230
|
+
* @param {Chunk | null | undefined} chunk chunk to append
|
|
231
|
+
* @returns {void}
|
|
232
|
+
*/
|
|
233
|
+
const push = (chunk) => {
|
|
224
234
|
if (!chunk || seen.has(chunk) || chunk === entryChunk) return;
|
|
225
235
|
if (chunksLoadedByAncestorTags.has(chunk)) return;
|
|
226
236
|
seen.add(chunk);
|
|
@@ -8,11 +8,13 @@
|
|
|
8
8
|
const makeSerializable = require("../util/makeSerializable");
|
|
9
9
|
const ContextDependency = require("./ContextDependency");
|
|
10
10
|
const ContextDependencyTemplateAsRequireCall = require("./ContextDependencyTemplateAsRequireCall");
|
|
11
|
+
const importOptionsCheck = require("./importOptionsCheck");
|
|
11
12
|
|
|
12
13
|
/** @import { Range } from "../javascript/JavascriptParser" */
|
|
13
|
-
/** @
|
|
14
|
-
/** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext<[Range]>} ObjectSerializerContext */
|
|
14
|
+
/** @import { ObjectDeserializerContext, ObjectSerializerContext } from "../serialization/ObjectMiddleware" */
|
|
15
15
|
/** @import { ContextDependencyOptions } from "./ContextDependency" */
|
|
16
|
+
/** @import { ReplaceSource } from "webpack-sources" */
|
|
17
|
+
/** @import { DependencyTemplateContext } from "../DependencyTemplate" */
|
|
16
18
|
|
|
17
19
|
class ImportContextDependency extends ContextDependency {
|
|
18
20
|
/**
|
|
@@ -26,6 +28,8 @@ class ImportContextDependency extends ContextDependency {
|
|
|
26
28
|
|
|
27
29
|
this.range = range;
|
|
28
30
|
this.valueRange = valueRange;
|
|
31
|
+
/** @type {Range | undefined} */
|
|
32
|
+
this.optionsRange = undefined;
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
get type() {
|
|
@@ -56,6 +60,7 @@ class ImportContextDependency extends ContextDependency {
|
|
|
56
60
|
*/
|
|
57
61
|
serialize(context) {
|
|
58
62
|
context.write(this.valueRange);
|
|
63
|
+
context.write(this.optionsRange);
|
|
59
64
|
|
|
60
65
|
super.serialize(context);
|
|
61
66
|
}
|
|
@@ -66,6 +71,7 @@ class ImportContextDependency extends ContextDependency {
|
|
|
66
71
|
*/
|
|
67
72
|
deserialize(context) {
|
|
68
73
|
this.valueRange = context.read();
|
|
74
|
+
this.optionsRange = context.read();
|
|
69
75
|
|
|
70
76
|
super.deserialize(context.rest);
|
|
71
77
|
}
|
|
@@ -76,6 +82,40 @@ makeSerializable(
|
|
|
76
82
|
"webpack/lib/dependencies/ImportContextDependency"
|
|
77
83
|
);
|
|
78
84
|
|
|
79
|
-
ImportContextDependency.Template =
|
|
85
|
+
ImportContextDependency.Template = class ImportContextDependencyTemplate extends (
|
|
86
|
+
ContextDependencyTemplateAsRequireCall
|
|
87
|
+
) {
|
|
88
|
+
/**
|
|
89
|
+
* Rewrites the call around its request, dropping anything the original one
|
|
90
|
+
* carried after it. Overridden where a later argument must be kept.
|
|
91
|
+
* @param {ContextDependency} dep the dependency
|
|
92
|
+
* @param {ReplaceSource} source the current replace source which can be modified
|
|
93
|
+
* @param {string} moduleExports the expression the request is passed to
|
|
94
|
+
* @param {DependencyTemplateContext} templateContext the context object
|
|
95
|
+
* @returns {void}
|
|
96
|
+
*/
|
|
97
|
+
replaceCall(dep, source, moduleExports, templateContext) {
|
|
98
|
+
const optionsRange = /** @type {ImportContextDependency} */ (dep)
|
|
99
|
+
.optionsRange;
|
|
100
|
+
if (optionsRange === undefined) {
|
|
101
|
+
super.replaceCall(dep, source, moduleExports, templateContext);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
// Request then options, in that order; their own source is kept so
|
|
105
|
+
// nested dependencies in them still get their replacements.
|
|
106
|
+
const range = /** @type {Range} */ (dep.range);
|
|
107
|
+
const valueRange = /** @type {Range} */ (dep.valueRange);
|
|
108
|
+
const check = importOptionsCheck(
|
|
109
|
+
templateContext.runtimeTemplate,
|
|
110
|
+
["r", "o"],
|
|
111
|
+
`${moduleExports}(r)`
|
|
112
|
+
);
|
|
113
|
+
source.replace(range[0], valueRange[0] - 1, `(${check})(`);
|
|
114
|
+
// The options range excludes any parentheses the source had, so a comma
|
|
115
|
+
// expression would otherwise split into arguments of its own.
|
|
116
|
+
source.replace(valueRange[1], optionsRange[0] - 1, ", (");
|
|
117
|
+
source.replace(optionsRange[1], range[1] - 1, "))");
|
|
118
|
+
}
|
|
119
|
+
};
|
|
80
120
|
|
|
81
121
|
module.exports = ImportContextDependency;
|
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
"use strict";
|
|
7
7
|
|
|
8
8
|
const Dependency = require("../Dependency");
|
|
9
|
-
const Template = require("../Template");
|
|
10
9
|
const makeSerializable = require("../util/makeSerializable");
|
|
11
10
|
const HarmonyImportGuard = require("./HarmonyImportGuard");
|
|
12
11
|
const { ImportPhaseUtils } = require("./ImportPhase");
|
|
13
12
|
const ModuleDependency = require("./ModuleDependency");
|
|
13
|
+
const importOptionsCheck = require("./importOptionsCheck");
|
|
14
14
|
|
|
15
15
|
/** @import { ReplaceSource } from "webpack-sources" */
|
|
16
16
|
/** @import AsyncDependenciesBlock from "../AsyncDependenciesBlock" */
|
|
@@ -226,35 +226,14 @@ ImportDependency.Template = class ImportDependencyTemplate extends (
|
|
|
226
226
|
}
|
|
227
227
|
|
|
228
228
|
// A non-static second argument must still be evaluated (for its side
|
|
229
|
-
// effects and evaluation order) and
|
|
230
|
-
// and wrap it
|
|
231
|
-
// the spec's `import(specifier, options)` evaluation.
|
|
229
|
+
// effects and evaluation order) and checked per spec, so keep it in place
|
|
230
|
+
// and wrap it.
|
|
232
231
|
if (dep.optionsRange) {
|
|
233
|
-
const
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
'if ((typeof o !== "object" && typeof o !== "function") || o === null) throw new TypeError("The second argument to import() must be an object");',
|
|
239
|
-
'var a = o["with"];',
|
|
240
|
-
"if (a !== undefined) {",
|
|
241
|
-
Template.indent([
|
|
242
|
-
'if ((typeof a !== "object" && typeof a !== "function") || a === null) throw new TypeError("The \'with\' option must be an object");',
|
|
243
|
-
"for (var k = Object.keys(a), i = 0; i < k.length; i++) {",
|
|
244
|
-
Template.indent([
|
|
245
|
-
'if (typeof a[k[i]] !== "string") throw new TypeError("Import attribute values must be strings");'
|
|
246
|
-
]),
|
|
247
|
-
"}"
|
|
248
|
-
]),
|
|
249
|
-
"}"
|
|
250
|
-
]),
|
|
251
|
-
"}"
|
|
252
|
-
]),
|
|
253
|
-
"} catch (e) { return Promise.reject(e); }",
|
|
254
|
-
`return ${content};`
|
|
255
|
-
]);
|
|
256
|
-
source.replace(dep.range[0], dep.optionsRange[0] - 1, `(${validator})(`);
|
|
257
|
-
source.replace(dep.optionsRange[1], dep.range[1] - 1, ")");
|
|
232
|
+
const check = importOptionsCheck(runtimeTemplate, ["o"], content);
|
|
233
|
+
// The options range excludes any parentheses the source had, so a
|
|
234
|
+
// comma expression would otherwise split into arguments of its own.
|
|
235
|
+
source.replace(dep.range[0], dep.optionsRange[0] - 1, `(${check})((`);
|
|
236
|
+
source.replace(dep.optionsRange[1], dep.range[1] - 1, "))");
|
|
258
237
|
return;
|
|
259
238
|
}
|
|
260
239
|
|
|
@@ -209,20 +209,18 @@ const isStaticStringAttributes = (node) => {
|
|
|
209
209
|
: key.type === "Literal"
|
|
210
210
|
? key.value
|
|
211
211
|
: undefined;
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
return false;
|
|
225
|
-
}
|
|
212
|
+
// Any other key is an expression webpack cannot account for, and its
|
|
213
|
+
// value still evaluates, so the argument has to stay.
|
|
214
|
+
if (keyName !== "with" && keyName !== "assert") return false;
|
|
215
|
+
const value = prop.value;
|
|
216
|
+
if (value.type !== "ObjectExpression") return false;
|
|
217
|
+
for (const attr of value.properties) {
|
|
218
|
+
if (attr.type !== "Property" || attr.kind !== "init" || attr.computed) {
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
const attrValue = attr.value;
|
|
222
|
+
if (attrValue.type !== "Literal" || typeof attrValue.value !== "string") {
|
|
223
|
+
return false;
|
|
226
224
|
}
|
|
227
225
|
}
|
|
228
226
|
}
|
|
@@ -676,6 +674,18 @@ class ImportParserPlugin {
|
|
|
676
674
|
parser
|
|
677
675
|
);
|
|
678
676
|
if (!dep) return;
|
|
677
|
+
// The context module ignores the options argument, but the spec
|
|
678
|
+
// evaluates it, so anything but a static attributes object stays.
|
|
679
|
+
const optionsNode = expr.options;
|
|
680
|
+
if (
|
|
681
|
+
optionsNode &&
|
|
682
|
+
optionsNode.range &&
|
|
683
|
+
!isStaticStringAttributes(optionsNode)
|
|
684
|
+
) {
|
|
685
|
+
/** @type {ImportContextDependency} */ (dep).optionsRange =
|
|
686
|
+
/** @type {Range} */ (optionsNode.range);
|
|
687
|
+
parser.walkExpression(optionsNode);
|
|
688
|
+
}
|
|
679
689
|
dep.loc = parser.getLocation(expr);
|
|
680
690
|
dep.optional = Boolean(parser.scope.inTry);
|
|
681
691
|
parser.state.current.addDependency(dep);
|