Invoices: ship pdfjs-dist's worker into the standalone image
Every PDF import failed in production with "Setting up fake worker failed: Cannot find module '/app/node_modules/pdfjs-dist/legacy/build/pdf.worker.mjs'". output: "standalone" ships only the files Next's output tracer can see. It traced pdf.mjs, because lib/invoice-parser.ts imports it by literal path, but the worker's sole reference is a createRequire(...).resolve() call, which the tracer does not follow. So the image contained pdf.mjs alone, pdfjs fell back to its default "./pdf.worker.mjs" relative to pdf.mjs, and the import hit a file that was never copied. Copy the whole package in the runner stage: the worker has to sit next to pdf.mjs, and so do the standard fonts, which the parser needs because it passes useSystemFonts. Verified against the reconstructed runner layout — the old layout reproduces the error verbatim, the new one parses and extracts text. Also in lib/invoice-parser.ts: workerPinned was set before the resolve, so a failed resolve was never retried; and the empty catch swallowed the MODULE_NOT_FOUND that named the real cause. Both fixed.
This commit is contained in:
parent
2594dead84
commit
6ae4e30284
2 changed files with 23 additions and 5 deletions
|
|
@ -78,6 +78,15 @@ COPY --from=builder /app/public ./public
|
|||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||
|
||||
# Next's output tracer cannot see pdfjs-dist's worker. The only reference to it
|
||||
# is a createRequire(...).resolve() call, which the tracer does not follow, so
|
||||
# the standalone bundle ships pdf.mjs WITHOUT pdf.worker.mjs — and every parse
|
||||
# then dies with "Setting up fake worker failed: Cannot find module
|
||||
# '/app/node_modules/pdfjs-dist/legacy/build/pdf.worker.mjs'". Copy the package
|
||||
# in whole: the worker has to sit next to pdf.mjs at runtime, and so do the
|
||||
# standard fonts, which the parser needs because it passes useSystemFonts.
|
||||
COPY --from=deps --chown=nextjs:nodejs /app/node_modules/pdfjs-dist ./node_modules/pdfjs-dist
|
||||
|
||||
USER nextjs
|
||||
EXPOSE 3000
|
||||
|
||||
|
|
|
|||
|
|
@ -172,21 +172,30 @@ export function isoDate(s: string): string {
|
|||
// falls back to a dynamic import of the worker module, which the bundler rewrites to a
|
||||
// .next path that does not exist in the standalone image — every parse then dies with
|
||||
// "Setting up fake worker failed". Pinning the worker to the real installed file avoids
|
||||
// that. pdfjs-dist is listed in serverExternalPackages so it is required (and traced)
|
||||
// from node_modules rather than bundled.
|
||||
// that, but only if the file is actually there: pdfjs-dist is in
|
||||
// serverExternalPackages so it is required from node_modules rather than bundled, and
|
||||
// Next's tracer does NOT copy pdf.worker.mjs — the standalone bundle contains pdf.mjs
|
||||
// alone. The Dockerfile copies the whole package in for that reason. Do not assume this
|
||||
// pin alone is sufficient.
|
||||
let workerPinned = false;
|
||||
async function loadPdfjs() {
|
||||
const pdfjs = await import("pdfjs-dist/legacy/build/pdf.mjs");
|
||||
if (!workerPinned) {
|
||||
workerPinned = true;
|
||||
try {
|
||||
const { createRequire } = await import("node:module");
|
||||
const req = createRequire(import.meta.url);
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = req.resolve(
|
||||
"pdfjs-dist/legacy/build/pdf.worker.mjs",
|
||||
);
|
||||
} catch {
|
||||
// Leave pdfjs's own default in place; it is correct for unbundled Node.
|
||||
workerPinned = true;
|
||||
} catch (err) {
|
||||
// Not fatal, but it must not be silent: pdfjs then falls back to a worker
|
||||
// path relative to pdf.mjs, so the parse fails much later with an opaque
|
||||
// "Setting up fake worker failed". Staying UNpinned lets the next parse
|
||||
// retry, so the worker is picked up as soon as it is on disk.
|
||||
console.error(
|
||||
`[invoice-parser] could not resolve pdf.worker.mjs: ${(err as Error).message}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
return pdfjs;
|
||||
|
|
|
|||
Loading…
Reference in a new issue