Skip to content

Commit 68c75e5

Browse files
authored
Use asynchronous wasm instantiation methods where possible (#174)
This fixes a problem (introduced in #167) on Chrome, which would complain about the module being too big. It also significantly simplifies the code on the browser entry points, because instantiateStreaming is widely supported.
1 parent 74b73ae commit 68c75e5

File tree

5 files changed

+79
-88
lines changed

5 files changed

+79
-88
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- The WebAssembly module is now loaded using `fetch` on Web platforms, reducing
66
the bundle size significantly, as well as the time it takes to compile it.
77
([#167](https://github.com/matrix-org/matrix-rust-sdk-crypto-wasm/pull/167)),
8+
([#174](https://github.com/matrix-org/matrix-rust-sdk-crypto-wasm/pull/174)),
89
([#175](https://github.com/matrix-org/matrix-rust-sdk-crypto-wasm/pull/175))
910

1011
**BREAKING CHANGES**

index.js

+5-19
Original file line numberDiff line numberDiff line change
@@ -45,32 +45,18 @@ bindings.__wbg_set_wasm(
4545
let modPromise = null;
4646

4747
/**
48-
* Loads the WASM module asynchronously
48+
* Loads and instantiates the WASM module asynchronously
4949
*
5050
* @returns {Promise<void>}
5151
*/
52-
async function loadModule() {
53-
let mod;
54-
if (typeof WebAssembly.compileStreaming === "function") {
55-
mod = await WebAssembly.compileStreaming(fetch(moduleUrl));
56-
} else {
57-
// Fallback to fetch and compile
58-
const response = await fetch(moduleUrl);
59-
if (!response.ok) {
60-
throw new Error(`Failed to fetch wasm module: ${moduleUrl}`);
61-
}
62-
const bytes = await response.arrayBuffer();
63-
mod = await WebAssembly.compile(bytes);
64-
}
65-
66-
/** @type {{exports: typeof import("./pkg/matrix_sdk_crypto_wasm_bg.wasm.d.ts")}} */
67-
// @ts-expect-error: Typescript doesn't know what the instance exports exactly
68-
const instance = new WebAssembly.Instance(mod, {
52+
async function loadModuleAsync() {
53+
const { instance } = await WebAssembly.instantiateStreaming(fetch(moduleUrl), {
6954
// @ts-expect-error: The bindings don't exactly match the 'ExportValue' type
7055
"./matrix_sdk_crypto_wasm_bg.js": bindings,
7156
});
7257

7358
bindings.__wbg_set_wasm(instance.exports);
59+
// @ts-expect-error: Typescript doesn't know what the module exports are
7460
instance.exports.__wbindgen_start();
7561
}
7662

@@ -82,7 +68,7 @@ async function loadModule() {
8268
* @returns {Promise<void>}
8369
*/
8470
async function initAsync() {
85-
if (!modPromise) modPromise = loadModule();
71+
if (!modPromise) modPromise = loadModuleAsync();
8672
await modPromise;
8773
}
8874

index.mjs

+5-19
Original file line numberDiff line numberDiff line change
@@ -45,32 +45,18 @@ bindings.__wbg_set_wasm(
4545
let modPromise = null;
4646

4747
/**
48-
* Loads the WASM module asynchronously
48+
* Loads and instantiates the WASM module asynchronously
4949
*
5050
* @returns {Promise<void>}
5151
*/
52-
async function loadModule() {
53-
let mod;
54-
if (typeof WebAssembly.compileStreaming === "function") {
55-
mod = await WebAssembly.compileStreaming(fetch(moduleUrl));
56-
} else {
57-
// Fallback to fetch and compile
58-
const response = await fetch(moduleUrl);
59-
if (!response.ok) {
60-
throw new Error(`Failed to fetch wasm module: ${moduleUrl}`);
61-
}
62-
const bytes = await response.arrayBuffer();
63-
mod = await WebAssembly.compile(bytes);
64-
}
65-
66-
/** @type {{exports: typeof import("./pkg/matrix_sdk_crypto_wasm_bg.wasm.d.ts")}} */
67-
// @ts-expect-error: Typescript doesn't know what the instance exports exactly
68-
const instance = new WebAssembly.Instance(mod, {
52+
async function loadModuleAsync() {
53+
const { instance } = await WebAssembly.instantiateStreaming(fetch(moduleUrl), {
6954
// @ts-expect-error: The bindings don't exactly match the 'ExportValue' type
7055
"./matrix_sdk_crypto_wasm_bg.js": bindings,
7156
});
7257

7358
bindings.__wbg_set_wasm(instance.exports);
59+
// @ts-expect-error: Typescript doesn't know what the module exports are
7460
instance.exports.__wbindgen_start();
7561
}
7662

@@ -82,7 +68,7 @@ async function loadModule() {
8268
* @returns {Promise<void>}
8369
*/
8470
export async function initAsync() {
85-
if (!modPromise) modPromise = loadModule();
71+
if (!modPromise) modPromise = loadModuleAsync();
8672
await modPromise;
8773
}
8874

node.js

+34-25
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ bindings.__wbg_set_wasm(
3434
{},
3535
{
3636
get(_target, prop) {
37-
const mod = loadModuleSync();
38-
// @ts-expect-error: This results to an `any` type, which is fine
39-
return initInstance(mod)[prop];
37+
const instance = loadModuleSync();
38+
// @ts-expect-error: This results in an `any` type, which is fine
39+
return instance[prop];
4040
},
4141
},
4242
),
@@ -55,48 +55,57 @@ let modPromise = null;
5555
let initialised = false;
5656

5757
/**
58-
* Loads the WASM module synchronously
58+
* Loads and instantiates the WASM module synchronously
5959
*
60-
* It will throw if there is an attempt to laod the module asynchronously running
60+
* It will throw if there is an attempt to load the module asynchronously running
6161
*
62-
* @returns {WebAssembly.Module}
62+
* @returns {typeof import("./pkg/matrix_sdk_crypto_wasm_bg.wasm.d")}
6363
*/
6464
function loadModuleSync() {
65-
if (modPromise) throw new Error("The WASM module is being loadded asynchronously but hasn't finished");
65+
if (modPromise) throw new Error("The WASM module is being loaded asynchronously but hasn't finished");
6666
const bytes = readFileSync(filename);
67-
return new WebAssembly.Module(bytes);
67+
const mod = new WebAssembly.Module(bytes);
68+
69+
const instance = new WebAssembly.Instance(mod, {
70+
// @ts-expect-error: The bindings don't exactly match the 'ExportValue' type
71+
"./matrix_sdk_crypto_wasm_bg.js": bindings,
72+
});
73+
74+
initInstance(instance);
75+
76+
// @ts-expect-error: Typescript doesn't know what the instance exports exactly
77+
return instance.exports;
6878
}
6979

7080
/**
71-
* Loads the WASM module asynchronously
81+
* Loads and instantiates the WASM module asynchronously
7282
*
73-
* @returns {Promise<WebAssembly.Module>}
83+
* @returns {Promise<typeof import("./pkg/matrix_sdk_crypto_wasm_bg.wasm.d")>}
7484
*/
75-
async function loadModule() {
85+
async function loadModuleAsync() {
7686
const bytes = await readFile(filename);
77-
return await WebAssembly.compile(bytes);
87+
const { instance } = await WebAssembly.instantiate(bytes, {
88+
// @ts-expect-error: The bindings don't exactly match the 'ExportValue' type
89+
"./matrix_sdk_crypto_wasm_bg.js": bindings,
90+
});
91+
92+
initInstance(instance);
93+
94+
// @ts-expect-error: Typescript doesn't know what the instance exports exactly
95+
return instance.exports;
7896
}
7997

8098
/**
8199
* Initializes the WASM module and returns the exports from the WASM module.
82100
*
83-
* @param {WebAssembly.Module} mod
84-
* @returns {typeof import("./pkg/matrix_sdk_crypto_wasm_bg.wasm.d")}
101+
* @param {WebAssembly.Instance} instance
85102
*/
86-
function initInstance(mod) {
103+
function initInstance(instance) {
87104
if (initialised) throw new Error("initInstance called twice");
88-
89-
/** @type {{exports: typeof import("./pkg/matrix_sdk_crypto_wasm_bg.wasm.d.ts")}} */
90-
// @ts-expect-error: Typescript doesn't know what the instance exports exactly
91-
const instance = new WebAssembly.Instance(mod, {
92-
// @ts-expect-error: The bindings don't exactly match the 'ExportValue' type
93-
"./matrix_sdk_crypto_wasm_bg.js": bindings,
94-
});
95-
96105
bindings.__wbg_set_wasm(instance.exports);
106+
// @ts-expect-error: Typescript doesn't know what the instance exports exactly
97107
instance.exports.__wbindgen_start();
98108
initialised = true;
99-
return instance.exports;
100109
}
101110

102111
/**
@@ -108,7 +117,7 @@ function initInstance(mod) {
108117
*/
109118
async function initAsync() {
110119
if (initialised) return;
111-
if (!modPromise) modPromise = loadModule().then(initInstance);
120+
if (!modPromise) modPromise = loadModuleAsync();
112121
await modPromise;
113122
}
114123

node.mjs

+34-25
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ bindings.__wbg_set_wasm(
3434
{},
3535
{
3636
get(_target, prop) {
37-
const mod = loadModuleSync();
38-
// @ts-expect-error: This results to an `any` type, which is fine
39-
return initInstance(mod)[prop];
37+
const instance = loadModuleSync();
38+
// @ts-expect-error: This results in an `any` type, which is fine
39+
return instance[prop];
4040
},
4141
},
4242
),
@@ -55,48 +55,57 @@ let modPromise = null;
5555
let initialised = false;
5656

5757
/**
58-
* Loads the WASM module synchronously
58+
* Loads and instantiates the WASM module synchronously
5959
*
60-
* It will throw if there is an attempt to laod the module asynchronously running
60+
* It will throw if there is an attempt to load the module asynchronously running
6161
*
62-
* @returns {WebAssembly.Module}
62+
* @returns {typeof import("./pkg/matrix_sdk_crypto_wasm_bg.wasm.d.ts")}
6363
*/
6464
function loadModuleSync() {
65-
if (modPromise) throw new Error("The WASM module is being loadded asynchronously but hasn't finished");
65+
if (modPromise) throw new Error("The WASM module is being loaded asynchronously but hasn't finished");
6666
const bytes = readFileSync(filename);
67-
return new WebAssembly.Module(bytes);
67+
const mod = new WebAssembly.Module(bytes);
68+
69+
const instance = new WebAssembly.Instance(mod, {
70+
// @ts-expect-error: The bindings don't exactly match the 'ExportValue' type
71+
"./matrix_sdk_crypto_wasm_bg.js": bindings,
72+
});
73+
74+
initInstance(instance);
75+
76+
// @ts-expect-error: Typescript doesn't know what the module exports are
77+
return instance.exports;
6878
}
6979

7080
/**
71-
* Loads the WASM module asynchronously
81+
* Loads and instantiates the WASM module asynchronously
7282
*
73-
* @returns {Promise<WebAssembly.Module>}
83+
* @returns {Promise<typeof import("./pkg/matrix_sdk_crypto_wasm_bg.wasm.d.ts")>}
7484
*/
75-
async function loadModule() {
85+
async function loadModuleAsync() {
7686
const bytes = await readFile(filename);
77-
return await WebAssembly.compile(bytes);
87+
const { instance } = await WebAssembly.instantiate(bytes, {
88+
// @ts-expect-error: The bindings don't exactly match the 'ExportValue' type
89+
"./matrix_sdk_crypto_wasm_bg.js": bindings,
90+
});
91+
92+
initInstance(instance);
93+
94+
// @ts-expect-error: Typescript doesn't know what the module exports are
95+
return instance.exports;
7896
}
7997

8098
/**
8199
* Initializes the WASM module and returns the exports from the WASM module.
82100
*
83-
* @param {WebAssembly.Module} mod
84-
* @returns {typeof import("./pkg/matrix_sdk_crypto_wasm_bg.wasm.d.ts")}
101+
* @param {WebAssembly.Instance} instance
85102
*/
86-
function initInstance(mod) {
103+
function initInstance(instance) {
87104
if (initialised) throw new Error("initInstance called twice");
88-
89-
/** @type {{exports: typeof import("./pkg/matrix_sdk_crypto_wasm_bg.wasm.d.ts")}} */
90-
// @ts-expect-error: Typescript doesn't know what the instance exports exactly
91-
const instance = new WebAssembly.Instance(mod, {
92-
// @ts-expect-error: The bindings don't exactly match the 'ExportValue' type
93-
"./matrix_sdk_crypto_wasm_bg.js": bindings,
94-
});
95-
96105
bindings.__wbg_set_wasm(instance.exports);
106+
// @ts-expect-error: Typescript doesn't know what the module exports are
97107
instance.exports.__wbindgen_start();
98108
initialised = true;
99-
return instance.exports;
100109
}
101110

102111
/**
@@ -108,7 +117,7 @@ function initInstance(mod) {
108117
*/
109118
export async function initAsync() {
110119
if (initialised) return;
111-
if (!modPromise) modPromise = loadModule().then(initInstance);
120+
if (!modPromise) modPromise = loadModuleAsync();
112121
await modPromise;
113122
}
114123

0 commit comments

Comments
 (0)