WebAssemblyModulesPlugin.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  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 { WEBASSEMBLY_MODULE_TYPE_SYNC } = require("../ModuleTypeConstants");
  8. const WebAssemblyExportImportedDependency = require("../dependencies/WebAssemblyExportImportedDependency");
  9. const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency");
  10. const { compareModulesByIdentifier } = require("../util/comparators");
  11. const memoize = require("../util/memoize");
  12. const WebAssemblyInInitialChunkError = require("./WebAssemblyInInitialChunkError");
  13. /** @typedef {import("webpack-sources").Source} Source */
  14. /** @typedef {import("../../declarations/WebpackOptions").OutputNormalized} OutputOptions */
  15. /** @typedef {import("../Compiler")} Compiler */
  16. /** @typedef {import("../Module")} Module */
  17. /** @typedef {import("../ModuleTemplate")} ModuleTemplate */
  18. /** @typedef {import("../javascript/JavascriptModulesPlugin").RenderContext} RenderContext */
  19. const getWebAssemblyGenerator = memoize(() =>
  20. require("./WebAssemblyGenerator")
  21. );
  22. const getWebAssemblyJavascriptGenerator = memoize(() =>
  23. require("./WebAssemblyJavascriptGenerator")
  24. );
  25. const getWebAssemblyParser = memoize(() => require("./WebAssemblyParser"));
  26. const PLUGIN_NAME = "WebAssemblyModulesPlugin";
  27. /**
  28. * @typedef {object} WebAssemblyModulesPluginOptions
  29. * @property {boolean} [mangleImports] mangle imports
  30. */
  31. class WebAssemblyModulesPlugin {
  32. /**
  33. * @param {WebAssemblyModulesPluginOptions} options options
  34. */
  35. constructor(options) {
  36. this.options = options;
  37. }
  38. /**
  39. * Apply the plugin
  40. * @param {Compiler} compiler the compiler instance
  41. * @returns {void}
  42. */
  43. apply(compiler) {
  44. compiler.hooks.compilation.tap(
  45. PLUGIN_NAME,
  46. (compilation, { normalModuleFactory }) => {
  47. compilation.dependencyFactories.set(
  48. WebAssemblyImportDependency,
  49. normalModuleFactory
  50. );
  51. compilation.dependencyFactories.set(
  52. WebAssemblyExportImportedDependency,
  53. normalModuleFactory
  54. );
  55. normalModuleFactory.hooks.createParser
  56. .for(WEBASSEMBLY_MODULE_TYPE_SYNC)
  57. .tap(PLUGIN_NAME, () => {
  58. const WebAssemblyParser = getWebAssemblyParser();
  59. return new WebAssemblyParser();
  60. });
  61. normalModuleFactory.hooks.createGenerator
  62. .for(WEBASSEMBLY_MODULE_TYPE_SYNC)
  63. .tap(PLUGIN_NAME, () => {
  64. const WebAssemblyJavascriptGenerator =
  65. getWebAssemblyJavascriptGenerator();
  66. const WebAssemblyGenerator = getWebAssemblyGenerator();
  67. return Generator.byType({
  68. javascript: new WebAssemblyJavascriptGenerator(),
  69. webassembly: new WebAssemblyGenerator(this.options)
  70. });
  71. });
  72. compilation.hooks.renderManifest.tap(PLUGIN_NAME, (result, options) => {
  73. const { chunkGraph } = compilation;
  74. const { chunk, outputOptions, codeGenerationResults } = options;
  75. for (const module of chunkGraph.getOrderedChunkModulesIterable(
  76. chunk,
  77. compareModulesByIdentifier
  78. )) {
  79. if (module.type === WEBASSEMBLY_MODULE_TYPE_SYNC) {
  80. const filenameTemplate =
  81. /** @type {NonNullable<OutputOptions["webassemblyModuleFilename"]>} */
  82. (outputOptions.webassemblyModuleFilename);
  83. result.push({
  84. render: () =>
  85. codeGenerationResults.getSource(
  86. module,
  87. chunk.runtime,
  88. "webassembly"
  89. ),
  90. filenameTemplate,
  91. pathOptions: {
  92. module,
  93. runtime: chunk.runtime,
  94. chunkGraph
  95. },
  96. auxiliary: true,
  97. identifier: `webassemblyModule${chunkGraph.getModuleId(
  98. module
  99. )}`,
  100. hash: chunkGraph.getModuleHash(module, chunk.runtime)
  101. });
  102. }
  103. }
  104. return result;
  105. });
  106. compilation.hooks.afterChunks.tap(PLUGIN_NAME, () => {
  107. const chunkGraph = compilation.chunkGraph;
  108. const initialWasmModules = new Set();
  109. for (const chunk of compilation.chunks) {
  110. if (chunk.canBeInitial()) {
  111. for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
  112. if (module.type === WEBASSEMBLY_MODULE_TYPE_SYNC) {
  113. initialWasmModules.add(module);
  114. }
  115. }
  116. }
  117. }
  118. for (const module of initialWasmModules) {
  119. compilation.errors.push(
  120. new WebAssemblyInInitialChunkError(
  121. module,
  122. compilation.moduleGraph,
  123. compilation.chunkGraph,
  124. compilation.requestShortener
  125. )
  126. );
  127. }
  128. });
  129. }
  130. );
  131. }
  132. }
  133. module.exports = WebAssemblyModulesPlugin;