AsyncWasmLoadingRuntimeModule.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const RuntimeGlobals = require("../RuntimeGlobals");
  7. const RuntimeModule = require("../RuntimeModule");
  8. const Template = require("../Template");
  9. /** @typedef {import("../Chunk")} Chunk */
  10. /** @typedef {import("../Compilation")} Compilation */
  11. /**
  12. * @typedef {object} AsyncWasmLoadingRuntimeModuleOptions
  13. * @property {function(string): string} generateLoadBinaryCode
  14. * @property {boolean} supportsStreaming
  15. */
  16. class AsyncWasmLoadingRuntimeModule extends RuntimeModule {
  17. /**
  18. * @param {AsyncWasmLoadingRuntimeModuleOptions} options options
  19. */
  20. constructor({ generateLoadBinaryCode, supportsStreaming }) {
  21. super("wasm loading", RuntimeModule.STAGE_NORMAL);
  22. this.generateLoadBinaryCode = generateLoadBinaryCode;
  23. this.supportsStreaming = supportsStreaming;
  24. }
  25. /**
  26. * @returns {string | null} runtime code
  27. */
  28. generate() {
  29. const compilation = /** @type {Compilation} */ (this.compilation);
  30. const chunk = /** @type {Chunk} */ (this.chunk);
  31. const { outputOptions, runtimeTemplate } = compilation;
  32. const fn = RuntimeGlobals.instantiateWasm;
  33. const wasmModuleSrcPath = compilation.getPath(
  34. JSON.stringify(outputOptions.webassemblyModuleFilename),
  35. {
  36. hash: `" + ${RuntimeGlobals.getFullHash}() + "`,
  37. hashWithLength: length =>
  38. `" + ${RuntimeGlobals.getFullHash}}().slice(0, ${length}) + "`,
  39. module: {
  40. id: '" + wasmModuleId + "',
  41. hash: `" + wasmModuleHash + "`,
  42. hashWithLength(length) {
  43. return `" + wasmModuleHash.slice(0, ${length}) + "`;
  44. }
  45. },
  46. runtime: chunk.runtime
  47. }
  48. );
  49. const loader = this.generateLoadBinaryCode(wasmModuleSrcPath);
  50. const fallback = [
  51. `.then(${runtimeTemplate.returningFunction("x.arrayBuffer()", "x")})`,
  52. `.then(${runtimeTemplate.returningFunction(
  53. "WebAssembly.instantiate(bytes, importsObj)",
  54. "bytes"
  55. )})`,
  56. `.then(${runtimeTemplate.returningFunction(
  57. "Object.assign(exports, res.instance.exports)",
  58. "res"
  59. )})`
  60. ];
  61. const getStreaming = () => {
  62. const concat = (/** @type {string[]} */ ...text) => text.join("");
  63. return [
  64. `var req = ${loader};`,
  65. `var fallback = ${runtimeTemplate.returningFunction(
  66. Template.asString(["req", Template.indent(fallback)])
  67. )};`,
  68. concat(
  69. "return req.then(",
  70. runtimeTemplate.basicFunction("res", [
  71. `if (typeof WebAssembly.instantiateStreaming === "function") {`,
  72. Template.indent([
  73. "return WebAssembly.instantiateStreaming(res, importsObj)",
  74. Template.indent([
  75. ".then(",
  76. Template.indent([
  77. runtimeTemplate.returningFunction(
  78. "Object.assign(exports, res.instance.exports)",
  79. "res"
  80. ) + ",",
  81. runtimeTemplate.basicFunction("e", [
  82. `if(res.headers.get("Content-Type") !== "application/wasm") {`,
  83. Template.indent([
  84. 'console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\\n", e);',
  85. "return fallback();"
  86. ]),
  87. "}",
  88. "throw e;"
  89. ])
  90. ]),
  91. ");"
  92. ])
  93. ]),
  94. "}",
  95. "return fallback();"
  96. ]),
  97. ");"
  98. )
  99. ];
  100. };
  101. return `${fn} = ${runtimeTemplate.basicFunction(
  102. "exports, wasmModuleId, wasmModuleHash, importsObj",
  103. this.supportsStreaming
  104. ? getStreaming()
  105. : [`return ${loader}`, Template.indent(fallback) + ";"]
  106. )};`;
  107. }
  108. }
  109. module.exports = AsyncWasmLoadingRuntimeModule;