From 0978c3b45d6f637808c9c285921acbca15a298f7 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 11 Dec 2024 11:52:59 +0000 Subject: [PATCH] address review comments --- index-wasm-esm.mjs | 52 +++++++++++++++++++++++++++++++++++++++------- index.mjs | 11 +++++++--- package.json | 1 + 3 files changed, 54 insertions(+), 10 deletions(-) diff --git a/index-wasm-esm.mjs b/index-wasm-esm.mjs index 8015d9b00..89db51798 100644 --- a/index-wasm-esm.mjs +++ b/index-wasm-esm.mjs @@ -22,18 +22,56 @@ import * as bindings from "./pkg/matrix_sdk_crypto_wasm_bg.js"; -/** @type {typeof import("./pkg/matrix_sdk_crypto_wasm_bg.wasm.d.ts")} */ -// @ts-expect-error TSC can't find the definitions file, for some reason. -const wasm = await import("./pkg/matrix_sdk_crypto_wasm_bg.wasm"); -bindings.__wbg_set_wasm(wasm); -wasm.__wbindgen_start(); +// Although we could simply instantiate the WASM at import time with a top-level `await`, +// we avoid that, to make it easier for callers to delay loading the WASM (and instead +// wait until `initAsync` is called). (Also, Safari 14 doesn't support top-level `await`.) +// +// However, having done so, there is no way to synchronously load the WASM if the user ends +// up using the bindings before calling `initAsync` (unlike under Node.js), so we just throw +// an error. +bindings.__wbg_set_wasm( + new Proxy( + {}, + { + get() { + throw new Error( + "@matrix-org/matrix-sdk-crypto-wasm was used before it was initialized. Call `initAsync` first.", + ); + }, + }, + ), +); + +/** + * Stores a promise of the `loadModuleAsync` call + * @type {Promise | null} + */ +let modPromise = null; + +/** + * Loads and instantiates the WASM module asynchronously + * + * @returns {Promise} + */ +async function loadModuleAsync() { + /** @type {typeof import("./pkg/matrix_sdk_crypto_wasm_bg.wasm.d.ts")} */ + // @ts-expect-error TSC can't find the definitions file, for some reason. + const wasm = await import("./pkg/matrix_sdk_crypto_wasm_bg.wasm"); + bindings.__wbg_set_wasm(wasm); + wasm.__wbindgen_start(); +} /** - * A no-op, for compatibility with other entry points. + * Load the WebAssembly module in the background, if it has not already been loaded. + * + * Returns a promise which will resolve once the other methods are ready. * * @returns {Promise} */ -export async function initAsync() {} +export async function initAsync() { + if (!modPromise) modPromise = loadModuleAsync(); + await modPromise; +} // Re-export everything from the generated javascript wrappers export * from "./pkg/matrix_sdk_crypto_wasm_bg.js"; diff --git a/index.mjs b/index.mjs index be247fe7d..b792f114f 100644 --- a/index.mjs +++ b/index.mjs @@ -23,8 +23,13 @@ import * as bindings from "./pkg/matrix_sdk_crypto_wasm_bg.js"; const moduleUrl = new URL("./pkg/matrix_sdk_crypto_wasm_bg.wasm", import.meta.url); -// We want to throw an error if the user tries to use the bindings before -// calling `initAsync`. +// Although we could simply instantiate the WASM at import time with a top-level `await`, +// we avoid that, to make it easier for callers to delay loading the WASM (and instead +// wait until `initAsync` is called). (Also, Safari 14 doesn't support top-level `await`.) +// +// However, having done so, there is no way to synchronously load the WASM if the user ends +// up using the bindings before calling `initAsync` (unlike under Node.js), so we just throw +// an error. bindings.__wbg_set_wasm( new Proxy( {}, @@ -39,7 +44,7 @@ bindings.__wbg_set_wasm( ); /** - * Stores a promise of the `loadModule` call + * Stores a promise of the `loadModuleAsync` call * @type {Promise | null} */ let modPromise = null; diff --git a/package.json b/package.json index 9b2d22b98..6f602e82f 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "files": [ "index.mjs", "index.js", + "index-wasm-esm.mjs", "index.d.ts", "node.mjs", "node.js",