diff --git a/.changeset/pdfium-engine-strict-mode-guard.md b/.changeset/pdfium-engine-strict-mode-guard.md new file mode 100644 index 000000000..55c61d39f --- /dev/null +++ b/.changeset/pdfium-engine-strict-mode-guard.md @@ -0,0 +1,5 @@ +--- +'@embedpdf/engines': patch +--- + +fix(engines): `usePdfiumEngine` now discards the engine it created if the effect was torn down before init resolved, instead of committing it. This stops React Strict Mode's dev remount from creating two engines, remounting engine-keyed consumers (e.g. ``) mid-load, and leaking the first engine. Engine teardown also captures its target locally so a `wasmUrl` change mid-init can no longer destroy the replacement engine. diff --git a/packages/engines/src/shared/hooks/use-pdfium-engine.ts b/packages/engines/src/shared/hooks/use-pdfium-engine.ts index f9365c2cc..b6da16946 100644 --- a/packages/engines/src/shared/hooks/use-pdfium-engine.ts +++ b/packages/engines/src/shared/hooks/use-pdfium-engine.ts @@ -16,6 +16,12 @@ interface UsePdfiumEngineProps { fontFallback?: FontFallbackConfig | null; } +function disposeEngine(engine: PdfEngine | null) { + engine?.closeAllDocuments?.().wait(() => { + engine?.destroy?.(); + }, ignore); +} + export function usePdfiumEngine(config?: UsePdfiumEngineProps) { const { wasmUrl = defaultWasmUrl, @@ -44,6 +50,14 @@ export function usePdfiumEngine(config?: UsePdfiumEngineProps) { encoderPoolSize, fontFallback, }); + + // Effect torn down before we resolved (e.g. Strict Mode's dev + // remount): discard this engine instead of committing it. + if (cancelled) { + disposeEngine(pdfEngine); + return; + } + engineRef.current = pdfEngine; setEngine(pdfEngine); setLoading(false); @@ -57,10 +71,8 @@ export function usePdfiumEngine(config?: UsePdfiumEngineProps) { return () => { cancelled = true; - engineRef.current?.closeAllDocuments?.().wait(() => { - engineRef.current?.destroy?.(); - engineRef.current = null; - }, ignore); + disposeEngine(engineRef.current); + engineRef.current = null; }; }, [wasmUrl, worker, logger, fontFallback]);