From ca6f2b7cc47641cecfbd35ebfc521ec077af1e1f Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Fri, 9 Oct 2026 19:41:19 +0400 Subject: [PATCH] =?UTF-8?q?fix(web):=20legacy-=D1=81=D0=B1=D0=BE=D1=80?= =?UTF-8?q?=D0=BA=D0=B0=20pdf.js=20=E2=80=94=20=C2=AB=D0=9D=D0=B5=20=D1=83?= =?UTF-8?q?=D0=B4=D0=B0=D0=BB=D0=BE=D1=81=D1=8C=20=D0=BE=D1=82=D0=BA=D1=80?= =?UTF-8?q?=D1=8B=D1=82=D1=8C=20PDF=C2=BB=20=D0=B2=20=D0=AF=D0=BD=D0=B4?= =?UTF-8?q?=D0=B5=D0=BA=D1=81=20=D0=91=D1=80=D0=B0=D1=83=D0=B7=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=20(#90)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Копия исправления arm-web #22 (контур разворачивается из web/). Обычная сборка pdfjs-dist 5.7 в воркере вызывает Uint8Array.prototype.toHex (Chromium 140+), в Яндекс Браузере getDocument падает «a.toHex is not a function». PdfPages берёт модуль и воркер из pdfjs-dist/legacy/build через widgets/DocumentReview/pdfjs.ts; регрессионный тест открывает PDF без Uint8Array.prototype.toHex. Co-Authored-By: Claude Fable 5.1 --- web/src/widgets/DocumentReview/PdfPages.tsx | 6 +-- web/src/widgets/DocumentReview/pdfjs.test.ts | 54 ++++++++++++++++++++ web/src/widgets/DocumentReview/pdfjs.ts | 8 +++ 3 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 web/src/widgets/DocumentReview/pdfjs.test.ts create mode 100644 web/src/widgets/DocumentReview/pdfjs.ts diff --git a/web/src/widgets/DocumentReview/PdfPages.tsx b/web/src/widgets/DocumentReview/PdfPages.tsx index b645c0d..12cb4e7 100644 --- a/web/src/widgets/DocumentReview/PdfPages.tsx +++ b/web/src/widgets/DocumentReview/PdfPages.tsx @@ -1,10 +1,6 @@ -import * as pdfjsLib from 'pdfjs-dist'; - import type { PDFDocumentProxy, RenderTask } from 'pdfjs-dist'; import { useCallback, useEffect, useRef, useState } from 'react'; - -// worker собирается вместе с приложением (без CDN) -pdfjsLib.GlobalWorkerOptions.workerSrc = new URL('pdfjs-dist/build/pdf.worker.min.mjs', import.meta.url).toString(); +import { pdfjsLib } from './pdfjs'; export const MIN_ZOOM = 0.5; export const MAX_ZOOM = 3; diff --git a/web/src/widgets/DocumentReview/pdfjs.test.ts b/web/src/widgets/DocumentReview/pdfjs.test.ts new file mode 100644 index 0000000..86339c1 --- /dev/null +++ b/web/src/widgets/DocumentReview/pdfjs.test.ts @@ -0,0 +1,54 @@ +import { afterEach, describe, expect, it } from 'vitest'; + +// под vitest `new URL(<пакет>, import.meta.url)` из pdfjs.ts не резолвится сборщиком — воркер берём по пути от корня проекта +const WORKER = new URL('../../../node_modules/pdfjs-dist/legacy/build/pdf.worker.min.mjs', import.meta.url).href; + +/** Минимальный PDF из одной страницы с корректной таблицей xref. */ +function minimalPdf(): Uint8Array { + const objects = [ + '<< /Type /Catalog /Pages 2 0 R >>', + '<< /Type /Pages /Kids [3 0 R] /Count 1 >>', + '<< /Type /Page /Parent 2 0 R /MediaBox [0 0 200 100] >>', + ]; + let body = '%PDF-1.4\n'; + const offsets: number[] = []; + objects.forEach((obj, i) => { + offsets.push(body.length); + body += `${i + 1} 0 obj\n${obj}\nendobj\n`; + }); + const xref = body.length; + body += `xref\n0 ${objects.length + 1}\n0000000000 65535 f \n`; + for (const o of offsets) { + body += `${String(o).padStart(10, '0')} 00000 n \n`; + } + body += `trailer\n<< /Size ${objects.length + 1} /Root 1 0 R >>\nstartxref\n${xref}\n%%EOF\n`; + return new TextEncoder().encode(body); +} + +type ToHexProto = { toHex?: unknown }; +const proto = Uint8Array.prototype as ToHexProto; +const nativeToHex = proto.toHex; + +afterEach(() => { + if (nativeToHex === undefined) { + delete proto.toHex; + } else { + proto.toHex = nativeToHex; + } +}); + +describe('pdfjs (сборка для браузеров без Uint8Array.prototype.toHex)', () => { + // Яндекс Браузер (ядро Chromium < 140) не имеет Uint8Array.prototype.toHex; обычная сборка pdf.js 5.x вызывает его + // при открытии документа (отпечаток) и падает «a.toHex is not a function». Legacy-сборка несёт полифилл. + it('открывает PDF, когда Uint8Array.prototype.toHex отсутствует', async () => { + delete proto.toHex; + const { pdfjsLib } = await import('./pdfjs'); + pdfjsLib.GlobalWorkerOptions.workerSrc = WORKER; + const doc = await pdfjsLib.getDocument({ data: minimalPdf() }).promise; + try { + expect(doc.numPages).toBe(1); + } finally { + await doc.destroy(); + } + }); +}); diff --git a/web/src/widgets/DocumentReview/pdfjs.ts b/web/src/widgets/DocumentReview/pdfjs.ts new file mode 100644 index 0000000..d236f17 --- /dev/null +++ b/web/src/widgets/DocumentReview/pdfjs.ts @@ -0,0 +1,8 @@ +// Legacy-сборка pdf.js: несёт полифиллы (в т. ч. Uint8Array.prototype.toHex, Chromium 140+), без которых обычная +// сборка падает при открытии документа в Яндекс Браузере — «a.toHex is not a function» (arm-web #22). Воркер — та же +// сборка, собирается вместе с приложением (без CDN). +import * as pdfjsLib from 'pdfjs-dist/legacy/build/pdf.mjs'; + +pdfjsLib.GlobalWorkerOptions.workerSrc = new URL('pdfjs-dist/legacy/build/pdf.worker.min.mjs', import.meta.url).toString(); + +export { pdfjsLib };