Blog

gPdf vs Puppeteer: kiedy 800 MB Chromium to zła odpowiedź

Puppeteer renderuje dowolną stronę webową do PDF, ale często płacisz za przeglądarkę, której prawie nie używasz. Praktyczne porównanie dla zespołów wybierających stos PDF w 2026 roku.

Jeśli dziś szukałeś “Puppeteer PDF alternative”, prawdziwe pytanie brzmi zapewne mniej więcej tak:

“Dlaczego moja funkcja serverless ma cold start przez 2 sekundy i używa 900 MB RAM tylko po to, żeby wydrukować jedną fakturę?”

Puppeteer to świetne narzędzie. Jest też mocno przewymiarowane do zadania, do którego używa go wiele zespołów: zamiany strukturalnych danych w przewidywalny PDF. Ten artykuł jest dla zespołu, który zaraz wypchnie Puppeteer na produkcję i po cichu zastanawia się, czy istnieje rozsądniejsza opcja.

Omówimy, gdzie Puppeteer naprawdę uzasadnia swój ciężar, gdzie go nie uzasadnia i jak wygląda praktyczna macierz decyzji w 2026 roku.

Co naprawdę dostarczasz z Puppeteer

Gdy uruchamiasz npm install puppeteer, pobierasz około 170 MB kompilacji Chromium przed zależnościami przechodnimi. W czasie działania Chromium w trybie bez głowy potrzebuje 600-900 MB pamięci rezydentnej dla pojedynczego renderu strony oraz 1-2 sekundy cold startu, żeby uruchomić proces przeglądarki. Każdy render musi:

  1. Uruchomić proces przeglądarki albo użyć puli
  2. Otworzyć nową kartę
  3. Przejść do HTML/URL
  4. Poczekać na domcontentloaded, a zwykle także na fonty, obrazy i web components
  5. Uruchomić page.pdf(), które serializuje namalowaną stronę przez silnik PDF Chromium
  6. Zamknąć kartę

To jest podatek całej platformy webowej. Płacisz go niezależnie od tego, czy dokumentem jest 90-stronicowa umowa prawna z osadzonymi wykresami SVG, czy jednostronicowa etykieta wysyłkowa z pięcioma liniami tekstu.

Dla przypadków HTML do PDF, w których wejście naprawdę wymaga układu CSS, treści liczonej JavaScriptem, fontów webowych i reszty platformy webowej, ten podatek jest uczciwy. Dla wszystkiego innego, czyli faktur, etykiet, paragonów, biletów, wyciągów i certyfikatów, to palenie pieniędzy.

Gdzie Puppeteer wygrywa

Najpierw trzeba uczciwie nazwać tę stronę decyzji, inaczej zespół będzie ją później kwestionował:

  • Wierne renderowanie HTML/CSS. Jeżeli system projektowy emituje HTML i chcesz pikselowo identyczne PDF-y tego HTML, Puppeteer jest bezkonkurencyjny. To dosłownie drukowanie z Chrome.
  • Funkcje platformy webowej. SVG z filtrami, przypadki brzegowe CSS Grid, web components, treść wyliczana JavaScriptem, iframe’y stron trzecich — to wszystko po prostu działa.
  • Debugowanie wizualne. Możesz zrobić screenshot w środku renderu, otworzyć DevTools dla trybu bez głowy i zobaczyć dokładnie to, co widzi silnik.
  • Brak kroku tłumaczenia. Jeżeli treść jest już stroną webową, nie ma mapowania schematu. page.goto(url); await page.pdf() to cały potok.

Jeżeli dowolne dwa z tych punktów opisują realne obciążenie, nie migruj. Puppeteer jest właściwą odpowiedzią.

Gdzie Puppeteer mocno przegrywa

Dla pozostałych przypadków koszty szybko się sumują.

Pamięć i cold start w serverless

Typowy Node 20 Lambda albo Cloudflare Container uruchamiający Puppeteer:

Metryka Typowa wartość
Rozmiar obrazu kontenera 250-400 MB (Chromium + Node + Twój kod)
Cold start 1,8-2,5 sekundy
RAM na ciepły render 600-900 MB
Równoległe rendery na instancję 1 GB 1 (czasem 2, jeśli strony są małe)

Jeżeli usługa faktur obsługuje 100 000 renderów miesięcznie, płacisz za energię uruchamiania przeglądarki przy każdym zimnym kontenerze, mimo że żaden z tych renderów nie potrzebował wykonania JavaScriptu.

Pułapka fontów w kontenerach

Chromium przychodzi z domyślnym zestawem fontów, w którym zwykle brakuje CJK, cyrylicy, dewanagari, arabskiego i długiego ogona glifów specyficznych dla skryptów. W produkcji wygląda to tak:

