Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improving wasm loading logic #1996

Merged
merged 2 commits into from
Feb 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 50 additions & 46 deletions crates/cli-support/src/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,20 +433,20 @@ impl<'a> Context<'a> {
let default_module_path = match self.config.mode {
OutputMode::Web => {
"\
if (typeof module === 'undefined') {
module = import.meta.url.replace(/\\.js$/, '_bg.wasm');
if (typeof input === 'undefined') {
input = import.meta.url.replace(/\\.js$/, '_bg.wasm');
}"
}
OutputMode::NoModules { .. } => {
"\
if (typeof module === 'undefined') {
if (typeof input === 'undefined') {
let src;
if (self.document === undefined) {
src = self.location.href;
} else {
src = self.document.currentScript.src;
}
module = src.replace(/\\.js$/, '_bg.wasm');
input = src.replace(/\\.js$/, '_bg.wasm');
}"
}
_ => "",
Expand Down Expand Up @@ -503,54 +503,58 @@ impl<'a> Context<'a> {

let js = format!(
"\
function init(module{init_memory_arg}) {{
{default_module_path}
let result;
const imports = {{}};
{imports_init}
if ((typeof URL === 'function' && module instanceof URL) || typeof module === 'string' || (typeof Request === 'function' && module instanceof Request)) {{
async function load(module, imports) {{
if (typeof Response === 'function' && module instanceof Response) {{
{init_memory2}
const response = fetch(module);
if (typeof WebAssembly.instantiateStreaming === 'function') {{
result = WebAssembly.instantiateStreaming(response, imports)
.catch(e => {{
return response
.then(r => {{
if (r.headers.get('Content-Type') != 'application/wasm') {{
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 r.arrayBuffer();
}} else {{
throw e;
}}
}})
.then(bytes => WebAssembly.instantiate(bytes, imports));
}});
}} else {{
result = response
.then(r => r.arrayBuffer())
.then(bytes => WebAssembly.instantiate(bytes, imports));
try {{
return await WebAssembly.instantiateStreaming(module, imports);

}} catch (e) {{
if (module.headers.get('Content-Type') != 'application/wasm') {{
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);

}} else {{
throw e;
}}
}}
}}

const bytes = await module.arrayBuffer();
return await WebAssembly.instantiate(bytes, imports);

}} else {{
{init_memory1}
result = WebAssembly.instantiate(module, imports)
.then(result => {{
if (result instanceof WebAssembly.Instance) {{
return {{ instance: result, module }};
}} else {{
return result;
}}
}});
const instance = await WebAssembly.instantiate(module, imports);

if (instance instanceof WebAssembly.Instance) {{
return {{ instance, module }};

}} else {{
return instance;
}}
}}
return result.then(({{instance, module}}) => {{
wasm = instance.exports;
init.__wbindgen_wasm_module = module;
{start}
return wasm;
}});
}}

async function init(input{init_memory_arg}) {{
{default_module_path}
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,
Expand Down
19 changes: 16 additions & 3 deletions examples/without-a-bundler/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,25 @@
// 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
// wasm to be loaded.
//
// 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
// `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
// exports which is the same as importing the `*_bg` module in other
// modes
Expand Down