WebAssemblyModulesPlugin.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  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 { compareModulesByIdOrIdentifier } = require("../util/comparators");
  15. const memoize = require("../util/memoize");
  16. const WebAssemblyInInitialChunkError = require("./WebAssemblyInInitialChunkError");
  17. /** @typedef {import("../Compiler")} Compiler */
  18. /** @typedef {import("../Module")} Module */
  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_TYPE]: new WebAssemblyJavascriptGenerator(),
  69. [WEBASSEMBLY_TYPE]: 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. compareModulesByIdOrIdentifier(chunkGraph)
  78. )) {
  79. if (module.type === WEBASSEMBLY_MODULE_TYPE_SYNC) {
  80. const filenameTemplate = outputOptions.webassemblyModuleFilename;
  81. result.push({
  82. render: () =>
  83. codeGenerationResults.getSource(
  84. module,
  85. chunk.runtime,
  86. "webassembly"
  87. ),
  88. filenameTemplate,
  89. pathOptions: {
  90. module,
  91. runtime: chunk.runtime,
  92. chunkGraph
  93. },
  94. auxiliary: true,
  95. identifier: `webassemblyModule${chunkGraph.getModuleId(
  96. module
  97. )}`,
  98. hash: chunkGraph.getModuleHash(module, chunk.runtime)
  99. });
  100. }
  101. }
  102. return result;
  103. });
  104. compilation.hooks.afterChunks.tap(PLUGIN_NAME, () => {
  105. const chunkGraph = compilation.chunkGraph;
  106. /** @type {Set<Module>} */
  107. const initialWasmModules = new Set();
  108. for (const chunk of compilation.chunks) {
  109. if (chunk.canBeInitial()) {
  110. for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
  111. if (module.type === WEBASSEMBLY_MODULE_TYPE_SYNC) {
  112. initialWasmModules.add(module);
  113. }
  114. }
  115. }
  116. }
  117. for (const module of initialWasmModules) {
  118. compilation.errors.push(
  119. new WebAssemblyInInitialChunkError(
  120. module,
  121. compilation.moduleGraph,
  122. compilation.chunkGraph,
  123. compilation.requestShortener
  124. )
  125. );
  126. }
  127. });
  128. }
  129. );
  130. }
  131. }
  132. module.exports = WebAssemblyModulesPlugin;