ब्लॉग

gPdf vs Puppeteer: जब 800 MB Chromium गलत जवाब हो

Puppeteer किसी भी web page को PDF बना सकता है, लेकिन कई workloads में आप ऐसे headless browser की कीमत देते हैं जिसकी जरूरत नहीं। 2026 के लिए व्यावहारिक तुलना।

अगर आपने आज “Puppeteer PDF alternative” खोजा है, तो असली सवाल शायद यह है:

“एक invoice print करने के लिए मेरी serverless function cold-start में 2 seconds और 900 MB RAM क्यों ले रही है?”

Puppeteer शानदार tool है। लेकिन जिस काम के लिए बहुत सी teams उसे इस्तेमाल करती हैं, यानी structured data को predictable PDF में बदलना, उसके लिए वह बहुत बड़ा हथौड़ा है। यह लेख उस team के लिए है जो Puppeteer production में भेजने वाली है और सोच रही है कि क्या कोई अधिक व्यावहारिक रास्ता है।

Puppeteer के साथ आप वास्तव में क्या ship करते हैं

npm install puppeteer के साथ आप dependencies से पहले ही लगभग 170 MB Chromium build डाउनलोड करते हैं। Runtime में headless Chromium एक page render के लिए 600-900 MB resident memory और browser spin-up के लिए 1-2 seconds cold start ले सकता है। हर render में:

  1. Browser process boot होता है, या pool reuse होता है।
  2. नया tab खुलता है।
  3. आपका HTML / URL navigate होता है।
  4. domcontentloaded और अक्सर fonts, images, web components का इंतजार होता है।
  5. page.pdf() painted page को Chromium PDF engine से serialize करता है।
  6. Tab बंद होता है।

यह पूरी web platform का tax है। 90-page legal contract हो या five-line shipping label, tax वही है।

जहां input सच में HTML है और CSS layout, JavaScript, web fonts और browser semantics चाहिए, यह tax उचित है। Invoices, labels, receipts, tickets, statements और certificates के लिए अक्सर यह बर्बादी है।

Puppeteer कहां जीतता है

पहले यह ईमानदारी से तय करें:

  • Faithful HTML/CSS rendering. Design system HTML emit करता है और PDF pixel-identical चाहिए, तो Puppeteer best है। यह Chrome printing है।
  • Web-platform features. SVG filters, CSS Grid edge cases, web components, JavaScript content और third-party iframes चलते हैं।
  • Visual debugging. Render के बीच screenshot, headless DevTools और exact visual state मिलती है।
  • Zero translation step. Content पहले से webpage है तो schema mapping नहीं। page.goto(url); await page.pdf() pipeline है।

इनमें से दो points आपके workload पर फिट हैं तो migrate न करें। Puppeteer सही जवाब है।

Puppeteer कहां बुरी तरह हारता है

बाकी cases में cost जल्दी जुड़ता है।

Serverless में memory और cold start

Typical Node 20 Lambda या Cloudflare Container में Puppeteer:

Metric Typical value
Container image size 250-400 MB (Chromium + Node + your code)
Cold-start time 1.8 - 2.5 seconds
Warm RAM per render 600 - 900 MB
Concurrent renders per 1 GB instance 1 (sometimes 2 if pages are tiny)

अगर invoice service महीने में 1,00,000 रेंडर करती है, तो हर cold container में browser boot की कीमत चुकती है, जबकि उन renders में JavaScript execution की जरूरत नहीं थी।

Containers में fonts का trap

Chromium default fonts के साथ आता है, लेकिन CJK, Cyrillic, Devanagari, Arabic और कई scripts अक्सर missing होती हैं। Production में यह ऐसे दिखता है:

Tokyo office की Q3 2025 invoice ▢▢▢▢ 2025年第3四半期 print करती है। Customer escalates. Team Dockerfile font installs और CSS fallback debug करने में sprint लगा देती है।

सिर्फ NotoSans CJK image में ~50 MB जोड़ता है। Global Noto fallback set ~250 MB तक जोड़ सकता है। एक Japanese invoice print करने के लिए आप Chromium और font cathedral दोनों की कीमत दे रहे हैं।

Determinism

Puppeteer renders Chromium versions के बीच byte-identical नहीं रहते। Patch upgrade kerning, font baseline या page breaks बदल सकता है। अगर PDF diff tests हैं, हर Chromium update एक investigation बन जाता है।

Render-time JavaScript

“Static” HTML भी parse, layout, paint और serialize होता है। Warm process पर भी यह अक्सर 80-400 ms per page होता है। वही one-page invoice JSON से binary renderer को देने पर 3-8 ms में निकल सकती है।

gPdf कहां fit होता है

gPdf model बदलता है: document को HTML के रूप में बताकर browser से paint नहीं करवाता। आप उसे structured JSON (DocumentRequest) के रूप में बताते हैं, और Rust renderer WebAssembly में compile होकर PDF direct emit करता है। Browser नहीं, DOM नहीं, JavaScript layout pass नहीं।

