WebAssemblyModulesPlugin.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const Generator = require("../Generator");
  7. const {
  8. JAVASCRIPT_TYPE,
  9. WEBASSEMBLY_TYPE
  10. } = require("../ModuleSourceTypeConstants");
  11. const { WEBASSEMBLY_MODULE_TYPE_SYNC } = require("../ModuleTypeConstants");
  12. const WebAssemblyExportImportedDependency = require("../dependencies/WebAssemblyExportImportedDependency");
  13. const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency");
  14. const { compareModulesByFullName } = require("../util/comparators");
  15. const lazyModule = require("../util/lazyModule");
  16. const preloadModuleType = require("../util/preloadModuleType");
  17. const WebAssemblyInInitialChunkError = require("./WebAssemblyInInitialChunkError");
  18. /** @import Compiler from "../Compiler" */
  19. /** @import Module from "../Module" */
  20. const getWebAssemblyGenerator = lazyModule(() =>
  21. require("./WebAssemblyGenerator")
  22. );
  23. const getWebAssemblyJavascriptGenerator = lazyModule(() =>
  24. require("./WebAssemblyJavascriptGenerator")
  25. );
  26. const getWebAssemblyParser = lazyModule(() => require("./WebAssemblyParser"));
  27. const getSyncWasmModule = lazyModule(() => require("./SyncWasmModule"));
  28. const PLUGIN_NAME = "WebAssemblyModulesPlugin";
  29. /**
  30. * Options that influence how synchronous WebAssembly modules are transformed
  31. * and emitted.
  32. * @typedef {object} WebAssemblyModulesPluginOptions
  33. * @property {boolean=} mangleImports mangle imports
  34. */
  35. /**
  36. * Adds parser, generator, manifest, and validation support for synchronous
  37. * WebAssembly modules in the compilation pipeline.
  38. */
  39. class WebAssemblyModulesPlugin {
  40. /**
  41. * Stores options that affect generated synchronous WebAssembly output.
  42. * @param {WebAssemblyModulesPluginOptions} options options
  43. */
  44. constructor(options) {
  45. /** @type {WebAssemblyModulesPluginOptions} */
  46. this.options = options;
  47. }
  48. /**
  49. * Registers compilation hooks that parse and generate sync WebAssembly
  50. * modules, emit their binary assets, and report invalid placement in initial
  51. * chunks.
  52. * @param {Compiler} compiler the compiler instance
  53. * @returns {void}
  54. */
  55. apply(compiler) {
  56. compiler.hooks.compilation.tap(
  57. PLUGIN_NAME,
  58. (compilation, { normalModuleFactory }) => {
  59. compilation.dependencyFactories.set(
  60. WebAssemblyImportDependency,
  61. normalModuleFactory
  62. );
  63. compilation.dependencyFactories.set(
  64. WebAssemblyExportImportedDependency,
  65. normalModuleFactory
  66. );
  67. preloadModuleType(normalModuleFactory, PLUGIN_NAME, [
  68. [
  69. WEBASSEMBLY_MODULE_TYPE_SYNC,
  70. [
  71. getSyncWasmModule,
  72. getWebAssemblyParser,
  73. getWebAssemblyJavascriptGenerator,
  74. getWebAssemblyGenerator
  75. ]
  76. ]
  77. ]);
  78. normalModuleFactory.hooks.createModuleClass
  79. .for(WEBASSEMBLY_MODULE_TYPE_SYNC)
  80. .tap(PLUGIN_NAME, (createData, _resolveData) => {
  81. const SyncWasmModule = getSyncWasmModule.loaded();
  82. return new SyncWasmModule(createData);
  83. });
  84. normalModuleFactory.hooks.createParser
  85. .for(WEBASSEMBLY_MODULE_TYPE_SYNC)
  86. .tap(PLUGIN_NAME, () => {
  87. const WebAssemblyParser = getWebAssemblyParser.loaded();
  88. return new WebAssemblyParser();
  89. });
  90. normalModuleFactory.hooks.createGenerator
  91. .for(WEBASSEMBLY_MODULE_TYPE_SYNC)
  92. .tap(PLUGIN_NAME, () => {
  93. const WebAssemblyJavascriptGenerator =
  94. getWebAssemblyJavascriptGenerator.loaded();
  95. const WebAssemblyGenerator = getWebAssemblyGenerator.loaded();
  96. return Generator.byType({
  97. [JAVASCRIPT_TYPE]: new WebAssemblyJavascriptGenerator(),
  98. [WEBASSEMBLY_TYPE]: new WebAssemblyGenerator(this.options)
  99. });
  100. });
  101. compilation.hooks.renderManifest.tap(PLUGIN_NAME, (result, options) => {
  102. const { chunkGraph } = compilation;
  103. const { chunk, outputOptions, codeGenerationResults } = options;
  104. for (const module of chunkGraph.getOrderedChunkModulesIterable(
  105. chunk,
  106. compareModulesByFullName(compiler)
  107. )) {
  108. if (module.type === WEBASSEMBLY_MODULE_TYPE_SYNC) {
  109. const filenameTemplate = outputOptions.webassemblyModuleFilename;
  110. result.push({
  111. render: () =>
  112. codeGenerationResults.getSource(
  113. module,
  114. chunk.runtime,
  115. "webassembly"
  116. ),
  117. filenameTemplate,
  118. pathOptions: {
  119. module,
  120. runtime: chunk.runtime,
  121. chunkGraph
  122. },
  123. auxiliary: true,
  124. identifier: `webassemblyModule${chunkGraph.getModuleId(
  125. module
  126. )}`,
  127. hash: chunkGraph.getModuleHash(module, chunk.runtime)
  128. });
  129. }
  130. }
  131. return result;
  132. });
  133. compilation.hooks.afterChunks.tap(PLUGIN_NAME, () => {
  134. const chunkGraph = compilation.chunkGraph;
  135. /** @type {Set<Module>} */
  136. const initialWasmModules = new Set();
  137. for (const chunk of compilation.chunks) {
  138. if (chunk.canBeInitial()) {
  139. for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
  140. if (module.type === WEBASSEMBLY_MODULE_TYPE_SYNC) {
  141. initialWasmModules.add(module);
  142. }
  143. }
  144. }
  145. }
  146. for (const module of initialWasmModules) {
  147. compilation.errors.push(
  148. new WebAssemblyInInitialChunkError(
  149. module,
  150. compilation.moduleGraph,
  151. compilation.chunkGraph,
  152. compilation.requestShortener
  153. )
  154. );
  155. }
  156. });
  157. }
  158. );
  159. }
  160. }
  161. module.exports = WebAssemblyModulesPlugin;