Faktura Q3 2025 dla biura w Tokio drukuje ▢▢▢▢ 2025年第3四半期. Klient eskaluje. Zespół spędza sprint na instalacji fontów w Dockerfile i regułach fontów zastępczych w CSS.

Samo osadzenie NotoSans CJK dodaje około 50 MB do obrazu. Globalny zestaw fontów zastępczych Noto dodaje około 250 MB. Płacisz za Chromium i katedrę fontów tylko po to, żeby wydrukować jedną japońską fakturę.

Determinizm

Rendery Puppeteer nie są bajtowo identyczne między wersjami Chromium. Aktualizacja patch może subtelnie przesunąć kerning, baseline fontu albo miejsca łamania stron. Jeżeli masz testy porównujące PDF-y, a powinieneś je mieć, każda aktualizacja Chromium staje się małym dochodzeniem: co się zmieniło i czy było to zamierzone?

JavaScript w czasie renderu

Nawet “statyczna” strona HTML musi zostać sparsowana, ułożona, namalowana i zserializowana. Empirycznie daje to 80-400 ms na stronę na ciepłym procesie. Większość tego czasu to układ, nie samo malowanie.

Dla porównania: serwer zwracający JSON bezpośrednio do binarnego silnika renderującego potrzebuje 3-8 ms dla tej samej jednostronicowej faktury. Do tych liczb zaraz wrócimy.

Gdzie pasuje gPdf

gPdf odwraca model: zamiast opisywać dokument jako HTML i prosić przeglądarkę, by go namalowała, opisujesz go jako strukturalny JSON (DocumentRequest), a silnik Rust skompilowany do WebAssembly emituje PDF bezpośrednio. Nie ma przeglądarki. Nie ma DOM. Nie ma przebiegu układu JavaScript.

Brzmi ograniczająco i takie jest dla problemów o kształcie HTML. Ale dla klasy dokumentów faktura / etykieta / paragon / wyciąg / certyfikat model JSON-first jest zwykle lepszym dopasowaniem:

  • Dane są już strukturalne. Faktura i tak istnieje gdzieś jako obiekt { customer, lines, totals, taxes, notes }. Nie chcesz najpierw renderować tego do HTML tylko po to, żeby przeglądarka z powrotem odczytała HTML jako układ. Chcesz przejść prosto z danych do PDF.
  • Układ staje się kontraktem. Gdy font_size: 11 zawsze oznacza 11 punktów, a gap: 8 zawsze oznacza 8 punktów, dwóch inżynierów przeglądających PR widzi dokładnie ten sam wynik. Nie ma różnicy interpretacji display: flex.
  • Wyjście jest bajtowo identyczne. Ten sam input → te same bajty. Możesz zrobić git diff dwóch PDF-ów i zobaczyć tylko rzeczywistą zmianę.
  • Cold start to start środowiska, nie uruchomienie przeglądarki. Izolat V8 w Cloudflare Workers inicjalizuje się w 5-20 ms. Moduł WASM pozostaje gorący w pamięci między wywołaniami na tym samym izolacie.

Typowy render jednostronicowej faktury w gPdf to 3-5 ms p50 wall-clock na edge, obsłużone z tego colo Cloudflare, w które trafił użytkownik. To około dwa rzędy wielkości szybciej niż ciepła ścieżka Puppeteer i trzy rzędy wielkości szybciej niż zimna ścieżka.

Macierz decyzji

Użyj tabeli, której faktycznie użyłbyś w przeglądzie projektu technicznego.

Obciążenie Użyj Puppeteer Użyj gPdf
Istniejący raport HTML → PDF ✅ pierwszy wybór ⚠️ wymaga przepisania
Faktury, wyciągi, paragony ⚠️ ciężkie narzędzie ✅ pierwszy wybór
Etykiety wysyłkowe z kodami kreskowymi ❌ unikaj (problemy z fontami) ✅ pierwszy wybór
E-invoice (Factur-X / ZUGFeRD / EN 16931) ❌ brak wbudowanego wsparcia ✅ wbudowane
Długoterminowa archiwizacja PDF/A ⚠️ wymaga przebiegu Ghostscript ✅ wbudowane profile
Makiety systemu projektowego z wiernością pikselową ✅ pierwszy wybór ❌ niewłaściwe narzędzie
Wykresy wymagające prawdziwego D3 / Recharts ✅ pierwszy wybór ❌ niewłaściwe narzędzie
Bilety, certyfikaty, identyfikatory ⚠️ nadmiarowe ✅ pierwszy wybór
Cokolwiek wymagającego JavaScriptu w czasie renderu ✅ jedyny wybór ❌ niewłaściwe narzędzie

