ReadFileCompileAsyncWasmPlugin.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  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. * @type {(path: string) => string} callback to generate code to load the wasm file
  46. */
  47. const generateLoadBinaryCode = this._import
  48. ? path =>
  49. Template.asString([
  50. "Promise.all([import('fs'), import('url')]).then(([{ readFile }, { URL }]) => new Promise((resolve, reject) => {",
  51. Template.indent([
  52. `readFile(new URL(${path}, ${compilation.outputOptions.importMetaName}.url), (err, buffer) => {`,
  53. Template.indent([
  54. "if (err) return reject(err);",
  55. "",
  56. "// Fake fetch response",
  57. "resolve({",
  58. Template.indent(["arrayBuffer() { return buffer; }"]),
  59. "});"
  60. ]),
  61. "});"
  62. ]),
  63. "}))"
  64. ])
  65. : path =>
  66. Template.asString([
  67. "new Promise(function (resolve, reject) {",
  68. Template.indent([
  69. "try {",
  70. Template.indent([
  71. "var { readFile } = require('fs');",
  72. "var { join } = require('path');",
  73. "",
  74. `readFile(join(__dirname, ${path}), function(err, buffer){`,
  75. Template.indent([
  76. "if (err) return reject(err);",
  77. "",
  78. "// Fake fetch response",
  79. "resolve({",
  80. Template.indent(["arrayBuffer() { return buffer; }"]),
  81. "});"
  82. ]),
  83. "});"
  84. ]),
  85. "} catch (err) { reject(err); }"
  86. ]),
  87. "})"
  88. ]);
  89. compilation.hooks.runtimeRequirementInTree
  90. .for(RuntimeGlobals.instantiateWasm)
  91. .tap(PLUGIN_NAME, (chunk, set, { chunkGraph }) => {
  92. if (!isEnabledForChunk(chunk)) return;
  93. if (
  94. !chunkGraph.hasModuleInGraph(
  95. chunk,
  96. m => m.type === WEBASSEMBLY_MODULE_TYPE_ASYNC
  97. )
  98. ) {
  99. return;
  100. }
  101. compilation.addRuntimeModule(
  102. chunk,
  103. new AsyncWasmLoadingRuntimeModule({
  104. generateLoadBinaryCode,
  105. supportsStreaming: false
  106. })
  107. );
  108. });
  109. });
  110. }
  111. }
  112. module.exports = ReadFileCompileAsyncWasmPlugin;