ImportDependency.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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 makeSerializable = require("../util/makeSerializable");
  8. const { ImportPhaseUtils } = require("./ImportPhase");
  9. const ModuleDependency = require("./ModuleDependency");
  10. /** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */
  11. /** @typedef {import("../AsyncDependenciesBlock")} AsyncDependenciesBlock */
  12. /** @typedef {import("../Dependency").RawReferencedExports} RawReferencedExports */
  13. /** @typedef {import("../Dependency").ReferencedExports} ReferencedExports */
  14. /** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
  15. /** @typedef {import("../Module")} Module */
  16. /** @typedef {import("../Module").BuildMeta} BuildMeta */
  17. /** @typedef {import("../ModuleGraph")} ModuleGraph */
  18. /** @typedef {import("../javascript/JavascriptParser").ImportAttributes} ImportAttributes */
  19. /** @typedef {import("../javascript/JavascriptParser").Range} Range */
  20. /** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
  21. /** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
  22. /** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
  23. /** @typedef {import("./ImportPhase").ImportPhaseType} ImportPhaseType */
  24. class ImportDependency extends ModuleDependency {
  25. /**
  26. * Creates an instance of ImportDependency.
  27. * @param {string} request the request
  28. * @param {Range} range expression range
  29. * @param {RawReferencedExports | null} referencedExports list of referenced exports
  30. * @param {ImportPhaseType} phase import phase
  31. * @param {ImportAttributes=} attributes import attributes
  32. */
  33. constructor(request, range, referencedExports, phase, attributes) {
  34. super(request);
  35. this.range = range;
  36. this.referencedExports = referencedExports;
  37. this.phase = phase;
  38. this.attributes = attributes;
  39. }
  40. get type() {
  41. return "import()";
  42. }
  43. get category() {
  44. return "esm";
  45. }
  46. /**
  47. * Returns an identifier to merge equal requests.
  48. * @returns {string | null} an identifier to merge equal requests
  49. */
  50. getResourceIdentifier() {
  51. let str = super.getResourceIdentifier();
  52. // We specifically use this check to avoid writing the default (`evaluation` or `0`) value and save memory
  53. if (this.phase) {
  54. str += `|phase${ImportPhaseUtils.stringify(this.phase)}`;
  55. }
  56. if (this.attributes) {
  57. str += `|attributes${JSON.stringify(this.attributes)}`;
  58. }
  59. return str;
  60. }
  61. /**
  62. * Returns list of exports referenced by this dependency
  63. * @param {ModuleGraph} moduleGraph module graph
  64. * @param {RuntimeSpec} runtime the runtime for which the module is analysed
  65. * @returns {ReferencedExports} referenced exports
  66. */
  67. getReferencedExports(moduleGraph, runtime) {
  68. if (!this.referencedExports) return Dependency.EXPORTS_OBJECT_REFERENCED;
  69. /** @type {ReferencedExports} */
  70. const refs = [];
  71. for (const referencedExport of this.referencedExports) {
  72. if (referencedExport[0] === "default") {
  73. const selfModule =
  74. /** @type {Module} */
  75. (moduleGraph.getParentModule(this));
  76. const importedModule =
  77. /** @type {Module} */
  78. (moduleGraph.getModule(this));
  79. const exportsType = importedModule.getExportsType(
  80. moduleGraph,
  81. /** @type {BuildMeta} */
  82. (selfModule.buildMeta).strictHarmonyModule
  83. );
  84. if (
  85. exportsType === "default-only" ||
  86. exportsType === "default-with-named"
  87. ) {
  88. return Dependency.EXPORTS_OBJECT_REFERENCED;
  89. }
  90. }
  91. refs.push({
  92. name: referencedExport,
  93. canMangle: false
  94. });
  95. }
  96. return refs;
  97. }
  98. /**
  99. * Serializes this instance into the provided serializer context.
  100. * @param {ObjectSerializerContext} context context
  101. */
  102. serialize(context) {
  103. context.write(this.range);
  104. context.write(this.referencedExports);
  105. context.write(this.phase);
  106. context.write(this.attributes);
  107. super.serialize(context);
  108. }
  109. /**
  110. * Restores this instance from the provided deserializer context.
  111. * @param {ObjectDeserializerContext} context context
  112. */
  113. deserialize(context) {
  114. this.range = context.read();
  115. this.referencedExports = context.read();
  116. this.phase = context.read();
  117. this.attributes = context.read();
  118. super.deserialize(context);
  119. }
  120. }
  121. makeSerializable(ImportDependency, "webpack/lib/dependencies/ImportDependency");
  122. ImportDependency.Template = class ImportDependencyTemplate extends (
  123. ModuleDependency.Template
  124. ) {
  125. /**
  126. * Applies the plugin by registering its hooks on the compiler.
  127. * @param {Dependency} dependency the dependency for which the template should be applied
  128. * @param {ReplaceSource} source the current replace source which can be modified
  129. * @param {DependencyTemplateContext} templateContext the context object
  130. * @returns {void}
  131. */
  132. apply(
  133. dependency,
  134. source,
  135. { runtimeTemplate, module, moduleGraph, chunkGraph, runtimeRequirements }
  136. ) {
  137. const dep = /** @type {ImportDependency} */ (dependency);
  138. const block = /** @type {AsyncDependenciesBlock} */ (
  139. moduleGraph.getParentBlock(dep)
  140. );
  141. let content = runtimeTemplate.moduleNamespacePromise({
  142. chunkGraph,
  143. block,
  144. module: /** @type {Module} */ (moduleGraph.getModule(dep)),
  145. request: dep.request,
  146. strict: /** @type {BuildMeta} */ (module.buildMeta).strictHarmonyModule,
  147. dependency: dep,
  148. message: "import()",
  149. runtimeRequirements
  150. });
  151. // For source phase imports, unwrap the default export
  152. // import.source() should return the source directly, not a namespace
  153. if (ImportPhaseUtils.isSource(dep.phase)) {
  154. content = `${content}.then(${runtimeTemplate.returningFunction(
  155. 'm["default"]',
  156. "m"
  157. )})`;
  158. }
  159. source.replace(dep.range[0], dep.range[1] - 1, content);
  160. }
  161. };
  162. module.exports = ImportDependency;