HarmonyExportExpressionDependency.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const ConcatenationScope = require("../ConcatenationScope");
  7. const RuntimeGlobals = require("../RuntimeGlobals");
  8. const makeSerializable = require("../util/makeSerializable");
  9. const propertyAccess = require("../util/propertyAccess");
  10. const HarmonyExportInitFragment = require("./HarmonyExportInitFragment");
  11. const NullDependency = require("./NullDependency");
  12. /** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */
  13. /** @typedef {import("../Dependency")} Dependency */
  14. /** @typedef {import("../Dependency").ExportsSpec} ExportsSpec */
  15. /** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
  16. /** @typedef {import("../ModuleGraph")} ModuleGraph */
  17. /** @typedef {import("../ModuleGraphConnection").ConnectionState} ConnectionState */
  18. /** @typedef {import("../javascript/JavascriptParser").Range} Range */
  19. /** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
  20. /** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
  21. /** @typedef {import("./HarmonyExportInitFragment").ExportMap} ExportMap */
  22. class HarmonyExportExpressionDependency extends NullDependency {
  23. /**
  24. * @param {Range} range range
  25. * @param {Range} rangeStatement range statement
  26. * @param {string} prefix prefix
  27. * @param {string | { id?: string | undefined, range: Range, prefix: string, suffix: string }=} declarationId declaration id
  28. */
  29. constructor(range, rangeStatement, prefix, declarationId) {
  30. super();
  31. this.range = range;
  32. this.rangeStatement = rangeStatement;
  33. this.prefix = prefix;
  34. this.declarationId = declarationId;
  35. }
  36. get type() {
  37. return "harmony export expression";
  38. }
  39. /**
  40. * Returns the exported names
  41. * @param {ModuleGraph} moduleGraph module graph
  42. * @returns {ExportsSpec | undefined} export names
  43. */
  44. getExports(moduleGraph) {
  45. return {
  46. exports: ["default"],
  47. priority: 1,
  48. terminalBinding: true,
  49. dependencies: undefined
  50. };
  51. }
  52. /**
  53. * @param {ModuleGraph} moduleGraph the module graph
  54. * @returns {ConnectionState} how this dependency connects the module to referencing modules
  55. */
  56. getModuleEvaluationSideEffectsState(moduleGraph) {
  57. // The expression/declaration is already covered by SideEffectsFlagPlugin
  58. return false;
  59. }
  60. /**
  61. * @param {ObjectSerializerContext} context context
  62. */
  63. serialize(context) {
  64. const { write } = context;
  65. write(this.range);
  66. write(this.rangeStatement);
  67. write(this.prefix);
  68. write(this.declarationId);
  69. super.serialize(context);
  70. }
  71. /**
  72. * @param {ObjectDeserializerContext} context context
  73. */
  74. deserialize(context) {
  75. const { read } = context;
  76. this.range = read();
  77. this.rangeStatement = read();
  78. this.prefix = read();
  79. this.declarationId = read();
  80. super.deserialize(context);
  81. }
  82. }
  83. makeSerializable(
  84. HarmonyExportExpressionDependency,
  85. "webpack/lib/dependencies/HarmonyExportExpressionDependency"
  86. );
  87. HarmonyExportExpressionDependency.Template = class HarmonyExportDependencyTemplate extends (
  88. NullDependency.Template
  89. ) {
  90. /**
  91. * @param {Dependency} dependency the dependency for which the template should be applied
  92. * @param {ReplaceSource} source the current replace source which can be modified
  93. * @param {DependencyTemplateContext} templateContext the context object
  94. * @returns {void}
  95. */
  96. apply(
  97. dependency,
  98. source,
  99. {
  100. module,
  101. moduleGraph,
  102. runtimeTemplate,
  103. runtimeRequirements,
  104. initFragments,
  105. runtime,
  106. concatenationScope
  107. }
  108. ) {
  109. const dep = /** @type {HarmonyExportExpressionDependency} */ (dependency);
  110. const { declarationId } = dep;
  111. const exportsName = module.exportsArgument;
  112. if (declarationId) {
  113. /** @type {string} */
  114. let name;
  115. if (typeof declarationId === "string") {
  116. name = declarationId;
  117. } else {
  118. name = ConcatenationScope.DEFAULT_EXPORT;
  119. source.replace(
  120. declarationId.range[0],
  121. declarationId.range[1] - 1,
  122. `${declarationId.prefix}${name}${declarationId.suffix}`
  123. );
  124. }
  125. if (concatenationScope) {
  126. concatenationScope.registerExport("default", name);
  127. } else {
  128. const used = moduleGraph
  129. .getExportsInfo(module)
  130. .getUsedName("default", runtime);
  131. if (used) {
  132. /** @type {ExportMap} */
  133. const map = new Map();
  134. map.set(used, `/* export default binding */ ${name}`);
  135. initFragments.push(new HarmonyExportInitFragment(exportsName, map));
  136. }
  137. }
  138. source.replace(
  139. dep.rangeStatement[0],
  140. dep.range[0] - 1,
  141. `/* harmony default export */ ${dep.prefix}`
  142. );
  143. } else {
  144. /** @type {string} */
  145. let content;
  146. const name = ConcatenationScope.DEFAULT_EXPORT;
  147. if (runtimeTemplate.supportsConst()) {
  148. content = `/* harmony default export */ const ${name} = `;
  149. if (concatenationScope) {
  150. concatenationScope.registerExport("default", name);
  151. } else {
  152. const used = moduleGraph
  153. .getExportsInfo(module)
  154. .getUsedName("default", runtime);
  155. if (used) {
  156. runtimeRequirements.add(RuntimeGlobals.exports);
  157. /** @type {ExportMap} */
  158. const map = new Map();
  159. map.set(used, name);
  160. initFragments.push(new HarmonyExportInitFragment(exportsName, map));
  161. } else {
  162. content = `/* unused harmony default export */ var ${name} = `;
  163. }
  164. }
  165. } else if (concatenationScope) {
  166. content = `/* harmony default export */ var ${name} = `;
  167. concatenationScope.registerExport("default", name);
  168. } else {
  169. const used = moduleGraph
  170. .getExportsInfo(module)
  171. .getUsedName("default", runtime);
  172. if (used) {
  173. runtimeRequirements.add(RuntimeGlobals.exports);
  174. // This is a little bit incorrect as TDZ is not correct, but we can't use const.
  175. content = `/* harmony default export */ ${exportsName}${propertyAccess(
  176. typeof used === "string" ? [used] : used
  177. )} = `;
  178. } else {
  179. content = `/* unused harmony default export */ var ${name} = `;
  180. }
  181. }
  182. if (dep.range) {
  183. source.replace(
  184. dep.rangeStatement[0],
  185. dep.range[0] - 1,
  186. `${content}(${dep.prefix}`
  187. );
  188. source.replace(dep.range[1], dep.rangeStatement[1] - 0.5, ");");
  189. return;
  190. }
  191. source.replace(dep.rangeStatement[0], dep.rangeStatement[1] - 1, content);
  192. }
  193. }
  194. };
  195. module.exports = HarmonyExportExpressionDependency;