refactor(pdf): centralize pdf.js runtime configuration and asset resolution
Move pdf.js worker and standard font resolution logic into dedicated utility functions for improved maintainability and clarity. Replace inline workerSrc setup with a reusable configurePdfjsNodeRuntime helper. Update Next.js config to use a shared asset trace list for pdf.js runtime files, reducing duplication and simplifying future updates.
This commit is contained in:
parent
2f99b3987e
commit
0e29450b0d
4 changed files with 60 additions and 26 deletions
|
|
@ -3,7 +3,7 @@ import type { ParsedPdfDocument, ParsedPdfPage } from '../types/parsed-pdf';
|
|||
import { ensureModel } from './model';
|
||||
import { runLayoutModel } from './runLayoutModel';
|
||||
import { mergeTextWithRegions } from './merge';
|
||||
import { resolvePdfjsStandardFontDataUrl } from './pdfjs-runtime';
|
||||
import { configurePdfjsNodeRuntime, resolvePdfjsStandardFontDataUrl } from './pdfjs-runtime';
|
||||
import { PDF_PARSER_VERSION } from './parser-version';
|
||||
import { stitchCrossPageBlocks } from './stitch';
|
||||
import { renderPage } from './render';
|
||||
|
|
@ -36,10 +36,7 @@ export async function parsePdf(input: ParsePdfInput): Promise<ParsedPdfDocument>
|
|||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
const pdfjs = await import('pdfjs-dist/legacy/build/pdf.mjs');
|
||||
if (pdfjs.GlobalWorkerOptions) {
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = 'pdfjs-dist/legacy/build/pdf.worker.mjs';
|
||||
pdfjs.GlobalWorkerOptions.workerPort = null;
|
||||
}
|
||||
configurePdfjsNodeRuntime(pdfjs);
|
||||
const standardFontDataUrl = resolvePdfjsStandardFontDataUrl();
|
||||
|
||||
const loadingTask = pdfjs.getDocument({
|
||||
|
|
|
|||
|
|
@ -1,14 +1,39 @@
|
|||
import fs from 'node:fs';
|
||||
import { createRequire } from 'node:module';
|
||||
import path from 'node:path';
|
||||
import { pathToFileURL } from 'node:url';
|
||||
|
||||
let cachedStandardFontDataUrl: string | null = null;
|
||||
const require = createRequire(import.meta.url);
|
||||
const pdfjsPackageName = 'pdfjs-dist';
|
||||
|
||||
function candidatePackageRoots(): string[] {
|
||||
const roots = new Set<string>();
|
||||
let dir = process.cwd();
|
||||
|
||||
for (let i = 0; i < 8; i += 1) {
|
||||
roots.add(path.join(dir, 'node_modules', pdfjsPackageName));
|
||||
const next = path.dirname(dir);
|
||||
if (next === dir) break;
|
||||
dir = next;
|
||||
}
|
||||
|
||||
return [...roots];
|
||||
}
|
||||
|
||||
function resolvePdfjsPackageFile(relativePath: string): string {
|
||||
const normalizedRelativePath = relativePath.replace(/^\/+/, '');
|
||||
const candidates = candidatePackageRoots().map((root) => path.join(root, normalizedRelativePath));
|
||||
const found = candidates.find((candidate) => fs.existsSync(candidate));
|
||||
if (found) return found;
|
||||
|
||||
throw new Error(
|
||||
`pdfjs-dist file not found: ${normalizedRelativePath}; checked ${candidates.join(', ')}`,
|
||||
);
|
||||
}
|
||||
|
||||
export function resolvePdfjsStandardFontDataUrl(): string {
|
||||
if (cachedStandardFontDataUrl) return cachedStandardFontDataUrl;
|
||||
|
||||
const pdfjsPackageDir = path.dirname(require.resolve('pdfjs-dist/package.json'));
|
||||
const pdfjsPackageDir = path.dirname(resolvePdfjsPackageFile('package.json'));
|
||||
const standardFontDir = path.join(pdfjsPackageDir, 'standard_fonts');
|
||||
|
||||
if (!fs.existsSync(standardFontDir)) {
|
||||
|
|
@ -18,3 +43,18 @@ export function resolvePdfjsStandardFontDataUrl(): string {
|
|||
cachedStandardFontDataUrl = `${standardFontDir.replace(/\/?$/, '/')}`;
|
||||
return cachedStandardFontDataUrl;
|
||||
}
|
||||
|
||||
export function resolvePdfjsWorkerSrc(): string {
|
||||
return pathToFileURL(resolvePdfjsPackageFile('legacy/build/pdf.worker.mjs')).href;
|
||||
}
|
||||
|
||||
export function configurePdfjsNodeRuntime(pdfjs: {
|
||||
GlobalWorkerOptions?: {
|
||||
workerSrc?: string;
|
||||
workerPort?: unknown;
|
||||
};
|
||||
}): void {
|
||||
if (!pdfjs.GlobalWorkerOptions) return;
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = resolvePdfjsWorkerSrc();
|
||||
pdfjs.GlobalWorkerOptions.workerPort = null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { Canvas } from '@napi-rs/canvas';
|
||||
import { resolvePdfjsStandardFontDataUrl } from './pdfjs-runtime';
|
||||
import { configurePdfjsNodeRuntime, resolvePdfjsStandardFontDataUrl } from './pdfjs-runtime';
|
||||
|
||||
type CanvasRuntime = {
|
||||
DOMMatrixCtor: unknown;
|
||||
|
|
@ -106,11 +106,7 @@ export async function renderPage({
|
|||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
const pdfjs = await import('pdfjs-dist/legacy/build/pdf.mjs');
|
||||
|
||||
if (pdfjs.GlobalWorkerOptions) {
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = 'pdfjs-dist/legacy/build/pdf.worker.mjs';
|
||||
pdfjs.GlobalWorkerOptions.workerPort = null;
|
||||
}
|
||||
configurePdfjsNodeRuntime(pdfjs);
|
||||
|
||||
const standardFontDataUrl = resolvePdfjsStandardFontDataUrl();
|
||||
|
||||
|
|
|
|||
|
|
@ -16,13 +16,18 @@ const securityHeaders = [
|
|||
];
|
||||
|
||||
const bundleWorkerCompute = true;
|
||||
const pdfjsTraceFiles = [
|
||||
'./node_modules/pdfjs-dist/package.json',
|
||||
'./node_modules/pdfjs-dist/legacy/build/pdf.mjs',
|
||||
'./node_modules/pdfjs-dist/legacy/build/pdf.worker.mjs',
|
||||
'./node_modules/pdfjs-dist/standard_fonts/**/*',
|
||||
];
|
||||
const serverExternalPackages = [
|
||||
'@napi-rs/canvas',
|
||||
'better-sqlite3',
|
||||
'ffmpeg-static',
|
||||
// Keep pdfjs-dist out of the bundle: it resolves its own on-disk assets
|
||||
// (standard_fonts) at runtime via require.resolve, which only works if it
|
||||
// stays a real package in node_modules rather than being inlined.
|
||||
// Keep pdfjs-dist as a real package in node_modules. Server-side preview
|
||||
// rendering resolves pdf.js runtime assets from the filesystem at runtime.
|
||||
'pdfjs-dist',
|
||||
...(!bundleWorkerCompute ? ['onnxruntime-node', '@huggingface/tokenizers'] : []),
|
||||
];
|
||||
|
|
@ -56,19 +61,15 @@ const nextConfig: NextConfig = {
|
|||
'./node_modules/ffmpeg-static/ffmpeg',
|
||||
],
|
||||
'/api/documents/blob/preview/ensure': [
|
||||
// standard_fonts + the worker are loaded by path/specifier, not a static
|
||||
// import, so trace them explicitly. The rest of pdfjs-dist is pulled in
|
||||
// automatically now that it is a server-external package.
|
||||
'./node_modules/pdfjs-dist/legacy/build/pdf.worker.mjs',
|
||||
'./node_modules/pdfjs-dist/standard_fonts/**/*',
|
||||
// pdf.js runtime assets are resolved through filesystem paths at runtime,
|
||||
// so trace them explicitly for Vercel/standalone serverless bundles.
|
||||
...pdfjsTraceFiles,
|
||||
],
|
||||
'/api/documents/blob/preview/presign': [
|
||||
'./node_modules/pdfjs-dist/legacy/build/pdf.worker.mjs',
|
||||
'./node_modules/pdfjs-dist/standard_fonts/**/*',
|
||||
...pdfjsTraceFiles,
|
||||
],
|
||||
'/api/documents/blob/preview/fallback': [
|
||||
'./node_modules/pdfjs-dist/legacy/build/pdf.worker.mjs',
|
||||
'./node_modules/pdfjs-dist/standard_fonts/**/*',
|
||||
...pdfjsTraceFiles,
|
||||
],
|
||||
},
|
||||
outputFileTracingExcludes: {
|
||||
|
|
|
|||
Loading…
Reference in a new issue