Jeżeli prawa kolumna pasuje w więcej niż trzech wierszach, oszczędności nie są subtelne.

Realne porównanie: render jednostronicowej faktury

Ta sama treść. Ten sam rozmiar papieru. Te same fonty (NotoSans). Ten sam profil wyjściowy PDF/A-3b.

Puppeteer (ciepły Lambda, 1 GB) gPdf (ciepły Cloudflare Worker)
Latencja p50 180 ms 3,4 ms
Latencja p99 420 ms 8 ms
Kara za cold start +1800 ms pierwszy render +12 ms pierwszy render
Szczytowa pamięć 720 MB 18 MB
Rozmiar obrazu / modułu 280 MB 4,5 MB
Glify CJK ❌ chyba że jawnie zainstalowane ✅ osadzony NotoSans CJK
Koszt / 100 000 renderów około 240 USD (obliczenia Lambda) około 5 USD (plan gPdf Basic)

Ostatni wiersz często zaskakuje. Różnica kosztu jest realna i nie jest promocją. Jest strukturalna. Nie musimy amortyzować startu Chromium, pamięci przeglądarki ani cold startów kontenera, więc koszt jednostkowy renderu jest naprawdę mały.

“Ale 5 USD za 100 000 stron brzmi zbyt tanio. Gdzie haczyk?”

Haczyk polega dokładnie na tym, że nie wysyłamy przeglądarki. Koszt uruchomienia binarnego silnika na ciepłym izolacie V8 to milisekundy CPU i kilobajty pamięci. Pobieranie cen w kształcie Puppeteer oznaczałoby opłatę za infrastrukturę, której nie uruchamiamy.

Kiedy nadal powinieneś wybrać Puppeteer

Bylibyśmy najgorszym doradcą, gdyby nasza odpowiedź zawsze brzmiała “użyj gPdf”. Nie brzmi. Uczciwe przypadki:

  1. Masz już Puppeteer na produkcji i działa. Nie migruj dla sportu. Właściwy moment na ocenę gPdf przychodzi wtedy, gdy Puppeteer zaczyna boleć: zwykle gdy miesięczne rachunki za obliczenia przekraczają 400 USD albo gdy cold start łamie coś niżej w procesie.

  2. Dokumenty są istniejącymi stronami webowymi, kropka. 60-stronicowy raport użytkownika stylowany przez Twój system projektowy, z zagnieżdżonymi wykresami i dynamiczną treścią, nie jest migracją do JSON. To przeprojektowanie.

  3. Potrzebujesz pikselowej zgodności z webowym podglądem. Niektóre procesy, na przykład “to, co widzisz w edytorze, dokładnie drukuje się w PDF”, naprawdę potrzebują Chromium jako silnika po obu stronach.

Jeżeli żaden z tych punktów nie dotyczy Twojego przypadku, matematyka jest prosta: mniejsze wdrożenie, niższa latencja, niższy rachunek, bajtowo identyczne wyjście i brak dramatu z instalacją fontów.

Jak migrować realne obciążenie

Jeżeli jesteś wystarczająco przekonany, żeby spróbować, migracja zwykle jest 1-2-dniowym eksperymentem na typ dokumentu, nie zmianą architektury:

  1. Wybierz jeden dokument — zacznij od tego o największym wolumenie, nie od najbardziej złożonego.
  2. Zmapuj logiczne sekcje szablonu HTML na elementy JSON gPdf (text, box, table, barcode, image).
  3. Użyj Playground, żeby iterować na realnym DocumentRequest, aż wynik będzie zgodny.
  4. Podłącz istniejący kształt danych do małej funkcji mapującej, która emituje JSON.
  5. Uruchom nową ścieżkę A/B wobec obecnej ścieżki Puppeteer przez tydzień. Porównaj PDF-y. Podejmij decyzję.

Większość zespołów łapie model JSON w jeden dzień. Trudnością nie jest nowe narzędzie, tylko rozplątanie gimnastyki HTML/CSS, którą stary szablon obrósł przez lata.

TL;DR

Puppeteer jest właściwą odpowiedzią dla stron webowych. Dla dokumentów płacisz podatek 100-200 razy na każdym renderze, żeby uniknąć małego jednorazowego kosztu opisania dokumentu jako danych. Jeżeli Twoja flota renderuje faktury, etykiety, paragony, wyciągi, bilety albo cokolwiek o kształcie “ten sam układ za każdym razem, inne wartości”, generator na edge taki jak gPdf będzie mierzalnie szybszy, mniejszy, tańszy i bardziej deterministyczny.

Wypróbuj Playground: to prawdziwy worker na edge, bez rejestracji, z odpowiedzią w przeglądarce poniżej 5 ms.