AsyncWebAssemblyModulesPlugin.js 5.9 KB

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