WasmFinalizeExportsPlugin.js 2.8 KB

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