AsyncWebAssemblyModulesPlugin.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const { SyncWaterfallHook } = require("tapable");
  7. const Compilation = require("../Compilation");
  8. const Generator = require("../Generator");
  9. const { tryRunOrWebpackError } = require("../HookWebpackError");
  10. const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency");
  11. const { compareModulesByIdentifier } = require("../util/comparators");
  12. const memoize = require("../util/memoize");
  13. /** @typedef {import("webpack-sources").Source} Source */
  14. /** @typedef {import("../Chunk")} Chunk */
  15. /** @typedef {import("../ChunkGraph")} ChunkGraph */
  16. /** @typedef {import("../CodeGenerationResults")} CodeGenerationResults */
  17. /** @typedef {import("../Compiler")} Compiler */
  18. /** @typedef {import("../DependencyTemplates")} DependencyTemplates */
  19. /** @typedef {import("../Module")} Module */
  20. /** @typedef {import("../ModuleGraph")} ModuleGraph */
  21. /** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
  22. /** @typedef {import("../Template").RenderManifestEntry} RenderManifestEntry */
  23. /** @typedef {import("../Template").RenderManifestOptions} RenderManifestOptions */
  24. const getAsyncWebAssemblyGenerator = memoize(() =>
  25. require("./AsyncWebAssemblyGenerator")
  26. );
  27. const getAsyncWebAssemblyJavascriptGenerator = memoize(() =>
  28. require("./AsyncWebAssemblyJavascriptGenerator")
  29. );
  30. const getAsyncWebAssemblyParser = memoize(() =>
  31. require("./AsyncWebAssemblyParser")
  32. );
  33. /**
  34. * @typedef {Object} WebAssemblyRenderContext
  35. * @property {Chunk} chunk the chunk
  36. * @property {DependencyTemplates} dependencyTemplates the dependency templates
  37. * @property {RuntimeTemplate} runtimeTemplate the runtime template
  38. * @property {ModuleGraph} moduleGraph the module graph
  39. * @property {ChunkGraph} chunkGraph the chunk graph
  40. * @property {CodeGenerationResults} codeGenerationResults results of code generation
  41. */
  42. /**
  43. * @typedef {Object} CompilationHooks
  44. * @property {SyncWaterfallHook<[Source, Module, WebAssemblyRenderContext]>} renderModuleContent
  45. */
  46. /** @type {WeakMap<Compilation, CompilationHooks>} */
  47. const compilationHooksMap = new WeakMap();
  48. class AsyncWebAssemblyModulesPlugin {
  49. /**
  50. * @param {Compilation} compilation the compilation
  51. * @returns {CompilationHooks} the attached hooks
  52. */
  53. static getCompilationHooks(compilation) {
  54. if (!(compilation instanceof Compilation)) {
  55. throw new TypeError(
  56. "The 'compilation' argument must be an instance of Compilation"
  57. );
  58. }
  59. let hooks = compilationHooksMap.get(compilation);
  60. if (hooks === undefined) {
  61. hooks = {
  62. renderModuleContent: new SyncWaterfallHook([
  63. "source",
  64. "module",
  65. "renderContext"
  66. ])
  67. };
  68. compilationHooksMap.set(compilation, hooks);
  69. }
  70. return hooks;
  71. }
  72. constructor(options) {
  73. this.options = options;
  74. }
  75. /**
  76. * Apply the plugin
  77. * @param {Compiler} compiler the compiler instance
  78. * @returns {void}
  79. */
  80. apply(compiler) {
  81. compiler.hooks.compilation.tap(
  82. "AsyncWebAssemblyModulesPlugin",
  83. (compilation, { normalModuleFactory }) => {
  84. const hooks =
  85. AsyncWebAssemblyModulesPlugin.getCompilationHooks(compilation);
  86. compilation.dependencyFactories.set(
  87. WebAssemblyImportDependency,
  88. normalModuleFactory
  89. );
  90. normalModuleFactory.hooks.createParser
  91. .for("webassembly/async")
  92. .tap("AsyncWebAssemblyModulesPlugin", () => {
  93. const AsyncWebAssemblyParser = getAsyncWebAssemblyParser();
  94. return new AsyncWebAssemblyParser();
  95. });
  96. normalModuleFactory.hooks.createGenerator
  97. .for("webassembly/async")
  98. .tap("AsyncWebAssemblyModulesPlugin", () => {
  99. const AsyncWebAssemblyJavascriptGenerator =
  100. getAsyncWebAssemblyJavascriptGenerator();
  101. const AsyncWebAssemblyGenerator = getAsyncWebAssemblyGenerator();
  102. return Generator.byType({
  103. javascript: new AsyncWebAssemblyJavascriptGenerator(
  104. compilation.outputOptions.webassemblyModuleFilename
  105. ),
  106. webassembly: new AsyncWebAssemblyGenerator(this.options)
  107. });
  108. });
  109. compilation.hooks.renderManifest.tap(
  110. "WebAssemblyModulesPlugin",
  111. (result, options) => {
  112. const { moduleGraph, chunkGraph, runtimeTemplate } = compilation;
  113. const {
  114. chunk,
  115. outputOptions,
  116. dependencyTemplates,
  117. codeGenerationResults
  118. } = options;
  119. for (const module of chunkGraph.getOrderedChunkModulesIterable(
  120. chunk,
  121. compareModulesByIdentifier
  122. )) {
  123. if (module.type === "webassembly/async") {
  124. const filenameTemplate =
  125. outputOptions.webassemblyModuleFilename;
  126. result.push({
  127. render: () =>
  128. this.renderModule(
  129. module,
  130. {
  131. chunk,
  132. dependencyTemplates,
  133. runtimeTemplate,
  134. moduleGraph,
  135. chunkGraph,
  136. codeGenerationResults
  137. },
  138. hooks
  139. ),
  140. filenameTemplate,
  141. pathOptions: {
  142. module,
  143. runtime: chunk.runtime,
  144. chunkGraph
  145. },
  146. auxiliary: true,
  147. identifier: `webassemblyAsyncModule${chunkGraph.getModuleId(
  148. module
  149. )}`,
  150. hash: chunkGraph.getModuleHash(module, chunk.runtime)
  151. });
  152. }
  153. }
  154. return result;
  155. }
  156. );
  157. }
  158. );
  159. }
  160. renderModule(module, renderContext, hooks) {
  161. const { codeGenerationResults, chunk } = renderContext;
  162. try {
  163. const moduleSource = codeGenerationResults.getSource(
  164. module,
  165. chunk.runtime,
  166. "webassembly"
  167. );
  168. return tryRunOrWebpackError(
  169. () =>
  170. hooks.renderModuleContent.call(moduleSource, module, renderContext),
  171. "AsyncWebAssemblyModulesPlugin.getCompilationHooks().renderModuleContent"
  172. );
  173. } catch (e) {
  174. e.module = module;
  175. throw e;
  176. }
  177. }
  178. }
  179. module.exports = AsyncWebAssemblyModulesPlugin;