fix: use static import + initSync for WASM in service worker
Chrome MV3 service workers do not support dynamic import(). Switch to static import of the wasm-pack JS glue and use initSync() with fetch() to load the WASM binary at runtime. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -21,27 +21,30 @@ const totpSecretCache: Map<string, string> = new Map();
|
|||||||
|
|
||||||
// --- WASM initialization ---
|
// --- WASM initialization ---
|
||||||
|
|
||||||
// We use a dynamic import so webpack treats idfoto_wasm.js as a separate chunk.
|
// Chrome MV3 service workers do NOT support dynamic import().
|
||||||
// The WASM file (idfoto_wasm_bg.wasm) is loaded by the JS glue code.
|
// Instead we load the WASM binary via fetch() and use the synchronous
|
||||||
type WasmModule = typeof import('idfoto-wasm');
|
// initSync() function exported by wasm-pack's --target web output.
|
||||||
|
// The JS glue is imported statically so webpack bundles it into
|
||||||
|
// the service worker script.
|
||||||
|
|
||||||
|
// @ts-ignore TS2307 — resolved by webpack alias / copy
|
||||||
|
import initSync, * as wasmBindings from '../../wasm/idfoto_wasm.js';
|
||||||
|
|
||||||
|
type WasmModule = typeof wasmBindings;
|
||||||
let wasm: WasmModule | null = null;
|
let wasm: WasmModule | null = null;
|
||||||
|
|
||||||
async function initWasm(): Promise<WasmModule> {
|
async function initWasm(): Promise<WasmModule> {
|
||||||
if (wasm) return wasm;
|
if (wasm) return wasm;
|
||||||
|
|
||||||
// wasm-pack --target web produces an ES module with an `default` init function
|
// Fetch the .wasm binary and instantiate synchronously
|
||||||
// that loads the .wasm file. In a Chrome MV3 service worker we import the JS
|
const wasmResponse = await fetch(chrome.runtime.getURL('idfoto_wasm_bg.wasm'));
|
||||||
// glue and call init() with the wasm URL.
|
const wasmBytes = await wasmResponse.arrayBuffer();
|
||||||
const mod = await import(
|
initSync({ module: new WebAssembly.Module(wasmBytes) });
|
||||||
// @ts-ignore TS2307 — resolved at runtime by the service worker, not by TS/webpack
|
|
||||||
/* webpackIgnore: true */ './idfoto_wasm.js'
|
|
||||||
) as WasmModule & { default: (input?: string | URL) => Promise<void> };
|
|
||||||
|
|
||||||
await mod.default('./idfoto_wasm_bg.wasm');
|
vault.setWasm(wasmBindings);
|
||||||
vault.setWasm(mod);
|
wasm = wasmBindings;
|
||||||
wasm = mod;
|
|
||||||
wasmReady = true;
|
wasmReady = true;
|
||||||
return mod;
|
return wasm;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Storage helpers ---
|
// --- Storage helpers ---
|
||||||
|
|||||||
@@ -8,14 +8,16 @@ import type { GitHost } from './git-host';
|
|||||||
import type { Entry, Manifest, ManifestEntry } from '../shared/types';
|
import type { Entry, Manifest, ManifestEntry } from '../shared/types';
|
||||||
|
|
||||||
// WASM module reference — set once during init.
|
// WASM module reference — set once during init.
|
||||||
let wasm: typeof import('idfoto-wasm') | null = null;
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
let wasm: any = null;
|
||||||
|
|
||||||
/// Store the WASM module reference after dynamic import.
|
/// Store the WASM module reference after initialization.
|
||||||
export function setWasm(w: typeof import('idfoto-wasm')): void {
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
export function setWasm(w: any): void {
|
||||||
wasm = w;
|
wasm = w;
|
||||||
}
|
}
|
||||||
|
|
||||||
function requireWasm(): NonNullable<typeof wasm> {
|
function requireWasm(): any {
|
||||||
if (!wasm) throw new Error('WASM module not initialized');
|
if (!wasm) throw new Error('WASM module not initialized');
|
||||||
return wasm;
|
return wasm;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user