WasmFinalizeExportsPlugin.js 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const formatLocation = require("../formatLocation");
  7. const UnsupportedWebAssemblyFeatureError = require("./UnsupportedWebAssemblyFeatureError");
  8. /** @typedef {import("../Compiler")} Compiler */
  9. /** @typedef {import("../Dependency")} Dependency */
  10. /** @typedef {import("../Module")} Module */
  11. /** @typedef {import("../Module").BuildMeta} BuildMeta */
  12. const PLUGIN_NAME = "WasmFinalizeExportsPlugin";
  13. class WasmFinalizeExportsPlugin {
  14. /**
  15. * Apply the plugin
  16. * @param {Compiler} compiler the compiler instance
  17. * @returns {void}
  18. */
  19. apply(compiler) {
  20. compiler.hooks.compilation.tap(PLUGIN_NAME, compilation => {
  21. compilation.hooks.finishModules.tap(PLUGIN_NAME, modules => {
  22. for (const module of modules) {
  23. // 1. if a WebAssembly module
  24. if (module.type.startsWith("webassembly") === true) {
  25. const jsIncompatibleExports =
  26. /** @type {BuildMeta} */
  27. (module.buildMeta).jsIncompatibleExports;
  28. if (jsIncompatibleExports === undefined) {
  29. continue;
  30. }
  31. for (const connection of compilation.moduleGraph.getIncomingConnections(
  32. module
  33. )) {
  34. // 2. is active and referenced by a non-WebAssembly module
  35. if (
  36. connection.isTargetActive(undefined) &&
  37. /** @type {Module} */
  38. (connection.originModule).type.startsWith("webassembly") ===
  39. false
  40. ) {
  41. const referencedExports =
  42. compilation.getDependencyReferencedExports(
  43. /** @type {Dependency} */ (connection.dependency),
  44. undefined
  45. );
  46. for (const info of referencedExports) {
  47. const names = Array.isArray(info) ? info : info.name;
  48. if (names.length === 0) continue;
  49. const name = names[0];
  50. if (typeof name === "object") continue;
  51. // 3. and uses a func with an incompatible JS signature
  52. if (
  53. Object.prototype.hasOwnProperty.call(
  54. jsIncompatibleExports,
  55. name
  56. )
  57. ) {
  58. // 4. error
  59. const error = new UnsupportedWebAssemblyFeatureError(
  60. `Export "${name}" with ${jsIncompatibleExports[name]} can only be used for direct wasm to wasm dependencies\n` +
  61. `It's used from ${
  62. /** @type {Module} */
  63. (connection.originModule).readableIdentifier(
  64. compilation.requestShortener
  65. )
  66. } at ${formatLocation(
  67. /** @type {Dependency} */ (connection.dependency).loc
  68. )}.`
  69. );
  70. error.module = module;
  71. compilation.errors.push(error);
  72. }
  73. }
  74. }
  75. }
  76. }
  77. }
  78. });
  79. });
  80. }
  81. }
  82. module.exports = WasmFinalizeExportsPlugin;