2019-05-24 18:30:43 +08:00
/ *
MIT License http : //www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @ sokra
* /
"use strict" ;
const RuntimeGlobals = require ( "../RuntimeGlobals" ) ;
const RuntimeModule = require ( "../RuntimeModule" ) ;
const Template = require ( "../Template" ) ;
2023-06-12 22:21:21 +08:00
/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../Compilation")} Compilation */
2023-05-26 02:31:28 +08:00
/ * *
2024-06-11 21:09:50 +08:00
* @ typedef { object } AsyncWasmLoadingRuntimeModuleOptions
2024-11-14 08:01:30 +08:00
* @ property { ( function ( string ) : string ) = } generateBeforeLoadBinaryCode
2023-05-26 02:31:28 +08:00
* @ property { function ( string ) : string } generateLoadBinaryCode
2024-11-14 09:50:01 +08:00
* @ property { ( function ( ) : string ) = } generateBeforeInstantiateStreaming
2023-05-26 02:31:28 +08:00
* @ property { boolean } supportsStreaming
* /
2021-08-16 15:43:50 +08:00
class AsyncWasmLoadingRuntimeModule extends RuntimeModule {
2023-05-26 02:31:28 +08:00
/ * *
* @ param { AsyncWasmLoadingRuntimeModuleOptions } options options
* /
2024-11-14 08:01:30 +08:00
constructor ( {
generateLoadBinaryCode ,
generateBeforeLoadBinaryCode ,
2024-11-14 09:50:01 +08:00
generateBeforeInstantiateStreaming ,
2024-11-14 08:01:30 +08:00
supportsStreaming
} ) {
2021-08-16 15:43:50 +08:00
super ( "wasm loading" , RuntimeModule . STAGE _NORMAL ) ;
2019-05-24 18:30:43 +08:00
this . generateLoadBinaryCode = generateLoadBinaryCode ;
2024-11-14 08:01:30 +08:00
this . generateBeforeLoadBinaryCode = generateBeforeLoadBinaryCode ;
2024-11-14 09:50:01 +08:00
this . generateBeforeInstantiateStreaming =
generateBeforeInstantiateStreaming ;
2019-05-24 18:30:43 +08:00
this . supportsStreaming = supportsStreaming ;
}
/ * *
2023-06-17 01:13:03 +08:00
* @ returns { string | null } runtime code
2019-05-24 18:30:43 +08:00
* /
generate ( ) {
2023-06-12 22:21:21 +08:00
const compilation = /** @type {Compilation} */ ( this . compilation ) ;
const chunk = /** @type {Chunk} */ ( this . chunk ) ;
2020-07-28 23:08:22 +08:00
const { outputOptions , runtimeTemplate } = compilation ;
2019-05-24 18:30:43 +08:00
const fn = RuntimeGlobals . instantiateWasm ;
2019-10-04 18:24:52 +08:00
const wasmModuleSrcPath = compilation . getPath (
2019-05-24 18:30:43 +08:00
JSON . stringify ( outputOptions . webassemblyModuleFilename ) ,
{
hash : ` " + ${ RuntimeGlobals . getFullHash } () + " ` ,
hashWithLength : length =>
` " + ${ RuntimeGlobals . getFullHash } }().slice(0, ${ length } ) + " ` ,
module : {
id : '" + wasmModuleId + "' ,
2024-10-14 11:02:08 +08:00
hash : '" + wasmModuleHash + "' ,
2019-05-24 18:30:43 +08:00
hashWithLength ( length ) {
2020-07-28 23:08:22 +08:00
return ` " + wasmModuleHash.slice(0, ${ length } ) + " ` ;
2019-05-24 18:30:43 +08:00
}
2020-07-28 00:09:48 +08:00
} ,
runtime : chunk . runtime
2019-05-24 18:30:43 +08:00
}
) ;
2024-01-27 13:08:13 +08:00
const loader = this . generateLoadBinaryCode ( wasmModuleSrcPath ) ;
const fallback = [
` .then( ${ runtimeTemplate . returningFunction ( "x.arrayBuffer()" , "x" ) } ) ` ,
` .then( ${ runtimeTemplate . returningFunction (
"WebAssembly.instantiate(bytes, importsObj)" ,
"bytes"
) } ) ` ,
` .then( ${ runtimeTemplate . returningFunction (
"Object.assign(exports, res.instance.exports)" ,
"res"
) } ) `
] ;
const getStreaming = ( ) => {
const concat = ( /** @type {string[]} */ ... text ) => text . join ( "" ) ;
return [
2024-11-14 08:01:30 +08:00
this . generateBeforeLoadBinaryCode
? this . generateBeforeLoadBinaryCode ( wasmModuleSrcPath )
: "" ,
2024-01-27 13:08:13 +08:00
` var req = ${ loader } ; ` ,
2024-06-11 21:09:50 +08:00
` var fallback = ${ runtimeTemplate . returningFunction (
Template . asString ( [ "req" , Template . indent ( fallback ) ] )
) } ; ` ,
2024-01-27 13:08:13 +08:00
concat (
"return req.then(" ,
runtimeTemplate . basicFunction ( "res" , [
2024-10-14 11:02:08 +08:00
'if (typeof WebAssembly.instantiateStreaming === "function") {' ,
2024-11-14 09:50:01 +08:00
Template . indent (
this . generateBeforeInstantiateStreaming
? this . generateBeforeInstantiateStreaming ( )
: ""
) ,
2024-01-27 13:08:13 +08:00
Template . indent ( [
"return WebAssembly.instantiateStreaming(res, importsObj)" ,
2024-01-30 20:06:52 +08:00
Template . indent ( [
".then(" ,
Template . indent ( [
2024-07-31 10:39:30 +08:00
` ${ runtimeTemplate . returningFunction (
2024-01-30 20:06:52 +08:00
"Object.assign(exports, res.instance.exports)" ,
"res"
2024-07-31 10:39:30 +08:00
) } , ` ,
2024-01-27 13:08:13 +08:00
runtimeTemplate . basicFunction ( "e" , [
2024-10-14 11:02:08 +08:00
'if(res.headers.get("Content-Type") !== "application/wasm") {' ,
2024-01-27 13:08:13 +08:00
Template . indent ( [
'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);' ,
"return fallback();"
] ) ,
"}" ,
"throw e;"
2024-01-30 20:06:52 +08:00
] )
] ) ,
");"
] )
2024-01-27 13:08:13 +08:00
] ) ,
"}" ,
"return fallback();"
] ) ,
");"
)
] ;
} ;
2020-07-28 23:08:22 +08:00
return ` ${ fn } = ${ runtimeTemplate . basicFunction (
"exports, wasmModuleId, wasmModuleHash, importsObj" ,
2024-01-27 13:08:13 +08:00
this . supportsStreaming
? getStreaming ( )
2024-11-14 08:01:30 +08:00
: [
this . generateBeforeLoadBinaryCode
? this . generateBeforeLoadBinaryCode ( wasmModuleSrcPath )
: "" ,
` return ${ loader } ` ,
` ${ Template . indent ( fallback ) } ; `
]
2020-07-28 23:08:22 +08:00
) } ; ` ;
2019-05-24 18:30:43 +08:00
}
}
2021-08-16 15:43:50 +08:00
module . exports = AsyncWasmLoadingRuntimeModule ;