今日「Puppeteer PDF alternative」と検索してここに来たなら、本当に聞きたいことは、おそらく次のようなものです。
「請求書を 1 枚印刷するだけなのに、なぜサーバーレス関数のコールドスタートに 2 秒かかり、RAM を 900 MB も使うのか?」
Puppeteer は非常に優れたツールです。ただし、多くのチームが使っている用途、つまり構造化データを予測可能な PDFへ変換する仕事には、過剰に大きいことがあります。この記事は、Puppeteer を本番投入する直前で、もっと現実的な選択肢がないか気になっているチーム向けの比較です。
Puppeteer が重さに見合う場面、見合わない場面、そして 2026 年時点の実際のトレードオフを整理します。
Puppeteer で実際に本番へ持ち込むもの
npm install puppeteer を実行すると、依存パッケージを除いても、およそ 170 MB の Chromium ビルドを取得します。実行時には、ヘッドレス Chromium が 1 ページのレンダリングに 600〜900 MB の常駐メモリを使い、ブラウザー起動に 1〜2 秒のコールドスタートがかかります。各レンダリングでは次の処理が必要です。
- ブラウザプロセスを起動する、またはプールを再利用する。
- 新しいタブを開く。
- HTML または URL へ移動する。
domcontentloadedを待つ。多くの場合、フォント、画像、Web Components も待つ。page.pdf()を実行し、描画済みページを Chromium の PDF エンジン経由で直列化する。- タブを閉じる。
これは Web プラットフォーム全体を背負うコストです。埋め込み SVG グラフを含む 90 ページの法務契約書でも、テキスト 5 行だけの 1 ページ配送ラベルでも、同じコストを払います。
入力が本当に HTML で、CSS レイアウト、JavaScript で評価されるコンテンツ、Web フォント、その他 Web プラットフォームの機能が必要な HTML から PDF の用途なら、そのコストは妥当です。それ以外、つまり請求書、配送ラベル、領収書、チケット、明細、証明書では、無駄な支出になりやすいです。
Puppeteer が勝つところ
ここを先に正直に見ておかないと、あとでチームが判断を疑うことになります。
- 忠実な HTML/CSS レンダリング。 デザインシステムが HTML を出力し、その HTML とピクセル単位で同じ PDF が必要なら、Puppeteer は非常に強い選択肢です。文字通り Chrome が印刷します。
- Web プラットフォーム機能。 フィルター付き SVG、CSS Grid の例外的な挙動、Web Components、JavaScript で評価されるコンテンツ、サードパーティ iframe などがそのまま動きます。
- 視覚的なデバッグ。 レンダリング途中でスクリーンショットを取り、ヘッドレスモードに対して DevTools を開き、レンダラーが見ているものを確認できます。
- 変換ステップがない。 コンテンツがすでに Web ページなら、スキーマへの写像は不要です。
page.goto(url); await page.pdf()が処理全体です。
このうち 2 つ以上が実際のワークロードに当てはまるなら、移行しないでください。 Puppeteer が正解です。
Puppeteer が大きく負けるところ
それ以外では、コストの積み上がりがすぐに大きくなります。
サーバーレスでのメモリとコールドスタート
Puppeteer を動かす典型的な Node 20 Lambda または Cloudflare Container は、次のようになります。
| 指標 | 典型値 |
|---|---|
| コンテナイメージサイズ | 250〜400 MB (Chromium + Node + 自社コード) |
| コールドスタート時間 | 1.8〜2.5 秒 |
| レンダリングごとのウォーム時 RAM | 600〜900 MB |
| 1 GB インスタンスあたりの同時レンダリング数 | 1 (ページが非常に小さい場合は 2 のこともある) |
請求書サービスが月 100,000 回レンダリングするなら、そのどれも JavaScript 実行を必要としていなくても、コールドコンテナごとにブラウザ起動のコストを払っています。
「コンテナ内フォント」の罠
Chromium にはデフォルトのフォントセットがありますが、そこには CJK、Cyrillic、Devanagari、Arabic、そのほか多くの文字体系固有のグリフが欠けていることがよくあります。本番で気づくと、次のような形になります。
東京オフィス向けの Q3 2025 請求書が
▢▢▢▢ 2025年第3四半期と印刷される。顧客からエスカレーションが来る。チームは Dockerfile のフォントインストールと CSS フォールバックのデバッグに 1 スプリントを使う。
NotoSans CJK だけでもイメージに 約 50 MB 増えます。グローバルな Noto フォールバックセットを入れると 約 250 MB です。日本語の請求書を 1 枚印刷するために、Chromium と巨大なフォント群の両方を抱えることになります。
再現性
Puppeteer のレンダリング結果は、Chromium のバージョンをまたいでバイト単位で同一にはなりません。パッチアップグレードだけで、カーニング、フォントのベースライン、改ページ位置が微妙に変わることがあります。PDF の差分を取るテストスイートがあるなら、そして本来は持つべきですが、Chromium の更新ごとに小さな発掘作業が発生します。どのレンダリングが変わったのか、それは意図した変更なのか、を調べる必要があります。
レンダリング時の JavaScript
「静的」な HTML ページでも、解析、レイアウト計算、描画、直列化が必要です。実測では、ウォーム状態のプロセスでも 1 ページあたり 80〜400 ms 程度かかります。大半は描画ではなくレイアウトです。
比較すると、サーバーが JSON を直接バイナリレンダラーへ渡す構成では、同じ 1 ページ請求書が 3〜8 ms で済みます。この数字には後で触れます。
gPdf が合うところ
gPdf はモデルを反転します。文書を HTML として記述してブラウザーに描画させるのではなく、構造化 JSON(DocumentRequest)として記述し、WebAssembly にコンパイルされた Rust レンダラーが PDF を直接出力します。ブラウザーはありません。DOM もありません。JavaScript のレイアウト処理もありません。
これは制約が強く聞こえますし、HTML 形の問題に対しては実際に制約です。しかし、請求書 / 配送ラベル / 領収書 / 明細 / 証明書 のような文書群では、JSON-first モデルの方がむしろ合っています。
- データはすでに構造化されています。 請求書はどこかで
{ customer, lines, totals, taxes, notes }のようなオブジェクトとして存在しています。それをいったん HTML にして、ブラウザにもう一度レイアウトとして解釈させたいわけではありません。データから PDF へ直接進みたいはずです。 - レイアウト仕様を安定した取り決めとして扱えます。
font_size: 11が常に 11 ポイントを意味し、gap: 8が常に 8 ポイントを意味するなら、PR をレビューする 2 人のエンジニアは同じ出力を見られます。display: flexの解釈差に悩む必要がありません。 - 出力はバイト単位で同一です。 同じ入力 → 同じバイト列。2 つの PDF を
git diffして、本当に変わった箇所だけを見ることができます。 - コールドスタートはブラウザー起動ではなくランタイム起動です。 Cloudflare Workers の V8 isolate は 5〜20 ms で初期化されます。同じ isolate 内では WASM モジュールがメモリ上でウォーム状態になります。
gPdf で 1 ページ請求書をレンダリングすると、Edge 上の実時間で 3〜5 ms p50 が典型です。ユーザーが到達した Cloudflare colo から返されます。これは Puppeteer のウォーム経路より約 2 桁速く、コールドスタート経路より約 3 桁速い水準です。
判断表
技術設計レビューで実際に使うような表にすると、こうなります。
| ワークロード | Puppeteer を使う | gPdf を使う |
|---|---|---|
| 既存 HTML レポート → PDF | ✅ 第一候補 | ⚠️ 作り直しが必要 |
| 請求書、明細、領収書 | ⚠️ 重すぎることが多い | ✅ 第一候補 |
| バーコード付き配送ラベル | ❌ 避けたい (フォント問題) | ✅ 第一候補 |
| E-invoice (Factur-X / ZUGFeRD / EN 16931) | ❌ 組み込み対応なし | ✅ 組み込み対応 |
| PDF/A 長期保存 | ⚠️ Ghostscript などの後段処理が必要 | ✅ 組み込みプロファイル |
| デザインシステムのピクセル忠実なモック | ✅ 第一候補 | ❌ 向かない |
| 実際の D3 / Recharts が必要なチャート | ✅ 第一候補 | ❌ 向かない |
| チケット、証明書、名札 | ⚠️ 過剰になりがち | ✅ 第一候補 |
| レンダリング時に JavaScript が必要なもの | ✅ ほぼ唯一の選択肢 | ❌ 向かない |
右列に 3 行以上当てはまるなら、節約効果は小さくありません。
実比較:1 ページ請求書のレンダリング
同じ内容。同じ用紙サイズ。同じフォント (NotoSans)。同じ PDF/A-3b 出力プロファイルです。
| Puppeteer (warm Lambda, 1 GB) | gPdf (warm Cloudflare Worker) | |
|---|---|---|
| p50 レイテンシ | 180 ms | 3.4 ms |
| p99 レイテンシ | 420 ms | 8 ms |
| コールドスタートの追加時間 | 初回レンダリング +1800 ms | 初回レンダリング +12 ms |
| ピーク時メモリ | 720 MB | 18 MB |
| イメージ / モジュールサイズ | 280 MB | 4.5 MB |
| CJK グリフ | ❌ 明示的なインストールが必要 | ✅ NotoSans CJK を内蔵 |
| 10万回レンダリングあたりのコスト | 約240米ドル (Lambda compute) | 約5米ドル (gPdf Basic plan) |
最後の行は驚かれがちです。コスト差は本物で、客寄せの数字ではありません。構造的な差です。gPdf は Chromium の起動、ブラウザメモリ、コンテナのコールドスタートを償却する必要がないため、レンダリングごとの単価が本当に小さくなります。
「でも10万ページ5米ドルは安すぎないか。落とし穴は?」
落とし穴は、まさにブラウザーを持ち込んでいないことです。ウォーム状態の V8 isolate 上でバイナリレンダラーを動かすコストは、ミリ秒単位の CPU と キロバイト単位のメモリです。Puppeteer 型の価格を付けるなら、それは実行していないインフラに課金していることになります。
それでも Puppeteer を選ぶべきとき
「常に gPdf を使う」と答えるなら、私たちは最悪の相談相手です。そうではありません。正直に言えば、次のケースでは Puppeteer を選ぶ理由があります。
-
すでに本番で Puppeteer を使っていて、問題なく動いている。 移行のために移行しないでください。gPdf を評価するのは、Puppeteer が痛み始めたときです。多くの場合、月間の計算処理コストが400米ドルを超える、またはコールドスタート SLA が下流処理を壊し始めたときです。
-
文書が既存の Web ページそのもの。 デザインシステムで装飾された 60 ページのユーザー生成レポートに、入れ子のチャートと動的コンテンツがあるなら、それは JSON 移行ではありません。再設計です。
-
Web プレビューとのピクセル単位の一致が必要。 「エディタで見たものがそのまま印刷される」系の処理では、両方のレンダラーに Chromium が必要になることがあります。
どれにも当てはまらないなら、計算は単純です。配備物は小さく、レイテンシは低く、請求額は下がり、出力はバイト単位で同一になり、フォントインストールの騒ぎも減ります。
実際のワークロードを移行するには
試す価値があると感じたなら、移行は通常、文書タイプごとに 1〜2 日の検証で済みます。アーキテクチャを作り直す作業ではありません。
- 文書を 1 つ選びます。最も複雑なものではなく、最も生成量が多いものから始めます。
- HTML テンプレートの論理セクションを gPdf JSON 要素 (
text,box,table,barcode,image) に写像します。 - Playground で実際の
DocumentRequestを反復し、出力が合うまで調整します。 - 既存のデータ構造から JSON を出力する小さな写像関数を接続します。
- 新しいエンドポイントを Puppeteer 側と 1 週間 A/B テストします。PDF の差分を確認し、判断します。
多くのチームは、1 日以内に JSON モデルの感覚をつかみます。難しいのは新しいツールではありません。時間をかけて古いテンプレートに積み上がった HTML/CSS の曲芸をほどくことです。
TL;DR
Puppeteer はWeb ページには正解です。文書では、文書をデータとして記述する小さな一度きりのコストを避けるために、レンダリングごとに 100〜200 倍のコストを払っていることがあります。請求書、配送ラベル、領収書、明細、チケット、その他「形は毎回同じで、値だけが変わる」ものを生成するなら、gPdf のような Edge ネイティブなレンダラーは、測定可能な形でより速く、より小さく、より安く、より再現性があります。
Playground で試してください。実際の Edge Worker で動いており、サインアップ不要で、ブラウザー内に 5 ms 未満でレスポンスが返ります。