fix: cross-platform Chrome detection with sane fallbacks (Linux/macOS) - #2
Open
arcahyadi wants to merge 2 commits into
Open
fix: cross-platform Chrome detection with sane fallbacks (Linux/macOS)#2arcahyadi wants to merge 2 commits into
arcahyadi wants to merge 2 commits into
Conversation
findChromePath() only handled Windows, so on Linux/macOS it always returned undefined and rendering depended entirely on puppeteer's own cache download. When that cache is missing or corrupt (e.g. an interrupted download leaves a version folder without the chrome binary), PDF generation fails with: Failed to generate PDF: Could not find Chrome (ver. 145.0.7632.67) - Remove hardcoded "C:\\Users\\Killian\\..." puppeteer-cache path - Add PUPPETEER_EXECUTABLE_PATH as the first override - Add puppeteer.executablePath() as a cache-aware candidate (guarded with try/catch so a broken cache no longer throws) - Add Linux (/usr/bin/google-chrome, chromium, edge, snap, /opt) and macOS (/Applications/...) well-known locations - Log every candidate path so misconfiguration is visible
Headings were rendered without id attributes, so markdown links pointing at headers within the same document (e.g. a table of contents using [Bab 1](Sterbweise#1-ringkasan-layanan)) had no target and were dead in the generated PDF. rehype-slug generates the same GitHub-style slugs users expect (1-ringkasan-layanan, 13-bantuan-dan-kontak, ...), which Chrome's print-to-PDF converts into named destinations and clickable internal link annotations.
Author
|
Follow-up commit `264d2d4` — second real-world failure found while rendering a 19 KB Indonesian student-services guide (12-page PDF with a linked table of contents): Problem: internal anchor links ( Fix: added Verified end-to-end on the user's actual 12-page document:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
findChromePath()inapp/lib/pdfGenerator.tsonly handled Windows. On Linux and macOS it returnedundefined, so PDF generation depended entirely on Puppeteer's own cache download. When that cache is missing or corrupt, rendering fails hard on non-Windows systems.The problem in detail
1. Hardcoded developer-machine path
The very first candidate was a path baked into the source for one specific machine:
This does nothing on other machines (wrong username, wrong pinned version
144.0.7559.96vs the one the current Puppeteer actually pins), andprocess.env["USERPROFILE"]variant still only runs on Windows.2. Linux/macOS got no candidates at all
findChromePath()ends withreturn undefined;for every non-Windows platform. The caller then falls back topuppeteer.launch(launchOptions)with noexecutablePath, which makes Puppeteer resolve its cache directory (~/.cache/puppeteer). If a pinned browser is not there, launch fails:3. Real-world failure mode observed
On an Ubuntu 24.04 (LXC) machine, the pinned Chrome download had been interrupted mid-extraction: the cache contained
~/.cache/puppeteer/chrome/linux-145.0.7632.67/chrome-linux64/with support folders (ABOUT,MEIPreload,WidevineCdm, ...) but nochromebinary (~131 MB of ~175 MB). Two aggravating effects:Every PDF render failed with
Could not find Chrome (ver. 145.0.7632.67), even though/usr/bin/google-chromewas installed and perfectly usable.Re-running
npx puppeteer browsers install chromerefused to repair it, because the version folder already exists:The user must manually
rm -rfthe corrupt folder before the installer will retry — a trap that is invisible from the error message.So the app had a single point of failure (the cache), no system-browser fallback outside Windows, and no diagnostic output about what it looked for.
What this PR changes
findChromePath()is now cross-platform and ordered by priority:PUPPETEER_EXECUTABLE_PATH— the standard Puppeteer env override, checked first so deployments can pin any browser explicitly.puppeteer.executablePath()— Puppeteer's own pinned cache binary, wrapped intry/catch. Previously an inconsistent/corrupt cache made the whole call throw; now it's just a non-candidate and we fall through./usr/bin/google-chrome,/usr/bin/google-chrome-stable,/usr/bin/chromium,/usr/bin/chromium-browser,/usr/bin/microsoft-edge,/snap/bin/chromium,/opt/google/chrome/chrome/Applications/Google Chrome.app/...,/Applications/Chromium.app/...,/Applications/Microsoft Edge.app/...C:\Users\Killian\...entry.The search loop now also logs every candidate path it probes (not only on Windows), so the next "Could not find Chrome" incident comes with diagnostics instead of a dead end.
Testing
On Ubuntu 24.04 (LXC) against
next dev:tsc --noEmit— clean.POST /api/convert-pdf→HTTP 200, valid 1-page PDF; process list confirms the pinnedchrome-linux64/chromeis used.POST /api/convert-pdf→HTTP 200, valid 1-page PDF via/usr/bin/google-chrome. With the old code this exact scenario returned the "Could not find Chrome" failure.