Skip to content

fix: copy pdf-parse, xlsx, papaparse, mammoth into packaged app bundle#518

Open
deepak0x wants to merge 1 commit intorowboatlabs:mainfrom
deepak0x:fix/pdf-parse-bundle-missing-deps
Open

fix: copy pdf-parse, xlsx, papaparse, mammoth into packaged app bundle#518
deepak0x wants to merge 1 commit intorowboatlabs:mainfrom
deepak0x:fix/pdf-parse-bundle-missing-deps

Conversation

@deepak0x
Copy link
Copy Markdown

@deepak0x deepak0x commented Apr 21, 2026

Fixes #486

The four file parser packages (pdf-parse, xlsx, papaparse, mammoth) are loaded inside builtin-tools.ts using a _importDynamic wrapper:

const _importDynamic = new Function('mod', 'return import(mod)') as (mod: string) => Promise<any>;

The comment above it explains the intent — using new Function prevents esbuild from statically resolving the imports, which avoids pulling pdfjs-dist's DOM polyfills into the Electron main process.

The problem is that this creates a conflict with how the app is packaged:

  • esbuild cannot see the dynamic import, so the packages are not bundled into main.cjs
  • forge.config.cjs explicitly ignores all node_modules when packaging the app

At runtime inside the packaged .app, when _importDynamic('pdf-parse') runs, there is no node_modules anywhere in the directory tree. The error is always:

Cannot find package 'pdf-parse' imported from /Applications/Rowboat.app/Contents/Resources/app/.package/dist/main.cjs

The same failure happens for xlsx, papaparse, and mammoth — all four file formats in parseFile are broken.

Fix

Two file changes:

bundle.mjs — mark the four packages as esbuild externals. The bundled main.cjs will emit require('pdf-parse') calls instead of trying (and failing) to inline them.

forge.config.cjs — after bundling, walk the pnpm store recursively and copy all transitive and optional dependencies of the four packages into .package/node_modules/. Optional dependencies are included because pdfjs-dist loads @napi-rs/canvas (an optional dep) to polyfill DOMMatrix — without it pdf-parse throws at import time.

… app

These four packages are loaded via _importDynamic (new Function pattern) in
builtin-tools.ts to prevent esbuild from statically bundling pdfjs-dist's DOM
polyfills into the Electron main process. As a result, esbuild cannot inline
them into main.cjs, and they are not available at runtime in the packaged app.

Two changes to fix this:

1. bundle.mjs: mark the four packages as esbuild external so the generated
   main.cjs emits require() calls for them rather than inlining them.

2. forge.config.cjs: after bundling, recursively collect all transitive and
   optional dependencies of the four packages from the pnpm store and copy
   them into .package/node_modules/. Optional deps are included because
   @napi-rs/canvas (required by pdfjs-dist for DOMMatrix polyfills) ships
   its native binaries as optional platform-specific packages.

Fixes: pdf-parse, xlsx, papaparse, mammoth all fail with
'Cannot find package' in the packaged .app (issue rowboatlabs#486).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Missing dependency: pdf-parse not found in application bundle

1 participant