यह HTML-shaped problems के लिए सीमित है। लेकिन invoice / label / receipt / statement / certificate जैसे documents के लिए JSON-first model अक्सर बेहतर है:

  • Data पहले से structured है। Invoice आम तौर पर { customer, lines, totals, taxes, notes } object के रूप में होती है। उसे HTML बनाकर फिर browser से layout पढ़वाना अनावश्यक है।
  • Layout contract बनता है। font_size: 11 हमेशा 11 points है, gap: 8 हमेशा 8 points।
  • Output byte-identical है। Same input → same bytes. PDF diff विश्वसनीय है।
  • Cold start runtime startup है, browser boot नहीं। Cloudflare Workers का V8 isolate 5-20 ms में शुरू होता है, और WASM module उसी isolate में hot रहता है।

gPdf की typical one-page invoice render edge पर 3-5 ms p50 wall-clock देती है। यह Puppeteer warm path से लगभग दो orders और cold path से तीन orders तेज है।

Decision matrix

Workload Use Puppeteer Use gPdf
Existing HTML report → PDF ✅ first choice ⚠️ requires rewrite
Invoices, statements, receipts ⚠️ heavy hammer ✅ first choice
Shipping labels with barcodes ❌ avoid (font issues) ✅ first choice
E-invoice (Factur-X / ZUGFeRD / EN 16931) ❌ no built-in support ✅ built-in
PDF/A long-term archival ⚠️ needs Ghostscript pass ✅ built-in profiles
Pixel-faithful design system mockups ✅ first choice ❌ wrong tool
Charts that need real D3 / Recharts ✅ first choice ❌ wrong tool
Tickets, certificates, name-tags ⚠️ overkill ✅ first choice
Anything that needs JavaScript at render time ✅ only choice ❌ wrong tool

अगर right column तीन से ज्यादा rows में जीतता है, savings छोटी नहीं हैं।

Real comparison: one-page invoice render

Same content, paper size, NotoSans fonts और PDF/A-3b profile:

Puppeteer (warm Lambda, 1 GB) gPdf (warm Cloudflare Worker)
p50 latency 180 ms 3.4 ms
p99 latency 420 ms 8 ms
Cold-start penalty +1800 ms first render +12 ms first render
Memory at peak 720 MB 18 MB
Image / module size 280 MB 4.5 MB
CJK glyphs ❌ unless explicit install ✅ embedded NotoSans CJK
लागत / 1,00,000 रेंडर ~$240 (Lambda compute) ~$5 (gPdf Basic plan)

Last row surprise करता है, लेकिन यह teaser price नहीं है। हम Chromium boot, browser memory और container cold starts amortize नहीं करते।

“$5/1,00,000 पृष्ठ बहुत cheap लगता है। Catch क्या है?”

Catch यही है कि हम browser ship नहीं करते। Warm V8 isolate पर binary renderer चलाने की cost milliseconds CPU और kilobytes memory है। Puppeteer-shaped price लेना ऐसी infrastructure के लिए charge करना होगा जिसे हम चलाते ही नहीं।

कब Puppeteer ही चुनना चाहिए

हमेशा “gPdf use करो” ईमानदार जवाब नहीं है:

  1. Puppeteer production में है और ठीक चल रहा है। सिर्फ बदलने के लिए migrate न करें। gPdf तब evaluate करें जब compute bill 400 USD/माह पार करे या cold-start SLA तोड़े।
  2. Documents सचमुच existing webpages हैं। User-generated 60-page report with charts और dynamic content JSON migration नहीं, redesign है।
  3. Web preview से pixel-perfect parity चाहिए। “Editor में जो दिखे वही print हो” workflows दोनों sides पर Chromium मांगते हैं।

इनमें से कुछ भी लागू नहीं होता तो math सीधी है: smaller deploy, lower latency, lower bill, byte-identical output और font-install drama कम।

Real workload migrate कैसे करें

आमतौर पर यह per document type 1-2 दिन का spike है:

  1. एक document चुनें, preferably highest-volume, सबसे complex नहीं।
  2. HTML template के logical sections को gPdf JSON elements (text, box, table, barcode, image) में map करें।
  3. Playground में real DocumentRequest iterate करें।
  4. Existing data-shape से JSON emit करने वाला छोटा mapper लिखें।
  5. एक सप्ताह Puppeteer endpoint के साथ A/B चलाएं। PDFs diff करें। फिर decide करें।

Most teams को JSON model एक दिन में समझ आ जाता है। मुश्किल new tool नहीं, पुराने HTML/CSS gymnastics खोलना है।

TL;DR

Puppeteer web pages के लिए सही जवाब है। Documents के लिए आप document को data के रूप में describe करने के छोटे one-time cost से बचने के लिए हर render पर 100-200× tax देते हैं। अगर system invoices, labels, receipts, statements या tickets जैसी “same shape, different values” चीजें generate करता है, gPdf जैसा edge-native renderer measurable तौर पर faster, smaller, cheaper और deterministic होगा।

Playground में आजमाएं। यह real edge worker है, signup नहीं, browser में under 5 ms response।