webpack
Version:
Packs ECMAScript/CommonJs/AMD modules for the browser. Allows you to split your codebase into multiple bundles, which can be loaded on demand. Supports loaders to preprocess files, i.e. json, jsx, es7, css, less, ... and your custom stuff.
150 lines (137 loc) • 4.66 kB
JavaScript
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
;
const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
const Template = require("../Template");
/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../Compilation")} Compilation */
/** @typedef {(wasmModuleSrcPath: string) => string} GenerateBeforeLoadBinaryCode */
/** @typedef {(wasmModuleSrcPath: string) => string} GenerateLoadBinaryCode */
/** @typedef {() => string} GenerateBeforeCompileStreaming */
/**
* @typedef {object} AsyncWasmCompileRuntimeModuleOptions
* @property {GenerateLoadBinaryCode} generateLoadBinaryCode
* @property {GenerateBeforeLoadBinaryCode=} generateBeforeLoadBinaryCode
* @property {GenerateBeforeCompileStreaming=} generateBeforeCompileStreaming
* @property {boolean} supportsStreaming
*/
class AsyncWasmCompileRuntimeModule extends RuntimeModule {
/**
* @param {AsyncWasmCompileRuntimeModuleOptions} options options
*/
constructor({
generateLoadBinaryCode,
generateBeforeLoadBinaryCode,
generateBeforeCompileStreaming,
supportsStreaming
}) {
super("wasm compile", RuntimeModule.STAGE_NORMAL);
/** @type {GenerateLoadBinaryCode} */
this.generateLoadBinaryCode = generateLoadBinaryCode;
/** @type {GenerateBeforeLoadBinaryCode | undefined} */
this.generateBeforeLoadBinaryCode = generateBeforeLoadBinaryCode;
/** @type {GenerateBeforeCompileStreaming | undefined} */
this.generateBeforeCompileStreaming = generateBeforeCompileStreaming;
/** @type {boolean} */
this.supportsStreaming = supportsStreaming;
}
/**
* Generates runtime code for this runtime module.
* @returns {string | null} runtime code
*/
generate() {
const compilation = /** @type {Compilation} */ (this.compilation);
const chunk = /** @type {Chunk} */ (this.chunk);
const { outputOptions, runtimeTemplate } = compilation;
const fn = RuntimeGlobals.compileWasm;
const wasmModuleSrcPath = compilation.getPath(
JSON.stringify(outputOptions.webassemblyModuleFilename),
{
hash: `" + ${RuntimeGlobals.getFullHash}() + "`,
hashWithLength: (length) =>
`" + ${RuntimeGlobals.getFullHash}}().slice(0, ${length}) + "`,
module: {
id: '" + wasmModuleId + "',
hash: '" + wasmModuleHash + "',
hashWithLength(length) {
return `" + wasmModuleHash.slice(0, ${length}) + "`;
}
},
runtime: chunk.runtime
}
);
const loader = this.generateLoadBinaryCode(wasmModuleSrcPath);
// Fallback path: fetch -> arrayBuffer -> WebAssembly.compile
const fallback = [
`.then(${runtimeTemplate.returningFunction("x.arrayBuffer()", "x")})`,
`.then(${runtimeTemplate.returningFunction(
"WebAssembly.compile(bytes)",
"bytes"
)})`
];
const getStreaming = () => {
/**
* @param {string[]} text text
* @returns {string} merged text
*/
const concat = (...text) => text.join("");
return [
this.generateBeforeLoadBinaryCode
? this.generateBeforeLoadBinaryCode(wasmModuleSrcPath)
: "",
`var req = ${loader};`,
`var fallback = ${runtimeTemplate.returningFunction(
Template.asString(["req", Template.indent(fallback)])
)};`,
concat(
"return req.then(",
runtimeTemplate.basicFunction("res", [
'if (typeof WebAssembly.compileStreaming === "function") {',
Template.indent(
this.generateBeforeCompileStreaming
? this.generateBeforeCompileStreaming()
: ""
),
Template.indent([
"return WebAssembly.compileStreaming(res)",
Template.indent([
".catch(",
Template.indent([
runtimeTemplate.basicFunction("e", [
'if(res.headers.get("Content-Type") !== "application/wasm") {',
Template.indent([
'console.warn("`WebAssembly.compileStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.compile` which is slower. Original error:\\n", e);',
"return fallback();"
]),
"}",
"throw e;"
])
]),
");"
])
]),
"}",
"return fallback();"
]),
");"
)
];
};
return `${fn} = ${runtimeTemplate.basicFunction(
"wasmModuleId, wasmModuleHash",
this.supportsStreaming
? getStreaming()
: [
this.generateBeforeLoadBinaryCode
? this.generateBeforeLoadBinaryCode(wasmModuleSrcPath)
: "",
`return ${loader}`,
`${Template.indent(fallback)};`
]
)};`;
}
}
module.exports = AsyncWasmCompileRuntimeModule;