UNPKG

9.91 kBJavaScriptView Raw
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const Dependency = require("../Dependency");
9const {
10 getDependencyUsedByExportsCondition
11} = require("../optimize/InnerGraph");
12const makeSerializable = require("../util/makeSerializable");
13const propertyAccess = require("../util/propertyAccess");
14const HarmonyImportDependency = require("./HarmonyImportDependency");
15
16/** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */
17/** @typedef {import("../ChunkGraph")} ChunkGraph */
18/** @typedef {import("../Dependency").ExportsSpec} ExportsSpec */
19/** @typedef {import("../Dependency").ReferencedExport} ReferencedExport */
20/** @typedef {import("../Dependency").UpdateHashContext} UpdateHashContext */
21/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
22/** @typedef {import("../ModuleGraph")} ModuleGraph */
23/** @typedef {import("../ModuleGraphConnection")} ModuleGraphConnection */
24/** @typedef {import("../ModuleGraphConnection").ConnectionState} ConnectionState */
25/** @typedef {import("../WebpackError")} WebpackError */
26/** @typedef {import("../util/Hash")} Hash */
27/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
28
29const idsSymbol = Symbol("HarmonyImportSpecifierDependency.ids");
30
31const { ExportPresenceModes } = HarmonyImportDependency;
32
33class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
34 constructor(
35 request,
36 sourceOrder,
37 ids,
38 name,
39 range,
40 exportPresenceMode,
41 assertions
42 ) {
43 super(request, sourceOrder, assertions);
44 this.ids = ids;
45 this.name = name;
46 this.range = range;
47 this.exportPresenceMode = exportPresenceMode;
48 this.namespaceObjectAsContext = false;
49 this.call = undefined;
50 this.directImport = undefined;
51 this.shorthand = undefined;
52 this.asiSafe = undefined;
53 /** @type {Set<string> | boolean} */
54 this.usedByExports = undefined;
55 }
56
57 // TODO webpack 6 remove
58 get id() {
59 throw new Error("id was renamed to ids and type changed to string[]");
60 }
61
62 // TODO webpack 6 remove
63 getId() {
64 throw new Error("id was renamed to ids and type changed to string[]");
65 }
66
67 // TODO webpack 6 remove
68 setId() {
69 throw new Error("id was renamed to ids and type changed to string[]");
70 }
71
72 get type() {
73 return "harmony import specifier";
74 }
75
76 /**
77 * @param {ModuleGraph} moduleGraph the module graph
78 * @returns {string[]} the imported ids
79 */
80 getIds(moduleGraph) {
81 const meta = moduleGraph.getMetaIfExisting(this);
82 if (meta === undefined) return this.ids;
83 const ids = meta[idsSymbol];
84 return ids !== undefined ? ids : this.ids;
85 }
86
87 /**
88 * @param {ModuleGraph} moduleGraph the module graph
89 * @param {string[]} ids the imported ids
90 * @returns {void}
91 */
92 setIds(moduleGraph, ids) {
93 moduleGraph.getMeta(this)[idsSymbol] = ids;
94 }
95
96 /**
97 * @param {ModuleGraph} moduleGraph module graph
98 * @returns {null | false | function(ModuleGraphConnection, RuntimeSpec): ConnectionState} function to determine if the connection is active
99 */
100 getCondition(moduleGraph) {
101 return getDependencyUsedByExportsCondition(
102 this,
103 this.usedByExports,
104 moduleGraph
105 );
106 }
107
108 /**
109 * @param {ModuleGraph} moduleGraph the module graph
110 * @returns {ConnectionState} how this dependency connects the module to referencing modules
111 */
112 getModuleEvaluationSideEffectsState(moduleGraph) {
113 return false;
114 }
115
116 /**
117 * Returns list of exports referenced by this dependency
118 * @param {ModuleGraph} moduleGraph module graph
119 * @param {RuntimeSpec} runtime the runtime for which the module is analysed
120 * @returns {(string[] | ReferencedExport)[]} referenced exports
121 */
122 getReferencedExports(moduleGraph, runtime) {
123 let ids = this.getIds(moduleGraph);
124 if (ids.length === 0) return Dependency.EXPORTS_OBJECT_REFERENCED;
125 let namespaceObjectAsContext = this.namespaceObjectAsContext;
126 if (ids[0] === "default") {
127 const selfModule = moduleGraph.getParentModule(this);
128 const importedModule = moduleGraph.getModule(this);
129 switch (
130 importedModule.getExportsType(
131 moduleGraph,
132 selfModule.buildMeta.strictHarmonyModule
133 )
134 ) {
135 case "default-only":
136 case "default-with-named":
137 if (ids.length === 1) return Dependency.EXPORTS_OBJECT_REFERENCED;
138 ids = ids.slice(1);
139 namespaceObjectAsContext = true;
140 break;
141 case "dynamic":
142 return Dependency.EXPORTS_OBJECT_REFERENCED;
143 }
144 }
145
146 if (
147 this.call &&
148 !this.directImport &&
149 (namespaceObjectAsContext || ids.length > 1)
150 ) {
151 if (ids.length === 1) return Dependency.EXPORTS_OBJECT_REFERENCED;
152 ids = ids.slice(0, -1);
153 }
154
155 return [ids];
156 }
157
158 /**
159 * @param {ModuleGraph} moduleGraph module graph
160 * @returns {number} effective mode
161 */
162 _getEffectiveExportPresenceLevel(moduleGraph) {
163 if (this.exportPresenceMode !== ExportPresenceModes.AUTO)
164 return this.exportPresenceMode;
165 return moduleGraph.getParentModule(this).buildMeta.strictHarmonyModule
166 ? ExportPresenceModes.ERROR
167 : ExportPresenceModes.WARN;
168 }
169
170 /**
171 * Returns warnings
172 * @param {ModuleGraph} moduleGraph module graph
173 * @returns {WebpackError[]} warnings
174 */
175 getWarnings(moduleGraph) {
176 const exportsPresence = this._getEffectiveExportPresenceLevel(moduleGraph);
177 if (exportsPresence === ExportPresenceModes.WARN) {
178 return this._getErrors(moduleGraph);
179 }
180 return null;
181 }
182
183 /**
184 * Returns errors
185 * @param {ModuleGraph} moduleGraph module graph
186 * @returns {WebpackError[]} errors
187 */
188 getErrors(moduleGraph) {
189 const exportsPresence = this._getEffectiveExportPresenceLevel(moduleGraph);
190 if (exportsPresence === ExportPresenceModes.ERROR) {
191 return this._getErrors(moduleGraph);
192 }
193 return null;
194 }
195
196 /**
197 * @param {ModuleGraph} moduleGraph module graph
198 * @returns {WebpackError[] | undefined} errors
199 */
200 _getErrors(moduleGraph) {
201 const ids = this.getIds(moduleGraph);
202 return this.getLinkingErrors(
203 moduleGraph,
204 ids,
205 `(imported as '${this.name}')`
206 );
207 }
208
209 /**
210 * implement this method to allow the occurrence order plugin to count correctly
211 * @returns {number} count how often the id is used in this dependency
212 */
213 getNumberOfIdOccurrences() {
214 return 0;
215 }
216
217 serialize(context) {
218 const { write } = context;
219 write(this.ids);
220 write(this.name);
221 write(this.range);
222 write(this.exportPresenceMode);
223 write(this.namespaceObjectAsContext);
224 write(this.call);
225 write(this.directImport);
226 write(this.shorthand);
227 write(this.asiSafe);
228 write(this.usedByExports);
229 super.serialize(context);
230 }
231
232 deserialize(context) {
233 const { read } = context;
234 this.ids = read();
235 this.name = read();
236 this.range = read();
237 this.exportPresenceMode = read();
238 this.namespaceObjectAsContext = read();
239 this.call = read();
240 this.directImport = read();
241 this.shorthand = read();
242 this.asiSafe = read();
243 this.usedByExports = read();
244 super.deserialize(context);
245 }
246}
247
248makeSerializable(
249 HarmonyImportSpecifierDependency,
250 "webpack/lib/dependencies/HarmonyImportSpecifierDependency"
251);
252
253HarmonyImportSpecifierDependency.Template = class HarmonyImportSpecifierDependencyTemplate extends (
254 HarmonyImportDependency.Template
255) {
256 /**
257 * @param {Dependency} dependency the dependency for which the template should be applied
258 * @param {ReplaceSource} source the current replace source which can be modified
259 * @param {DependencyTemplateContext} templateContext the context object
260 * @returns {void}
261 */
262 apply(dependency, source, templateContext) {
263 const dep = /** @type {HarmonyImportSpecifierDependency} */ (dependency);
264 const { moduleGraph, runtime } = templateContext;
265 const connection = moduleGraph.getConnection(dep);
266 // Skip rendering depending when dependency is conditional
267 if (connection && !connection.isTargetActive(runtime)) return;
268
269 const ids = dep.getIds(moduleGraph);
270 const exportExpr = this._getCodeForIds(dep, source, templateContext, ids);
271 const range = dep.range;
272 if (dep.shorthand) {
273 source.insert(range[1], `: ${exportExpr}`);
274 } else {
275 source.replace(range[0], range[1] - 1, exportExpr);
276 }
277 }
278
279 /**
280 * @param {HarmonyImportSpecifierDependency} dep dependency
281 * @param {ReplaceSource} source source
282 * @param {DependencyTemplateContext} templateContext context
283 * @param {string[]} ids ids
284 * @returns {string} generated code
285 */
286 _getCodeForIds(dep, source, templateContext, ids) {
287 const { moduleGraph, module, runtime, concatenationScope } =
288 templateContext;
289 const connection = moduleGraph.getConnection(dep);
290 let exportExpr;
291 if (
292 connection &&
293 concatenationScope &&
294 concatenationScope.isModuleInScope(connection.module)
295 ) {
296 if (ids.length === 0) {
297 exportExpr = concatenationScope.createModuleReference(
298 connection.module,
299 {
300 asiSafe: dep.asiSafe
301 }
302 );
303 } else if (dep.namespaceObjectAsContext && ids.length === 1) {
304 exportExpr =
305 concatenationScope.createModuleReference(connection.module, {
306 asiSafe: dep.asiSafe
307 }) + propertyAccess(ids);
308 } else {
309 exportExpr = concatenationScope.createModuleReference(
310 connection.module,
311 {
312 ids,
313 call: dep.call,
314 directImport: dep.directImport,
315 asiSafe: dep.asiSafe
316 }
317 );
318 }
319 } else {
320 super.apply(dep, source, templateContext);
321
322 const { runtimeTemplate, initFragments, runtimeRequirements } =
323 templateContext;
324
325 exportExpr = runtimeTemplate.exportFromImport({
326 moduleGraph,
327 module: moduleGraph.getModule(dep),
328 request: dep.request,
329 exportName: ids,
330 originModule: module,
331 asiSafe: dep.shorthand ? true : dep.asiSafe,
332 isCall: dep.call,
333 callContext: !dep.directImport,
334 defaultInterop: true,
335 importVar: dep.getImportVar(moduleGraph),
336 initFragments,
337 runtime,
338 runtimeRequirements
339 });
340 }
341 return exportExpr;
342 }
343};
344
345module.exports = HarmonyImportSpecifierDependency;