HarmonyImportSpecifierDependency.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const Dependency = require("../Dependency");
  7. const InitFragment = require("../InitFragment");
  8. const Template = require("../Template");
  9. const {
  10. InlinedUsedName,
  11. isExportInlined,
  12. isInlineEnabled,
  13. isInlineExportsEnabled
  14. } = require("../optimize/InlineExports");
  15. const {
  16. getDependencyUsedByExportsCondition
  17. } = require("../optimize/InnerGraph");
  18. const { getTrimmedIdsAndRange } = require("../util/chainedImports");
  19. const makeSerializable = require("../util/makeSerializable");
  20. const { propertyAccess } = require("../util/property");
  21. const traverseDestructuringAssignmentProperties = require("../util/traverseDestructuringAssignmentProperties");
  22. const HarmonyImportDependency = require("./HarmonyImportDependency");
  23. const HarmonyImportGuard = require("./HarmonyImportGuard");
  24. const { ImportPhaseUtils } = require("./ImportPhase");
  25. /** @import { ReplaceSource } from "webpack-sources" */
  26. /** @import { GetConditionFn, ReferencedExports } from "../Dependency" */
  27. /** @import { DependencyTemplateContext } from "../DependencyTemplate" */
  28. /** @import Module, { BuildMeta } from "../Module" */
  29. /** @import ModuleGraph from "../ModuleGraph" */
  30. /**
  31. * @import ModuleGraphConnection, {
  32. * ConnectionState
  33. * } from "../ModuleGraphConnection"
  34. */
  35. /** @import WebpackError from "../errors/WebpackError" */
  36. /**
  37. * @import {
  38. * DestructuringAssignmentProperties,
  39. * ImportAttributes,
  40. * Range
  41. * } from "../javascript/JavascriptParser"
  42. */
  43. /** @import { UsedByExports } from "../optimize/InnerGraph" */
  44. /**
  45. * @import {
  46. * ObjectDeserializerContext,
  47. * ObjectSerializerContext
  48. * } from "../serialization/ObjectMiddleware"
  49. */
  50. /** @import { RuntimeSpec } from "../util/runtime" */
  51. /** @import { IdRanges } from "../util/chainedImports" */
  52. /** @import { ExportPresenceMode } from "./HarmonyImportDependency" */
  53. /** @typedef {HarmonyImportDependency.Ids} Ids */
  54. /** @import { ImportPhaseType } from "./ImportPhase" */
  55. /** @import { DependencyGuard } from "./HarmonyImportGuard" */
  56. /**
  57. * @import {
  58. * JavascriptModuleBuildMeta
  59. * } from "../javascript/JavascriptModule"
  60. */
  61. const idsSymbol = /** @type {symbol} */ (
  62. Symbol("HarmonyImportSpecifierDependency.ids")
  63. );
  64. const { ExportPresenceModes } = HarmonyImportDependency;
  65. /**
  66. * One condition closure per module graph and variant rather than per dependency.
  67. * The dependency the condition was built for is always the one on the connection
  68. * it is called with, since `ModuleGraph#setResolvedModule` is the only caller of
  69. * `getCondition` and pairs the two. Indexed by
  70. * `(usedByExports ? 1 : 0) | (inlineEnabled ? 2 : 0)`.
  71. * @type {WeakMap<ModuleGraph, (GetConditionFn | undefined)[]>}
  72. */
  73. const conditionsByModuleGraph = new WeakMap();
  74. class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
  75. // read by `HarmonyImportGuard` in place of `instanceof`, which would cycle
  76. get isHarmonyImportSpecifier() {
  77. return true;
  78. }
  79. /**
  80. * Creates an instance of HarmonyImportSpecifierDependency.
  81. * @param {string} request request
  82. * @param {number} sourceOrder source order
  83. * @param {Ids} ids ids
  84. * @param {string} name name
  85. * @param {Range} range range
  86. * @param {ExportPresenceMode} exportPresenceMode export presence mode
  87. * @param {ImportPhaseType} phase import phase
  88. * @param {ImportAttributes | undefined} attributes import attributes
  89. * @param {IdRanges | undefined} idRanges ranges for members of ids; the two arrays are right-aligned
  90. */
  91. constructor(
  92. request,
  93. sourceOrder,
  94. ids,
  95. name,
  96. range,
  97. exportPresenceMode,
  98. phase,
  99. attributes,
  100. idRanges // TODO webpack 6 make this non-optional. It must always be set to properly trim ids.
  101. ) {
  102. super(request, sourceOrder, phase, attributes);
  103. /** @type {Ids} */
  104. this.ids = ids;
  105. /** @type {string} */
  106. this.name = name;
  107. this.range = range;
  108. /** @type {IdRanges | undefined} */
  109. this.idRanges = idRanges;
  110. /** @type {ExportPresenceMode} */
  111. this.exportPresenceMode = exportPresenceMode;
  112. /** @type {undefined | boolean} */
  113. this.namespaceObjectAsContext = false;
  114. /** @type {undefined | boolean} */
  115. this.call = undefined;
  116. /** @type {undefined | boolean} */
  117. this.directImport = undefined;
  118. /** @type {undefined | boolean | string} */
  119. this.shorthand = undefined;
  120. /** @type {undefined | boolean} */
  121. this.asiSafe = undefined;
  122. /** @type {UsedByExports | undefined} */
  123. this.usedByExports = undefined;
  124. /** @type {DestructuringAssignmentProperties | undefined} */
  125. this.referencedPropertiesInDestructuring = undefined;
  126. /** @type {DependencyGuard[] | undefined} */
  127. this.branchGuards = undefined;
  128. }
  129. // TODO webpack 6 remove
  130. /**
  131. * Returns id.
  132. * @deprecated
  133. */
  134. get id() {
  135. throw new Error("id was renamed to ids and type changed to string[]");
  136. }
  137. // TODO webpack 6 remove
  138. /**
  139. * Returns id.
  140. * @deprecated
  141. */
  142. getId() {
  143. throw new Error("id was renamed to ids and type changed to string[]");
  144. }
  145. // TODO webpack 6 remove
  146. /**
  147. * Updates id.
  148. * @deprecated
  149. */
  150. setId() {
  151. throw new Error("id was renamed to ids and type changed to string[]");
  152. }
  153. get type() {
  154. return "harmony import specifier";
  155. }
  156. /**
  157. * Returns the export name this dependency requests from its target module (lazy barrel optimization).
  158. * @returns {string | true | null} export name, true for all exports, null for none
  159. */
  160. getForwardId() {
  161. return this.ids.length > 0 ? this.ids[0] : true;
  162. }
  163. /**
  164. * Returns the imported ids.
  165. * @param {ModuleGraph} moduleGraph the module graph
  166. * @returns {Ids} the imported ids
  167. */
  168. getIds(moduleGraph) {
  169. const meta = moduleGraph.getMetaIfExisting(this);
  170. if (meta === undefined) return this.ids;
  171. const ids = meta[idsSymbol];
  172. return ids !== undefined ? ids : this.ids;
  173. }
  174. /**
  175. * Updates ids using the provided module graph.
  176. * @param {ModuleGraph} moduleGraph the module graph
  177. * @param {Ids} ids the imported ids
  178. * @returns {void}
  179. */
  180. setIds(moduleGraph, ids) {
  181. moduleGraph.getMeta(this)[idsSymbol] = ids;
  182. }
  183. /**
  184. * Returns function to determine if the connection is active.
  185. * @param {ModuleGraph} moduleGraph module graph
  186. * @returns {null | false | GetConditionFn} function to determine if the connection is active
  187. */
  188. getCondition(moduleGraph) {
  189. const usedByExportsCondition = getDependencyUsedByExportsCondition(
  190. this,
  191. moduleGraph
  192. );
  193. if (usedByExportsCondition === false) return false;
  194. const inlineEnabled = isInlineExportsEnabled(moduleGraph);
  195. // Keep the connection unconditional (fast path) when nothing can deactivate it
  196. if (
  197. usedByExportsCondition === null &&
  198. this.branchGuards === undefined &&
  199. !inlineEnabled
  200. ) {
  201. return null;
  202. }
  203. // Everything the condition still needs is either per module graph or on
  204. // the connection it is called with, so one closure per variant serves the
  205. // whole graph instead of one per dependency.
  206. const slot =
  207. (usedByExportsCondition === null ? 0 : 1) | (inlineEnabled ? 2 : 0);
  208. let variants = conditionsByModuleGraph.get(moduleGraph);
  209. if (variants === undefined) {
  210. variants = [undefined, undefined, undefined, undefined];
  211. conditionsByModuleGraph.set(moduleGraph, variants);
  212. }
  213. const cached = variants[slot];
  214. if (cached !== undefined) return cached;
  215. /** @type {GetConditionFn} */
  216. const condition = (connection, runtime) => {
  217. const dep = /** @type {HarmonyImportSpecifierDependency} */ (
  218. connection.dependency
  219. );
  220. if (usedByExportsCondition !== null) {
  221. const result = usedByExportsCondition(connection, runtime);
  222. if (result === false) return false;
  223. }
  224. // `isInlineEnabled` is the cheap module-level precondition of
  225. // `isExportInlined`; checking it here keeps the id lookup off the hot
  226. // path for the common target module that has no inlined exports
  227. if (inlineEnabled && isInlineEnabled(connection.module)) {
  228. const ids = dep.getIds(moduleGraph);
  229. if (
  230. ids.length > 0 &&
  231. isExportInlined(moduleGraph, connection.module, ids, runtime)
  232. ) {
  233. return false;
  234. }
  235. }
  236. const guards = dep.branchGuards;
  237. if (
  238. guards !== undefined &&
  239. HarmonyImportGuard.isDeadByGuards(guards, moduleGraph, runtime)
  240. ) {
  241. return false;
  242. }
  243. return true;
  244. };
  245. variants[slot] = condition;
  246. return condition;
  247. }
  248. /**
  249. * Gets module evaluation side effects state.
  250. * @param {ModuleGraph} moduleGraph the module graph
  251. * @returns {ConnectionState} how this dependency connects the module to referencing modules
  252. */
  253. getModuleEvaluationSideEffectsState(moduleGraph) {
  254. return false;
  255. }
  256. /**
  257. * Returns list of exports referenced by this dependency
  258. * @param {ModuleGraph} moduleGraph module graph
  259. * @param {RuntimeSpec} runtime the runtime for which the module is analysed
  260. * @returns {ReferencedExports} referenced exports
  261. */
  262. getReferencedExports(moduleGraph, runtime) {
  263. let ids = this.getIds(moduleGraph);
  264. if (ids.length === 0) {
  265. const refs = this._getReferencedExportsInDestructuring();
  266. // The whole namespace object is used as a value (no destructuring): it
  267. // can be rendered as a decoupled namespace object, keeping the module's
  268. // exports mangleable. Deferred imports keep their special namespace.
  269. return refs === Dependency.EXPORTS_OBJECT_REFERENCED &&
  270. !ImportPhaseUtils.isDefer(this.phase)
  271. ? Dependency.EXPORTS_OBJECT_REFERENCED_MANGLEABLE
  272. : refs;
  273. }
  274. let namespaceObjectAsContext = this.namespaceObjectAsContext;
  275. if (ids[0] === "default") {
  276. const selfModule =
  277. /** @type {Module} */
  278. (moduleGraph.getParentModule(this));
  279. const importedModule =
  280. /** @type {Module} */
  281. (moduleGraph.getModule(this));
  282. switch (
  283. importedModule.getExportsType(
  284. moduleGraph,
  285. /** @type {BuildMeta} */
  286. (selfModule.buildMeta).strictHarmonyModule
  287. )
  288. ) {
  289. case "default-only":
  290. case "default-with-named":
  291. if (ids.length === 1) {
  292. return this._getReferencedExportsInDestructuring();
  293. }
  294. ids = ids.slice(1);
  295. namespaceObjectAsContext = true;
  296. break;
  297. case "dynamic":
  298. return Dependency.EXPORTS_OBJECT_REFERENCED;
  299. }
  300. }
  301. if (
  302. this.call &&
  303. !this.directImport &&
  304. (namespaceObjectAsContext || ids.length > 1)
  305. ) {
  306. if (ids.length === 1) return Dependency.EXPORTS_OBJECT_REFERENCED;
  307. ids = ids.slice(0, -1);
  308. }
  309. return this._getReferencedExportsInDestructuring(ids);
  310. }
  311. /**
  312. * Get referenced exports in destructuring.
  313. * @param {Ids=} ids ids
  314. * @returns {ReferencedExports} referenced exports
  315. */
  316. _getReferencedExportsInDestructuring(ids) {
  317. if (this.referencedPropertiesInDestructuring) {
  318. /** @type {ReferencedExports} */
  319. const refs = [];
  320. traverseDestructuringAssignmentProperties(
  321. this.referencedPropertiesInDestructuring,
  322. (stack) => {
  323. const idsInDestructuring = stack.map((p) => p.id);
  324. // Destructuring consumer can't accept an inlined literal
  325. refs.push({
  326. name: ids ? [...ids, ...idsInDestructuring] : idsInDestructuring,
  327. canInline: false
  328. });
  329. }
  330. );
  331. return refs;
  332. }
  333. return ids
  334. ? [
  335. {
  336. name: ids,
  337. canMangle: true,
  338. // Need access the export value to trigger side effects for deferred module
  339. canInline: !ImportPhaseUtils.isDefer(this.phase)
  340. }
  341. ]
  342. : Dependency.EXPORTS_OBJECT_REFERENCED;
  343. }
  344. /**
  345. * Get effective export presence level.
  346. * @param {ModuleGraph} moduleGraph module graph
  347. * @returns {ExportPresenceMode} effective mode
  348. */
  349. _getEffectiveExportPresenceLevel(moduleGraph) {
  350. if (this.exportPresenceMode !== ExportPresenceModes.AUTO) {
  351. return this.exportPresenceMode;
  352. }
  353. const buildMeta =
  354. /** @type {JavascriptModuleBuildMeta} */
  355. (
  356. /** @type {Module} */
  357. (moduleGraph.getParentModule(this)).buildMeta
  358. );
  359. return buildMeta.strictHarmonyModule
  360. ? ExportPresenceModes.ERROR
  361. : ExportPresenceModes.WARN;
  362. }
  363. /**
  364. * Returns warnings.
  365. * @param {ModuleGraph} moduleGraph module graph
  366. * @returns {WebpackError[] | null | undefined} warnings
  367. */
  368. getWarnings(moduleGraph) {
  369. const exportsPresence = this._getEffectiveExportPresenceLevel(moduleGraph);
  370. if (exportsPresence === ExportPresenceModes.WARN) {
  371. return this._getErrors(moduleGraph);
  372. }
  373. return null;
  374. }
  375. /**
  376. * Returns errors.
  377. * @param {ModuleGraph} moduleGraph module graph
  378. * @returns {WebpackError[] | null | undefined} errors
  379. */
  380. getErrors(moduleGraph) {
  381. const exportsPresence = this._getEffectiveExportPresenceLevel(moduleGraph);
  382. if (exportsPresence === ExportPresenceModes.ERROR) {
  383. return this._getErrors(moduleGraph);
  384. }
  385. return null;
  386. }
  387. /**
  388. * Returns errors.
  389. * @param {ModuleGraph} moduleGraph module graph
  390. * @returns {WebpackError[] | undefined} errors
  391. */
  392. _getErrors(moduleGraph) {
  393. const ids = this.getIds(moduleGraph);
  394. return this.getLinkingErrors(
  395. moduleGraph,
  396. ids,
  397. `(imported as '${this.name}')`
  398. );
  399. }
  400. /**
  401. * implement this method to allow the occurrence order plugin to count correctly
  402. * @returns {number} count how often the id is used in this dependency
  403. */
  404. getNumberOfIdOccurrences() {
  405. return 0;
  406. }
  407. /**
  408. * Serializes this instance into the provided serializer context.
  409. * @param {ObjectSerializerContext} context context
  410. */
  411. serialize(context) {
  412. const { write } = context;
  413. write(this.ids);
  414. write(this.name);
  415. write(this.range);
  416. write(this.idRanges);
  417. write(this.exportPresenceMode);
  418. write(this.namespaceObjectAsContext);
  419. write(this.call);
  420. write(this.directImport);
  421. write(this.shorthand);
  422. write(this.asiSafe);
  423. write(this.usedByExports);
  424. write(this.referencedPropertiesInDestructuring);
  425. write(this.branchGuards);
  426. super.serialize(context);
  427. }
  428. /**
  429. * Restores this instance from the provided deserializer context.
  430. * @param {ObjectDeserializerContext} context context
  431. */
  432. deserialize(context) {
  433. const { read } = context;
  434. this.ids = read();
  435. this.name = read();
  436. this.range = read();
  437. this.idRanges = read();
  438. this.exportPresenceMode = read();
  439. this.namespaceObjectAsContext = read();
  440. this.call = read();
  441. this.directImport = read();
  442. this.shorthand = read();
  443. this.asiSafe = read();
  444. this.usedByExports = read();
  445. this.referencedPropertiesInDestructuring = read();
  446. this.branchGuards = read();
  447. super.deserialize(context);
  448. }
  449. }
  450. makeSerializable(
  451. HarmonyImportSpecifierDependency,
  452. "webpack/lib/dependencies/HarmonyImportSpecifierDependency"
  453. );
  454. HarmonyImportSpecifierDependency.Template = class HarmonyImportSpecifierDependencyTemplate extends (
  455. HarmonyImportDependency.Template
  456. ) {
  457. /**
  458. * Applies the plugin by registering its hooks on the compiler.
  459. * @param {Dependency} dependency the dependency for which the template should be applied
  460. * @param {ReplaceSource} source the current replace source which can be modified
  461. * @param {DependencyTemplateContext} templateContext the context object
  462. * @returns {void}
  463. */
  464. apply(dependency, source, templateContext) {
  465. const dep = /** @type {HarmonyImportSpecifierDependency} */ (dependency);
  466. const { moduleGraph, runtime, initFragments } = templateContext;
  467. const connection = moduleGraph.getConnection(dep);
  468. const ids = dep.getIds(moduleGraph);
  469. if (
  470. connection &&
  471. !connection.isTargetActive(runtime) &&
  472. !isExportInlined(moduleGraph, connection.module, ids, runtime)
  473. ) {
  474. initFragments.push(
  475. new InitFragment(
  476. `/* unused harmony import specifier */ var ${dep.name};\n`,
  477. InitFragment.STAGE_HARMONY_IMPORTS,
  478. 0,
  479. `unused import specifier ${dep.name}`
  480. )
  481. );
  482. return;
  483. }
  484. const {
  485. trimmedRange: [trimmedRangeStart, trimmedRangeEnd],
  486. trimmedIds
  487. } = getTrimmedIdsAndRange(ids, dep.range, dep.idRanges, moduleGraph, dep);
  488. const exportExpr = this._getCodeForIds(
  489. dep,
  490. source,
  491. templateContext,
  492. trimmedIds,
  493. connection
  494. );
  495. if (dep.shorthand) {
  496. source.insert(trimmedRangeEnd, `: ${exportExpr}`);
  497. } else {
  498. source.replace(trimmedRangeStart, trimmedRangeEnd - 1, exportExpr);
  499. }
  500. if (dep.referencedPropertiesInDestructuring) {
  501. let prefixedIds = ids;
  502. if (ids[0] === "default") {
  503. const selfModule =
  504. /** @type {Module} */
  505. (moduleGraph.getParentModule(dep));
  506. const importedModule =
  507. /** @type {Module} */
  508. (moduleGraph.getModule(dep));
  509. const exportsType = importedModule.getExportsType(
  510. moduleGraph,
  511. /** @type {BuildMeta} */
  512. (selfModule.buildMeta).strictHarmonyModule
  513. );
  514. if (
  515. (exportsType === "default-only" ||
  516. exportsType === "default-with-named") &&
  517. ids.length >= 1
  518. ) {
  519. prefixedIds = ids.slice(1);
  520. }
  521. }
  522. /** @type {{ ids: Ids, range: Range, shorthand: boolean | string }[]} */
  523. const replacementsInDestructuring = [];
  524. traverseDestructuringAssignmentProperties(
  525. dep.referencedPropertiesInDestructuring,
  526. undefined,
  527. (stack) => {
  528. const property = stack[stack.length - 1];
  529. replacementsInDestructuring.push({
  530. ids: stack.map((p) => p.id),
  531. range: property.range,
  532. shorthand: property.shorthand
  533. });
  534. }
  535. );
  536. // loop-invariant: resolve the imported module's exports info once
  537. const destructuredExportsInfo = moduleGraph.getExportsInfo(
  538. /** @type {Module} */ (moduleGraph.getModule(dep))
  539. );
  540. for (const { ids, shorthand, range } of replacementsInDestructuring) {
  541. /** @type {Ids} */
  542. const concatedIds = [...prefixedIds, ...ids];
  543. const used = destructuredExportsInfo.getUsedName(concatedIds, runtime);
  544. if (!used) {
  545. return;
  546. } else if (used instanceof InlinedUsedName) {
  547. throw new Error(
  548. `Should not inline for destructuring name ${concatedIds.join(".")}`
  549. );
  550. }
  551. // Destructuring can't consume an inlined literal — should be unreachable
  552. // because the consumer-side canInline=false suppresses inlining there.
  553. if (!Array.isArray(used)) continue;
  554. const newName = used[used.length - 1];
  555. const name = concatedIds[concatedIds.length - 1];
  556. if (newName === name) continue;
  557. const comment = `${Template.toNormalComment(name)} `;
  558. const key = comment + JSON.stringify(newName);
  559. source.replace(
  560. range[0],
  561. range[1] - 1,
  562. shorthand ? `${key}: ${name}` : `${key}`
  563. );
  564. }
  565. }
  566. }
  567. /**
  568. * Returns generated code.
  569. * @param {HarmonyImportSpecifierDependency} dep dependency
  570. * @param {ReplaceSource} source source
  571. * @param {DependencyTemplateContext} templateContext context
  572. * @param {Ids} ids ids
  573. * @param {ModuleGraphConnection | undefined} connection the resolved connection for dep
  574. * @returns {string} generated code
  575. */
  576. _getCodeForIds(dep, source, templateContext, ids, connection) {
  577. const { moduleGraph, module, runtime, concatenationScope } =
  578. templateContext;
  579. /** @type {string} */
  580. let exportExpr;
  581. if (
  582. connection &&
  583. concatenationScope &&
  584. concatenationScope.isModuleInScope(connection.module)
  585. ) {
  586. if (ids.length === 0) {
  587. exportExpr = concatenationScope.createModuleReference(
  588. connection.module,
  589. {
  590. asiSafe: dep.asiSafe,
  591. deferredImport: ImportPhaseUtils.isDefer(dep.phase),
  592. // A bare namespace value that isn't destructured may escape, so
  593. // allow a decoupled namespace object that keeps the original names.
  594. // Deferred imports keep their special namespace object.
  595. mangleableNamespace:
  596. !dep.referencedPropertiesInDestructuring &&
  597. !ImportPhaseUtils.isDefer(dep.phase)
  598. }
  599. );
  600. } else if (dep.namespaceObjectAsContext && ids.length === 1) {
  601. exportExpr =
  602. concatenationScope.createModuleReference(connection.module, {
  603. asiSafe: dep.asiSafe,
  604. deferredImport: ImportPhaseUtils.isDefer(dep.phase)
  605. }) + propertyAccess(ids);
  606. } else {
  607. exportExpr = concatenationScope.createModuleReference(
  608. connection.module,
  609. {
  610. ids,
  611. call: dep.call,
  612. directImport: dep.directImport,
  613. asiSafe: dep.asiSafe,
  614. deferredImport: ImportPhaseUtils.isDefer(dep.phase)
  615. }
  616. );
  617. }
  618. } else {
  619. super.apply(dep, source, templateContext);
  620. const { runtimeTemplate, initFragments, runtimeRequirements } =
  621. templateContext;
  622. exportExpr = runtimeTemplate.exportFromImport({
  623. moduleGraph,
  624. module: /** @type {Module} */ (moduleGraph.getModule(dep)),
  625. chunkGraph: templateContext.chunkGraph,
  626. request: dep.request,
  627. exportName: ids,
  628. originModule: module,
  629. asiSafe: dep.shorthand ? true : dep.asiSafe,
  630. isCall: dep.call,
  631. callContext: !dep.directImport,
  632. defaultInterop: true,
  633. importVar: dep.getImportVar(moduleGraph),
  634. initFragments,
  635. runtime,
  636. runtimeRequirements,
  637. dependency: dep,
  638. // A bare namespace value that isn't destructured may escape, so allow a
  639. // decoupled namespace object that keeps the original export names.
  640. // Deferred imports keep their special namespace object.
  641. mangleableNamespace:
  642. ids.length === 0 &&
  643. !dep.referencedPropertiesInDestructuring &&
  644. !ImportPhaseUtils.isDefer(dep.phase)
  645. });
  646. }
  647. return exportExpr;
  648. }
  649. };
  650. HarmonyImportSpecifierDependency.idsSymbol = idsSymbol;
  651. module.exports = HarmonyImportSpecifierDependency;