ReadFileCompileAsyncWasmPlugin.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const { WEBASSEMBLY_MODULE_TYPE_ASYNC } = require("../ModuleTypeConstants");
  7. const RuntimeGlobals = require("../RuntimeGlobals");
  8. const Template = require("../Template");
  9. const AsyncWasmLoadingRuntimeModule = require("../wasm-async/AsyncWasmLoadingRuntimeModule");
  10. /** @typedef {import("../Chunk")} Chunk */
  11. /** @typedef {import("../Compiler")} Compiler */
  12. /**
  13. * @typedef {object} ReadFileCompileAsyncWasmPluginOptions
  14. * @property {boolean} [import] use import?
  15. */
  16. const PLUGIN_NAME = "ReadFileCompileAsyncWasmPlugin";
  17. class ReadFileCompileAsyncWasmPlugin {
  18. /**
  19. * @param {ReadFileCompileAsyncWasmPluginOptions} [options] options object
  20. */
  21. constructor({ import: useImport = false } = {}) {
  22. this._import = useImport;
  23. }
  24. /**
  25. * Apply the plugin
  26. * @param {Compiler} compiler the compiler instance
  27. * @returns {void}
  28. */
  29. apply(compiler) {
  30. compiler.hooks.thisCompilation.tap(PLUGIN_NAME, compilation => {
  31. const globalWasmLoading = compilation.outputOptions.wasmLoading;
  32. /**
  33. * @param {Chunk} chunk chunk
  34. * @returns {boolean} true, if wasm loading is enabled for the chunk
  35. */
  36. const isEnabledForChunk = chunk => {
  37. const options = chunk.getEntryOptions();
  38. const wasmLoading =
  39. options && options.wasmLoading !== undefined
  40. ? options.wasmLoading
  41. : globalWasmLoading;
  42. return wasmLoading === "async-node";
  43. };
  44. /**
  45. * @param {string} path path to wasm file
  46. * @returns {string} generated code to load the wasm file
  47. */
  48. const generateLoadBinaryCode = this._import
  49. ? path =>
  50. Template.asString([
  51. "Promise.all([import('fs'), import('url')]).then(([{ readFile }, { URL }]) => new Promise((resolve, reject) => {",
  52. Template.indent([
  53. `readFile(new URL(${path}, ${compilation.outputOptions.importMetaName}.url), (err, buffer) => {`,
  54. Template.indent([
  55. "if (err) return reject(err);",
  56. "",
  57. "// Fake fetch response",
  58. "resolve({",
  59. Template.indent(["arrayBuffer() { return buffer; }"]),
  60. "});"
  61. ]),
  62. "});"
  63. ]),
  64. "}))"
  65. ])
  66. : path =>
  67. Template.asString([
  68. "new Promise(function (resolve, reject) {",
  69. Template.indent([
  70. "try {",
  71. Template.indent([
  72. "var { readFile } = require('fs');",
  73. "var { join } = require('path');",
  74. "",
  75. `readFile(join(__dirname, ${path}), function(err, buffer){`,
  76. Template.indent([
  77. "if (err) return reject(err);",
  78. "",
  79. "// Fake fetch response",
  80. "resolve({",
  81. Template.indent(["arrayBuffer() { return buffer; }"]),
  82. "});"
  83. ]),
  84. "});"
  85. ]),
  86. "} catch (err) { reject(err); }"
  87. ]),
  88. "})"
  89. ]);
  90. compilation.hooks.runtimeRequirementInTree
  91. .for(RuntimeGlobals.instantiateWasm)
  92. .tap(PLUGIN_NAME, (chunk, set, { chunkGraph }) => {
  93. if (!isEnabledForChunk(chunk)) return;
  94. if (
  95. !chunkGraph.hasModuleInGraph(
  96. chunk,
  97. m => m.type === WEBASSEMBLY_MODULE_TYPE_ASYNC
  98. )
  99. ) {
  100. return;
  101. }
  102. compilation.addRuntimeModule(
  103. chunk,
  104. new AsyncWasmLoadingRuntimeModule({
  105. generateLoadBinaryCode,
  106. supportsStreaming: false
  107. })
  108. );
  109. });
  110. });
  111. }
  112. }
  113. module.exports = ReadFileCompileAsyncWasmPlugin;