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:
- Uruchomić proces przeglądarki albo użyć puli
- Otworzyć nową kartę
- Przejść do HTML/URL
- Poczekać na
domcontentloaded, a zwykle także na fonty, obrazy i web components - Uruchomić
page.pdf(), które serializuje namalowaną stronę przez silnik PDF Chromium - 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: 11zawsze oznacza 11 punktów, agap: 8zawsze oznacza 8 punktów, dwóch inżynierów przeglądających PR widzi dokładnie ten sam wynik. Nie ma różnicy interpretacjidisplay: flex. - Wyjście jest bajtowo identyczne. Ten sam input → te same bajty. Możesz zrobić
git diffdwó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:
-
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.
-
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.
-
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:
- Wybierz jeden dokument — zacznij od tego o największym wolumenie, nie od najbardziej złożonego.
- Zmapuj logiczne sekcje szablonu HTML na elementy JSON gPdf (
text,box,table,barcode,image). - Użyj Playground, żeby iterować na realnym
DocumentRequest, aż wynik będzie zgodny. - Podłącz istniejący kształt danych do małej funkcji mapującej, która emituje JSON.
- 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.