1717
1818// Resolved pdfjs URL — computed once from main thread's module resolution
1919
20- let _pdfjsUrl : string | null = null
20+ let _pdfjsUrls : { library : string ; worker : string } | null = null
2121
22- function getPdfjsUrl ( ) : string | null {
23- if ( _pdfjsUrl !== null ) return _pdfjsUrl
22+ function getPdfjsUrls ( ) : { library : string ; worker : string } | null {
23+ if ( _pdfjsUrls !== null ) return _pdfjsUrls
2424 try {
25- // Resolve via the bundler/dev server so the URL is usable from a Worker
26- _pdfjsUrl = new URL ( 'pdfjs-dist/build/pdf.min.mjs' , import . meta. url ) . toString ( )
25+ const library = new URL ( 'pdfjs-dist/build/pdf.min.mjs' , import . meta. url ) . toString ( )
26+ const worker = new URL ( 'pdfjs-dist/build/pdf.worker.min.mjs' , import . meta. url ) . toString ( )
27+ /** Bundlers can emit root-relative asset URLs, which cannot resolve inside a blob worker. */
28+ _pdfjsUrls = {
29+ library : new URL ( library , window . location . href ) . href ,
30+ worker : new URL ( worker , window . location . href ) . href ,
31+ }
2732 } catch {
28- _pdfjsUrl = ''
33+ return null
2934 }
30- return _pdfjsUrl || null
35+ return _pdfjsUrls
3136}
3237
3338// Worker-based renderer (fully isolated from main thread pdfjs)
3439
3540/**
3641 * Inline source for the PDF render worker.
37- * Receives: { id, pdfData, width, height, pdfjsUrl }
42+ * Receives: { id, pdfData, width, height, pdfjsUrl, pdfjsWorkerUrl }
3843 * Posts back: { id, blob } or { id, error }
3944 *
4045 * The worker loads its OWN pdfjs instance via dynamic import, so its static
4146 * PagesMapper state is completely independent of the main thread.
42- * pdfjs's own internal worker is disabled (workerPort = null, workerSrc = '')
43- * so pdfjs runs single-threaded inside this worker — acceptable for tiny
44- * 1-page EMF PDFs .
47+ * Loading the matching worker module installs its WorkerMessageHandler in
48+ * this isolated global scope. PDF.js then uses its in-context worker fallback
49+ * without creating another worker or changing the host app's configuration .
4550 */
4651const WORKER_SRC = /* js */ `
4752let pdfjsLib = null;
4853
4954self.onmessage = async (e) => {
50- const { id, pdfData, width, height, pdfjsUrl } = e.data;
55+ const { id, pdfData, width, height, pdfjsUrl, pdfjsWorkerUrl } = e.data;
5156 try {
5257 if (!pdfjsLib) {
58+ await import(pdfjsWorkerUrl);
5359 pdfjsLib = await import(pdfjsUrl);
54- pdfjsLib.GlobalWorkerOptions.workerSrc = '';
5560 }
5661
5762 const doc = await pdfjsLib.getDocument({ data: pdfData }).promise;
@@ -88,7 +93,7 @@ const _pending = new Map<
8893 { resolve : ( b : Blob | null ) => void ; reject : ( e : Error ) => void }
8994> ( )
9095
91- function getWorker ( _pdfjsUrl : string ) : Worker | null {
96+ function getWorker ( ) : Worker | null {
9297 if ( _workerFailed ) return null
9398 if ( _worker ) return _worker
9499
@@ -130,10 +135,10 @@ function renderInWorker(
130135 pdfData : Uint8Array ,
131136 width : number ,
132137 height : number ,
133- pdfjsUrl : string
138+ pdfjsUrls : { library : string ; worker : string }
134139) : Promise < Blob | null > {
135140 return new Promise ( ( resolve ) => {
136- const worker = getWorker ( pdfjsUrl )
141+ const worker = getWorker ( )
137142 if ( ! worker ) {
138143 resolve ( null )
139144 return
@@ -147,7 +152,17 @@ function renderInWorker(
147152
148153 // Transfer the buffer to avoid copying
149154 const copy = pdfData . slice ( ) // copy so caller retains original
150- worker . postMessage ( { id, pdfData : copy , width, height, pdfjsUrl } , [ copy . buffer ] )
155+ worker . postMessage (
156+ {
157+ id,
158+ pdfData : copy ,
159+ width,
160+ height,
161+ pdfjsUrl : pdfjsUrls . library ,
162+ pdfjsWorkerUrl : pdfjsUrls . worker ,
163+ } ,
164+ [ copy . buffer ]
165+ )
151166
152167 // Timeout: if worker doesn't respond in 15s, give up
153168 setTimeout ( ( ) => {
@@ -175,14 +190,14 @@ export async function renderPdfToImage(
175190 width : number ,
176191 height : number
177192) : Promise < string | null > {
178- const pdfjsUrl = getPdfjsUrl ( )
193+ const pdfjsUrls = getPdfjsUrls ( )
179194
180- if ( ! pdfjsUrl || typeof OffscreenCanvas === 'undefined' || typeof Worker === 'undefined' ) {
195+ if ( ! pdfjsUrls || typeof OffscreenCanvas === 'undefined' || typeof Worker === 'undefined' ) {
181196 return null
182197 }
183198
184199 try {
185- const blob = await renderInWorker ( pdfData , width , height , pdfjsUrl )
200+ const blob = await renderInWorker ( pdfData , width , height , pdfjsUrls )
186201 if ( blob ) return URL . createObjectURL ( blob )
187202 } catch {
188203 // Worker failed — no fallback, return null
0 commit comments