Ensure we await for the wasm module to load (#11995)

Webpack seems to always convert imports to be async. This causes a issue where
init_sdk is not always initialized before we call it. To resolve this I added
a promise we can await in MV3 mode, and also defined a timeout which throws an
error we can use to identify if we have issues loading the module.
This commit is contained in:
Oscar Hinton 2024-11-14 17:29:56 +01:00 committed by GitHub
parent 5da5c886ea
commit ef127fd26e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 31 additions and 3 deletions

View File

@ -20,22 +20,28 @@ const supported = (() => {
return false;
})();
// Due to using webpack as bundler, sync imports will return an async module. Since we do support
// top level awaits, we define a promise we can await in the `load` function.
let loadingPromise: Promise<any> | undefined;
// Manifest v3 does not support dynamic imports in the service worker.
if (BrowserApi.isManifestVersion(3)) {
if (supported) {
// eslint-disable-next-line no-console
console.debug("WebAssembly is supported in this environment");
import("./wasm");
loadingPromise = import("./wasm");
} else {
// eslint-disable-next-line no-console
console.debug("WebAssembly is not supported in this environment");
import("./fallback");
loadingPromise = import("./fallback");
}
}
// Manifest v2 expects dynamic imports to prevent timing issues.
async function load() {
if (BrowserApi.isManifestVersion(3)) {
// Ensure we have loaded the module
await loadingPromise;
return;
}
@ -59,8 +65,30 @@ export class BrowserSdkClientFactory implements SdkClientFactory {
async createSdkClient(
...args: ConstructorParameters<typeof BitwardenClient>
): Promise<BitwardenClient> {
await load();
try {
await loadWithTimeout();
} catch (error) {
throw new Error(`Failed to load: ${error.message}`);
}
return Promise.resolve((globalThis as any).init_sdk(...args));
}
}
const loadWithTimeout = async () => {
return new Promise<void>((resolve, reject) => {
const timer = setTimeout(() => {
reject(new Error("Operation timed out after 1 second"));
}, 1000);
load()
.then(() => {
clearTimeout(timer);
resolve();
})
.catch((error) => {
clearTimeout(timer);
reject(error);
});
});
};