HarmonyCompatibilityDependency.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const { UsageState } = require("../ExportsInfo");
  7. const InitFragment = require("../InitFragment");
  8. const RuntimeGlobals = require("../RuntimeGlobals");
  9. const isGeneratorLowered = require("../async-modules/isGeneratorLowered");
  10. const makeSerializable = require("../util/makeSerializable");
  11. const memoize = require("../util/memoize");
  12. const NullDependency = require("./NullDependency");
  13. // Required here rather than at the top: the plugin reaches back into the dependencies.
  14. const getJavascriptModulesPlugin = memoize(() =>
  15. require("../javascript/JavascriptModulesPlugin")
  16. );
  17. /** @import { ReplaceSource } from "webpack-sources" */
  18. /** @import Dependency from "../Dependency" */
  19. /** @import { DependencyTemplateContext } from "../DependencyTemplate" */
  20. /** @import { BuildMeta } from "../Module" */
  21. /**
  22. * @import {
  23. * JavascriptModuleBuildInfo
  24. * } from "../javascript/JavascriptModule"
  25. */
  26. class HarmonyCompatibilityDependency extends NullDependency {
  27. get type() {
  28. return "harmony export header";
  29. }
  30. }
  31. makeSerializable(
  32. HarmonyCompatibilityDependency,
  33. "webpack/lib/dependencies/HarmonyCompatibilityDependency"
  34. );
  35. HarmonyCompatibilityDependency.Template = class HarmonyExportDependencyTemplate extends (
  36. NullDependency.Template
  37. ) {
  38. /**
  39. * Applies the plugin by registering its hooks on the compiler.
  40. * @param {Dependency} dependency the dependency for which the template should be applied
  41. * @param {ReplaceSource} source the current replace source which can be modified
  42. * @param {DependencyTemplateContext} templateContext the context object
  43. * @returns {void}
  44. */
  45. apply(
  46. dependency,
  47. source,
  48. {
  49. module,
  50. runtimeTemplate,
  51. moduleGraph,
  52. initFragments,
  53. runtimeRequirements,
  54. runtime,
  55. concatenationScope
  56. }
  57. ) {
  58. // a wrapped module has a real exports object that still needs `__esModule`
  59. if (concatenationScope && !concatenationScope.isWrapped()) return;
  60. const exportsInfo = moduleGraph.getExportsInfo(module);
  61. if (
  62. exportsInfo.getReadOnlyExportInfo("__esModule").getUsed(runtime) !==
  63. UsageState.Unused
  64. ) {
  65. const content = runtimeTemplate.defineEsModuleFlagStatement({
  66. exportsArgument: module.exportsArgument,
  67. runtimeRequirements
  68. });
  69. // A library exporting the same bindings natively never reads the marker back
  70. // off the exports object, so it takes the call over and emits it where wrapped.
  71. const hooks = getJavascriptModulesPlugin().getCompilationHooks(
  72. runtimeTemplate.compilation
  73. );
  74. const takenOver =
  75. hooks.onDemandExportsGeneration.isUsed() &&
  76. hooks.onDemandExportsGeneration.call(
  77. module,
  78. runtime,
  79. content,
  80. false
  81. ) === true;
  82. if (!takenOver) {
  83. initFragments.push(
  84. new InitFragment(
  85. content,
  86. InitFragment.STAGE_HARMONY_EXPORTS,
  87. 0,
  88. "harmony compatibility"
  89. )
  90. );
  91. }
  92. }
  93. if (moduleGraph.isAsync(module)) {
  94. runtimeRequirements.add(RuntimeGlobals.module);
  95. const hasAwait = /** @type {BuildMeta} */ (module.buildMeta).async
  96. ? ", 1"
  97. : "";
  98. // A module-scope `await using` is disposed when its scope ends, so the body
  99. // needs a block that closes before the module reports completion —
  100. // otherwise dependents run before disposal is awaited.
  101. const usesTopLevelUsingDeclaration =
  102. /** @type {JavascriptModuleBuildInfo} */
  103. (module.buildInfo).usesTopLevelUsingDeclaration;
  104. const blockStart = usesTopLevelUsingDeclaration ? " {" : "";
  105. const blockEnd = usesTopLevelUsingDeclaration ? "\n}" : "";
  106. // Target has no `async`/`await` but has generators: drive the body as a
  107. // generator so `await` becomes `yield`, keeping the module in a single
  108. // scope (unlike a `.then` callback) without transpiling to a state machine.
  109. if (isGeneratorLowered(module, moduleGraph, runtimeTemplate)) {
  110. runtimeRequirements.add(RuntimeGlobals.asyncModuleGenerator);
  111. initFragments.push(
  112. new InitFragment(
  113. `${RuntimeGlobals.asyncModule}(${module.moduleArgument}, ${RuntimeGlobals.asyncModuleGenerator}(function* (__webpack_handle_async_dependencies__, __webpack_async_result__) { try {${blockStart}\n`,
  114. InitFragment.STAGE_ASYNC_BOUNDARY,
  115. 0,
  116. undefined,
  117. `${blockEnd}\n__webpack_async_result__();\n} catch(e) { __webpack_async_result__(e); } })${hasAwait});`
  118. )
  119. );
  120. } else {
  121. runtimeRequirements.add(RuntimeGlobals.asyncModule);
  122. initFragments.push(
  123. new InitFragment(
  124. runtimeTemplate.supportsArrowFunction()
  125. ? `${RuntimeGlobals.asyncModule}(${module.moduleArgument}, async (__webpack_handle_async_dependencies__, __webpack_async_result__) => { try {${blockStart}\n`
  126. : `${RuntimeGlobals.asyncModule}(${module.moduleArgument}, async function (__webpack_handle_async_dependencies__, __webpack_async_result__) { try {${blockStart}\n`,
  127. InitFragment.STAGE_ASYNC_BOUNDARY,
  128. 0,
  129. undefined,
  130. `${blockEnd}\n__webpack_async_result__();\n} catch(e) { __webpack_async_result__(e); } }${hasAwait});`
  131. )
  132. );
  133. }
  134. }
  135. }
  136. };
  137. module.exports = HarmonyCompatibilityDependency;