source: frontend/node_modules/webpack/lib/dependencies/HarmonyImportDependency.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 11 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 15.2 KB
Line 
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const ConditionalInitFragment = require("../ConditionalInitFragment");
9const Dependency = require("../Dependency");
10const InitFragment = require("../InitFragment");
11const Template = require("../Template");
12const AwaitDependenciesInitFragment = require("../async-modules/AwaitDependenciesInitFragment");
13const { filterRuntime, mergeRuntime } = require("../util/runtime");
14const HarmonyLinkingError = require("./HarmonyLinkingError");
15const { ImportPhase, ImportPhaseUtils } = require("./ImportPhase");
16const ModuleDependency = require("./ModuleDependency");
17
18/** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */
19/** @typedef {import("../../declarations/WebpackOptions").JavascriptParserOptions} JavascriptParserOptions */
20/** @typedef {import("../Dependency").ReferencedExports} ReferencedExports */
21/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
22/** @typedef {import("../ExportsInfo")} ExportsInfo */
23/** @typedef {import("../Module")} Module */
24/** @typedef {import("../Module").BuildMeta} BuildMeta */
25/** @typedef {import("../ModuleGraph")} ModuleGraph */
26/** @typedef {import("../errors/WebpackError")} WebpackError */
27/** @typedef {import("../javascript/JavascriptParser").ImportAttributes} ImportAttributes */
28/** @typedef {import("./ImportPhase").ImportPhaseType} ImportPhaseType */
29/** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
30/** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
31/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
32
33/** @typedef {0 | 1 | 2 | 3} ExportPresenceMode */
34
35const ExportPresenceModes = {
36 NONE: /** @type {ExportPresenceMode} */ (0),
37 WARN: /** @type {ExportPresenceMode} */ (1),
38 AUTO: /** @type {ExportPresenceMode} */ (2),
39 ERROR: /** @type {ExportPresenceMode} */ (3),
40 /**
41 * Returns result.
42 * @param {string | false} str param
43 * @returns {ExportPresenceMode} result
44 */
45 fromUserOption(str) {
46 switch (str) {
47 case "error":
48 return ExportPresenceModes.ERROR;
49 case "warn":
50 return ExportPresenceModes.WARN;
51 case "auto":
52 return ExportPresenceModes.AUTO;
53 case false:
54 return ExportPresenceModes.NONE;
55 default:
56 throw new Error(`Invalid export presence value ${str}`);
57 }
58 },
59 /**
60 * Resolve export presence mode from parser options with a specific key and shared fallbacks.
61 * @param {string | false | undefined} specificValue the type-specific option value (e.g. importExportsPresence or reexportExportsPresence)
62 * @param {JavascriptParserOptions} options parser options
63 * @returns {ExportPresenceMode} resolved mode
64 */
65 resolveFromOptions(specificValue, options) {
66 if (specificValue !== undefined) {
67 return ExportPresenceModes.fromUserOption(specificValue);
68 }
69 if (options.exportsPresence !== undefined) {
70 return ExportPresenceModes.fromUserOption(options.exportsPresence);
71 }
72 return options.strictExportPresence
73 ? ExportPresenceModes.ERROR
74 : ExportPresenceModes.AUTO;
75 }
76};
77
78/**
79 * Get the non-optional leading part of a member chain.
80 * @param {string[]} members members
81 * @param {boolean[]} membersOptionals optionality for each member
82 * @returns {string[]} the non-optional prefix
83 */
84const getNonOptionalPart = (members, membersOptionals) => {
85 let i = 0;
86 while (i < members.length && membersOptionals[i] === false) i++;
87 return i !== members.length ? members.slice(0, i) : members;
88};
89
90/** @typedef {string[]} Ids */
91
92class HarmonyImportDependency extends ModuleDependency {
93 /**
94 * Creates an instance of HarmonyImportDependency.
95 * @param {string} request request string
96 * @param {number} sourceOrder source order
97 * @param {ImportPhaseType=} phase import phase
98 * @param {ImportAttributes=} attributes import attributes
99 */
100 constructor(
101 request,
102 sourceOrder,
103 phase = ImportPhase.Evaluation,
104 attributes = undefined
105 ) {
106 super(request, sourceOrder);
107 this.phase = phase;
108 this.attributes = attributes;
109 }
110
111 get category() {
112 return "esm";
113 }
114
115 /**
116 * Returns true if this dependency can be concatenated
117 * @returns {boolean} true if this dependency can be concatenated
118 */
119 canConcatenate() {
120 return true;
121 }
122
123 /**
124 * Returns an identifier to merge equal requests.
125 * @returns {string | null} an identifier to merge equal requests
126 */
127 getResourceIdentifier() {
128 let str = super.getResourceIdentifier();
129 // We specifically use this check to avoid writing the default (`evaluation` or `0`) value and save memory
130 if (this.phase) {
131 str += `|phase${ImportPhaseUtils.stringify(this.phase)}`;
132 }
133 if (this.attributes) {
134 str += `|attributes${JSON.stringify(this.attributes)}`;
135 }
136 return str;
137 }
138
139 /**
140 * Returns list of exports referenced by this dependency
141 * @param {ModuleGraph} moduleGraph module graph
142 * @param {RuntimeSpec} runtime the runtime for which the module is analysed
143 * @returns {ReferencedExports} referenced exports
144 */
145 getReferencedExports(moduleGraph, runtime) {
146 return Dependency.NO_EXPORTS_REFERENCED;
147 }
148
149 /**
150 * Returns name of the variable for the import.
151 * @param {ModuleGraph} moduleGraph the module graph
152 * @returns {string} name of the variable for the import
153 */
154 getImportVar(moduleGraph) {
155 const module = /** @type {Module} */ (moduleGraph.getParentModule(this));
156 const importedModule = /** @type {Module} */ (moduleGraph.getModule(this));
157 const meta = moduleGraph.getMeta(module);
158
159 const isDeferred =
160 ImportPhaseUtils.isDefer(this.phase) &&
161 !(/** @type {BuildMeta} */ (importedModule.buildMeta).async);
162
163 const metaKey = isDeferred ? "deferredImportVarMap" : "importVarMap";
164 let importVarMap = meta[metaKey];
165 if (!importVarMap) {
166 meta[metaKey] = importVarMap =
167 /** @type {Map<Module, string>} */
168 (new Map());
169 }
170
171 let importVar = importVarMap.get(importedModule);
172 if (importVar) return importVar;
173 importVar = `${Template.toIdentifier(`${this.userRequest}`)}__WEBPACK_${
174 isDeferred ? "DEFERRED_" : ""
175 }IMPORTED_MODULE_${importVarMap.size}__`;
176 importVarMap.set(importedModule, importVar);
177 return importVar;
178 }
179
180 /**
181 * Gets module exports.
182 * @param {DependencyTemplateContext} context the template context
183 * @returns {string} the expression
184 */
185 getModuleExports({
186 runtimeTemplate,
187 moduleGraph,
188 chunkGraph,
189 runtimeRequirements
190 }) {
191 return runtimeTemplate.moduleExports({
192 module: moduleGraph.getModule(this),
193 chunkGraph,
194 request: this.request,
195 runtimeRequirements
196 });
197 }
198
199 /**
200 * Gets import statement.
201 * @param {boolean} update create new variables or update existing one
202 * @param {DependencyTemplateContext} templateContext the template context
203 * @returns {[string, string]} the import statement and the compat statement
204 */
205 getImportStatement(
206 update,
207 { runtimeTemplate, module, moduleGraph, chunkGraph, runtimeRequirements }
208 ) {
209 return runtimeTemplate.importStatement({
210 update,
211 module: /** @type {Module} */ (moduleGraph.getModule(this)),
212 moduleGraph,
213 chunkGraph,
214 importVar: this.getImportVar(moduleGraph),
215 request: this.request,
216 originModule: module,
217 runtimeRequirements,
218 dependency: this
219 });
220 }
221
222 /**
223 * Gets linking errors.
224 * @param {ModuleGraph} moduleGraph module graph
225 * @param {Ids} ids imported ids
226 * @param {string} additionalMessage extra info included in the error message
227 * @returns {WebpackError[] | undefined} errors
228 */
229 getLinkingErrors(moduleGraph, ids, additionalMessage) {
230 // Source phase imports don't have exports to check
231 if (ImportPhaseUtils.isSource(this.phase)) {
232 return;
233 }
234
235 const importedModule = moduleGraph.getModule(this);
236 // ignore errors for missing or failed modules
237 if (!importedModule || importedModule.getNumberOfErrors() > 0) {
238 return;
239 }
240
241 const parentModule =
242 /** @type {Module} */
243 (moduleGraph.getParentModule(this));
244 const exportsType = importedModule.getExportsType(
245 moduleGraph,
246 /** @type {BuildMeta} */ (parentModule.buildMeta).strictHarmonyModule
247 );
248 if (exportsType === "namespace" || exportsType === "default-with-named") {
249 if (ids.length === 0) {
250 return;
251 }
252
253 if (
254 (exportsType !== "default-with-named" || ids[0] !== "default") &&
255 moduleGraph.isExportProvided(importedModule, ids) === false
256 ) {
257 // We are sure that it's not provided
258
259 // Try to provide detailed info in the error message
260 let pos = 0;
261 let exportsInfo = moduleGraph.getExportsInfo(importedModule);
262 while (pos < ids.length && exportsInfo) {
263 const id = ids[pos++];
264 const exportInfo = exportsInfo.getReadOnlyExportInfo(id);
265 if (exportInfo.provided === false) {
266 // We are sure that it's not provided
267 const providedExports = exportsInfo.getProvidedExports();
268 const moreInfo = !Array.isArray(providedExports)
269 ? " (possible exports unknown)"
270 : providedExports.length === 0
271 ? " (module has no exports)"
272 : ` (possible exports: ${providedExports.join(", ")})`;
273 return [
274 new HarmonyLinkingError(
275 `export ${ids
276 .slice(0, pos)
277 .map((id) => `'${id}'`)
278 .join(".")} ${additionalMessage} was not found in '${
279 this.userRequest
280 }'${moreInfo}`
281 )
282 ];
283 }
284 exportsInfo =
285 /** @type {ExportsInfo} */
286 (exportInfo.getNestedExportsInfo());
287 }
288
289 // General error message
290 return [
291 new HarmonyLinkingError(
292 `export ${ids
293 .map((id) => `'${id}'`)
294 .join(".")} ${additionalMessage} was not found in '${
295 this.userRequest
296 }'`
297 )
298 ];
299 }
300 }
301 switch (exportsType) {
302 case "default-only":
303 // It's has only a default export
304 if (ids.length > 0 && ids[0] !== "default") {
305 // In strict harmony modules we only support the default export
306 return [
307 new HarmonyLinkingError(
308 `Can't import the named export ${ids
309 .map((id) => `'${id}'`)
310 .join(
311 "."
312 )} ${additionalMessage} from default-exporting module (only default export is available)`
313 )
314 ];
315 }
316 break;
317 case "default-with-named":
318 // It has a default export and named properties redirect
319 // In some cases we still want to warn here
320 if (
321 ids.length > 0 &&
322 ids[0] !== "default" &&
323 /** @type {BuildMeta} */
324 (importedModule.buildMeta).defaultObject === "redirect-warn"
325 ) {
326 // For these modules only the default export is supported
327 return [
328 new HarmonyLinkingError(
329 `Should not import the named export ${ids
330 .map((id) => `'${id}'`)
331 .join(
332 "."
333 )} ${additionalMessage} from default-exporting module (only default export is available soon)`
334 )
335 ];
336 }
337 break;
338 }
339 }
340
341 /**
342 * Serializes this instance into the provided serializer context.
343 * @param {ObjectSerializerContext} context context
344 */
345 serialize(context) {
346 const { write } = context;
347 write(this.attributes);
348 write(this.phase);
349 super.serialize(context);
350 }
351
352 /**
353 * Restores this instance from the provided deserializer context.
354 * @param {ObjectDeserializerContext} context context
355 */
356 deserialize(context) {
357 const { read } = context;
358 this.attributes = read();
359 this.phase = read();
360 super.deserialize(context);
361 }
362}
363
364module.exports = HarmonyImportDependency;
365
366/** @type {WeakMap<Module, WeakMap<Module, RuntimeSpec | boolean>>} */
367const importEmittedMap = new WeakMap();
368
369HarmonyImportDependency.Template = class HarmonyImportDependencyTemplate extends (
370 ModuleDependency.Template
371) {
372 /**
373 * Applies the plugin by registering its hooks on the compiler.
374 * @param {Dependency} dependency the dependency for which the template should be applied
375 * @param {ReplaceSource} source the current replace source which can be modified
376 * @param {DependencyTemplateContext} templateContext the context object
377 * @returns {void}
378 */
379 apply(dependency, source, templateContext) {
380 const dep = /** @type {HarmonyImportDependency} */ (dependency);
381 const { module, chunkGraph, moduleGraph, runtime } = templateContext;
382
383 const connection = moduleGraph.getConnection(dep);
384 if (connection && !connection.isTargetActive(runtime)) return;
385
386 const referencedModule = connection && connection.module;
387
388 if (
389 connection &&
390 connection.weak &&
391 referencedModule &&
392 chunkGraph.getModuleId(referencedModule) === null
393 ) {
394 // in weak references, module might not be in any chunk
395 // but that's ok, we don't need that logic in this case
396 return;
397 }
398
399 const moduleKey = referencedModule
400 ? referencedModule.identifier()
401 : dep.request;
402 const key = `${
403 ImportPhaseUtils.isDefer(dep.phase)
404 ? "deferred "
405 : ImportPhaseUtils.isSource(dep.phase)
406 ? "source "
407 : ""
408 }harmony import ${moduleKey}`;
409
410 const runtimeCondition = dep.weak
411 ? false
412 : connection
413 ? filterRuntime(runtime, (r) => connection.isTargetActive(r))
414 : true;
415
416 if (module && referencedModule) {
417 let emittedModules = importEmittedMap.get(module);
418 if (emittedModules === undefined) {
419 emittedModules = new WeakMap();
420 importEmittedMap.set(module, emittedModules);
421 }
422 let mergedRuntimeCondition = runtimeCondition;
423 const oldRuntimeCondition = emittedModules.get(referencedModule) || false;
424 if (oldRuntimeCondition !== false && mergedRuntimeCondition !== true) {
425 if (mergedRuntimeCondition === false || oldRuntimeCondition === true) {
426 mergedRuntimeCondition = oldRuntimeCondition;
427 } else {
428 mergedRuntimeCondition = mergeRuntime(
429 oldRuntimeCondition,
430 mergedRuntimeCondition
431 );
432 }
433 }
434 emittedModules.set(referencedModule, mergedRuntimeCondition);
435 }
436
437 const importStatement = dep.getImportStatement(false, templateContext);
438 if (
439 referencedModule &&
440 templateContext.moduleGraph.isAsync(referencedModule)
441 ) {
442 templateContext.initFragments.push(
443 new ConditionalInitFragment(
444 importStatement[0],
445 InitFragment.STAGE_HARMONY_IMPORTS,
446 /** @type {number} */ (dep.sourceOrder),
447 key,
448 runtimeCondition
449 )
450 );
451 const importVar = dep.getImportVar(templateContext.moduleGraph);
452 templateContext.initFragments.push(
453 new AwaitDependenciesInitFragment(new Map([[importVar, importVar]]))
454 );
455 templateContext.initFragments.push(
456 new ConditionalInitFragment(
457 importStatement[1],
458 InitFragment.STAGE_ASYNC_HARMONY_IMPORTS,
459 /** @type {number} */ (dep.sourceOrder),
460 `${key} compat`,
461 runtimeCondition
462 )
463 );
464 } else {
465 templateContext.initFragments.push(
466 new ConditionalInitFragment(
467 importStatement[0] + importStatement[1],
468 InitFragment.STAGE_HARMONY_IMPORTS,
469 /** @type {number} */ (dep.sourceOrder),
470 key,
471 runtimeCondition
472 )
473 );
474 }
475 }
476
477 /**
478 * Gets import emitted runtime.
479 * @param {Module} module the module
480 * @param {Module} referencedModule the referenced module
481 * @returns {RuntimeSpec | boolean} runtimeCondition in which this import has been emitted
482 */
483 static getImportEmittedRuntime(module, referencedModule) {
484 const emittedModules = importEmittedMap.get(module);
485 if (emittedModules === undefined) return false;
486 return emittedModules.get(referencedModule) || false;
487 }
488};
489
490module.exports.ExportPresenceModes = ExportPresenceModes;
491module.exports.getNonOptionalPart = getNonOptionalPart;
Note: See TracBrowser for help on using the repository browser.