fix(file-viewer): keep rendering a PDF after a file-watcher reload
Nightly Build / build (push) Successful in 8m13s
Nightly Build / build (push) Successful in 8m13s
An open PDF went blank the moment the watcher reported the file had changed, and stayed blank for the rest of the session — every later version of the file too. <pdf-view>._teardown() released the previous document with PDFDocumentProxy.destroy(), a method pdf.js no longer has: a document is torn down through its loading task. The absent method threw a TypeError, and _teardown() is the *first* statement of _open(): the page list had already been emptied, so nothing after the throw ran — no new document was loaded, and the emptied .pdfv-pages had nothing to refill it. Since _doc was never cleared either, every subsequent src hit the same throw, which is why the viewer never recovered. _open() is async and its caller (updated()) does not await it, so the TypeError surfaced only as an unhandled rejection. Tear the document down through doc.loadingTask.destroy() instead, and swallow its failure: releasing the previous document must never be able to stop the next one from loading. The same call in _open()'s stale-document path had the identical bug. Verified in headless Chromium against the real component: swapping the blob URL the way FileViewerBase._load does now reloads the document (5 pages -> 7 -> 5, correct text layer, no exceptions), including three reloads fired back-to-back so the stale-document path is exercised.
This commit is contained in:
@@ -62,6 +62,23 @@ const MAX_DPR = 2;
|
||||
|
||||
let _pdfjsPromise = null;
|
||||
|
||||
/**
|
||||
* Tear a document down. pdf.js dropped `PDFDocumentProxy.destroy()` — the
|
||||
* document is released through its loading task — and calling the absent method
|
||||
* threw a TypeError out of `_teardown()`, which is called *first* in `_open()`:
|
||||
* the page list had already been emptied, the rest of `_open()` never ran, and
|
||||
* the viewer stayed blank for the rest of its life (every later src hit the same
|
||||
* throw). That is what a file-watcher reload of an open PDF looked like. Hence
|
||||
* also the swallow: releasing the previous document must never be able to stop
|
||||
* the next one from loading.
|
||||
*/
|
||||
function destroyDoc(doc) {
|
||||
try {
|
||||
const p = doc?.loadingTask?.destroy();
|
||||
if (p?.catch) p.catch(() => { /* already gone */ });
|
||||
} catch { /* already gone */ }
|
||||
}
|
||||
|
||||
/** Import pdf.js once per page load and point it at the vendored worker. */
|
||||
function loadPdfjs() {
|
||||
if (!_pdfjsPromise) {
|
||||
@@ -131,7 +148,7 @@ export class PdfView extends LightElement {
|
||||
standardFontDataUrl: STD_FONTS_URL,
|
||||
}).promise;
|
||||
// A newer src landed while we were loading — drop this one on the floor.
|
||||
if (seq !== this._loadSeq) { doc.destroy(); return; }
|
||||
if (seq !== this._loadSeq) { destroyDoc(doc); return; }
|
||||
this._pdfjs = pdfjs;
|
||||
this._doc = doc;
|
||||
this._total = doc.numPages;
|
||||
@@ -186,8 +203,9 @@ export class PdfView extends LightElement {
|
||||
for (const slot of this._slots) this._release(slot);
|
||||
this._slots = [];
|
||||
this.querySelector('.pdfv-pages')?.replaceChildren();
|
||||
this._doc?.destroy();
|
||||
const doc = this._doc;
|
||||
this._doc = null;
|
||||
destroyDoc(doc);
|
||||
this._lastWidth = 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user