Improving wasm loading logic (#1996)

* Improving wasm loading logic

* Adding in note to the book about the new loading functionality
This commit is contained in:
Pauan
2020-02-11 17:58:42 +01:00
committed by GitHub
parent 91f0dbdb28
commit ca742a84c4
2 changed files with 66 additions and 49 deletions

View File

@ -434,20 +434,20 @@ impl<'a> Context<'a> {
let default_module_path = match self.config.mode { let default_module_path = match self.config.mode {
OutputMode::Web => { OutputMode::Web => {
"\ "\
if (typeof module === 'undefined') { if (typeof input === 'undefined') {
module = import.meta.url.replace(/\\.js$/, '_bg.wasm'); input = import.meta.url.replace(/\\.js$/, '_bg.wasm');
}" }"
} }
OutputMode::NoModules { .. } => { OutputMode::NoModules { .. } => {
"\ "\
if (typeof module === 'undefined') { if (typeof input === 'undefined') {
let src; let src;
if (document === undefined) { if (document === undefined) {
src = location.href; src = location.href;
} else { } else {
src = document.currentScript.src; src = document.currentScript.src;
} }
module = src.replace(/\\.js$/, '_bg.wasm'); input = src.replace(/\\.js$/, '_bg.wasm');
}" }"
} }
_ => "", _ => "",
@ -504,54 +504,58 @@ impl<'a> Context<'a> {
let js = format!( let js = format!(
"\ "\
function init(module{init_memory_arg}) {{ async function load(module, imports) {{
{default_module_path} if (typeof Response === 'function' && module instanceof Response) {{
let result;
const imports = {{}};
{imports_init}
if ((typeof URL === 'function' && module instanceof URL) || typeof module === 'string' || (typeof Request === 'function' && module instanceof Request)) {{
{init_memory2} {init_memory2}
const response = fetch(module);
if (typeof WebAssembly.instantiateStreaming === 'function') {{ if (typeof WebAssembly.instantiateStreaming === 'function') {{
result = WebAssembly.instantiateStreaming(response, imports) try {{
.catch(e => {{ return await WebAssembly.instantiateStreaming(module, imports);
return response
.then(r => {{ }} catch (e) {{
if (r.headers.get('Content-Type') != 'application/wasm') {{ if (module.headers.get('Content-Type') != 'application/wasm') {{
console.warn(\"`WebAssembly.instantiateStreaming` failed \ console.warn(\"`WebAssembly.instantiateStreaming` failed \
because your server does not serve wasm with \ because your server does not serve wasm with \
`application/wasm` MIME type. Falling back to \ `application/wasm` MIME type. Falling back to \
`WebAssembly.instantiate` which is slower. Original \ `WebAssembly.instantiate` which is slower. Original \
error:\\n\", e); error:\\n\", e);
return r.arrayBuffer();
}} else {{ }} else {{
throw e; throw e;
}} }}
}}) }}
.then(bytes => WebAssembly.instantiate(bytes, imports));
}});
}} else {{
result = response
.then(r => r.arrayBuffer())
.then(bytes => WebAssembly.instantiate(bytes, imports));
}} }}
const bytes = await module.arrayBuffer();
return await WebAssembly.instantiate(bytes, imports);
}} else {{ }} else {{
{init_memory1} {init_memory1}
result = WebAssembly.instantiate(module, imports) const instance = await WebAssembly.instantiate(module, imports);
.then(result => {{
if (result instanceof WebAssembly.Instance) {{ if (instance instanceof WebAssembly.Instance) {{
return {{ instance: result, module }}; return {{ instance, module }};
}} else {{
return result; }} else {{
}} return instance;
}}); }}
}} }}
return result.then(({{instance, module}}) => {{ }}
wasm = instance.exports;
init.__wbindgen_wasm_module = module; async function init(input{init_memory_arg}) {{
{start} {default_module_path}
return wasm; const imports = {{}};
}}); {imports_init}
if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) {{
input = fetch(input);
}}
const {{ instance, module }} = await load(await input, imports);
wasm = instance.exports;
init.__wbindgen_wasm_module = module;
{start}
return wasm;
}} }}
", ",
init_memory_arg = init_memory_arg, init_memory_arg = init_memory_arg,

View File

@ -19,12 +19,25 @@
// default export to inform it where the wasm file is located on the // default export to inform it where the wasm file is located on the
// server, and then we wait on the returned promise to wait for the // server, and then we wait on the returned promise to wait for the
// wasm to be loaded. // wasm to be loaded.
//
// It may look like this: `await init('./pkg/without_a_bundler_bg.wasm');`, // It may look like this: `await init('./pkg/without_a_bundler_bg.wasm');`,
// but there is also a handy default inside `init` function, which uses // but there is also a handy default inside `init` function, which uses
// `import.meta` to locate the wasm file relatively to js file // `import.meta` to locate the wasm file relatively to js file.
//
// Note that instead of a string you can also pass in any of the
// following things:
//
// * `WebAssembly.Module`
//
// * `ArrayBuffer`
//
// * `Response`
//
// * `Promise` which returns any of the above, e.g. `fetch("./path/to/wasm")`
//
// This gives you complete control over how the module is loaded
// and compiled.
// //
// Note that instead of a string here you can also pass in an instance
// of `WebAssembly.Module` which allows you to compile your own module.
// Also note that the promise, when resolved, yields the wasm module's // Also note that the promise, when resolved, yields the wasm module's
// exports which is the same as importing the `*_bg` module in other // exports which is the same as importing the `*_bg` module in other
// modes // modes