HarmonyExportExpressionDependency.js 6.1 KB

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