Блог

gPdf vs DocRaptor: почему рендеринг на edge побеждает HTML-в-PDF

DocRaptor использует Prince для конвертации HTML в PDF на хостинговом бэкенде. gPdf рендерит структурированный JSON напрямую на edge Cloudflare. Разница цен — 18×. Вот почему это не наживка.

DocRaptor — компетентный продукт. Оборачивает Prince — золотой стандарт движков HTML-в-PDF — в хостинговый REST API с retry, асинхронными job-ами и приличной документацией. Существует более десяти лет, и для многих команд это очевидный выбор «не хочу самостоятельно эксплуатировать Prince».

Мы — инструмент другой формы. gPdf вообще не принимает HTML; берёт структурированный JSON и рендерит напрямую на edge Cloudflare. Разница прайс-листа при 100K страниц/месяц: $5/месяц (gPdf Basic) vs $89/месяц (DocRaptor Basic) — около 18×. Эта разница не открывающая промо. Она структурная. Этот пост объясняет, почему структура производит эту цену, и где каждый инструмент действительно подходит.

Две архитектуры рядом

СлойDocRaptor (HTML → PDF)gPdf (JSON → PDF)
ВходHTML + CSS (с расширениями Prince paged-media)JSON DocumentRequest
RendererPrince (компилированный C++ движок)Собственный движок Rust, скомпилированный в WebAssembly
ХостингЦентрализованные серверы DocRaptor (датацентр US)Cloudflare Workers, каждый CF colo (300+ городов)
Холодный стартСерверный пул воркеровЗагрузка V8 isolate, однозначные мс
Compute на рендерPass layout по HTML/CSS, затем Prince пагинируетПрямая вёрстка, без pass интерпретации layout
p50 на рендер~250–800 мс wall-clock (сеть + рендер)~3–8 мс (сеть + рендер)
Детерминизм выводаВысокий (Prince зрелый)Байт-идентичный (тот же JSON → те же байты)

Если вы читаете эти две колонки как «универсальный HTML-принтер» vs «целенаправленно построенный рендерер документов», вы уже поняли архитектурное решение. Всё остальное (латентность, стоимость, даже списки функций) — ниже по течению этого единственного выбора.

Налог Prince

Prince хорош. Также делает работу, в которой большинство workflow счёт/чек/этикетка не нуждаются: реализовать CSS Paged Media — правила переноса страниц, бегущие headers, сноски, перекрёстные ссылки, генерируемый контент — для произвольного HTML, который пользователь может бросить.

Эта универсальность имеет runtime-стоимость. Чтобы пагинировать произвольный HTML, движок должен:

  1. Распарсить и валидировать HTML
  2. Разрешить CSS-каскад (потенциально с собственными расширениями Prince)
  3. Построить дерево рендера
  4. Запустить multi-pass layout (особенно для таблиц через страницы или балансирующих столбцов)
  5. Разрешить перекрёстные ссылки между страницами
  6. Эмитировать PDF-объекты

Большинство этих pass-ей — стоимость принятия HTML как входа. Если ваш вход уже структурированные данные (а почти всегда так — ваш счёт существует как JSON-объект до того, как вы оборачиваете его в HTML), вы платите за эти pass-ы compute и латентностью на каждом рендере, и они не добавляют ценности выводу.

gPdf полностью пропускает шаг интерпретации layout. JSON DocumentRequest уже структурно специфицирует layout страницы — { pages: [{ size, elements: [...] }] }. Renderer верстает элементы, пагинирует таблицы/списки детерминистично и эмитирует PDF. Никакого CSS-каскада для разрешения, никакого float-layout для вычисления, никакого pass разрешения перекрёстных ссылок.

Результат: тот же одностраничный счёт, занимающий ~300 мс на DocRaptor, занимает ~3 мс на gPdf. Мы быстрее не потому, что написали более быстрый Prince — мы быстрее потому, что не делаем большинства того, что делает Prince.

«Слишком дёшево, чтобы быть правдой» — это реальное возражение в закупках

Адресуем это напрямую, потому что всплывает в каждом B2B-звонке продаж.

«$5/месяц за 100K рендеров. DocRaptor — $89. Anvil — $0,10/PDF (то есть $10.000 при том же объёме). Что с вами не так?»

Три честные причины, по которым мы можем взимать это:

1. Мы не запускаем браузер

DocRaptor амортизирует Prince-инфраструктуру между клиентами. gPdf амортизирует один Cloudflare Worker, что стоит около $0,50/миллион запросов на Workers Bundled. С JSON-формой входа наш renderer берёт около 1,5 мс CPU на рендер. Накиньте 50% маржи и вы всё ещё в диапазоне центов-за-тысячу-рендеров. Арифметика — это цена.

2. Мы не запускаем control plane

Никаких асинхронных job-ов, callback-ов, очереди retry, хранилища документов, UI ссылок предпросмотра, multi-tenant БД. Каждый рендер — единственный round-trip к stateless-функции и обратно. Это удаляет всю поверхность ops, которую большинство компаний «PDF API» бюджетируют — что также является поверхностью, оправдывающей их цену.

3. Модель самоотбирается из workload-ов, на которых мы потеряли бы деньги

Если ваш документ действительно нуждается в HTML-в-PDF (60-страничный юридический договор, сложный CSS-Grid отчёт), вы отскочите от JSON-модели в первый час и пойдёте в DocRaptor всё равно. Нам не нужно защитно ценить эти workload-ы, потому что они саморутятся. Нужно только ценить длинный, но узкий хвост workload-ов «структурированные-данные-в-документ», где стоимость на рендер действительно крошечная.

Вместе: $5/100K — не loss-leader, это реальная себестоимость плюс маржа. Можем держать её там бесконечно, потому что базовый compute действительно настолько дёшев, когда вы не отгружаете браузер.

Где DocRaptor — правильный выбор

Стараемся не писать корыстные сравнения. Случаи, где DocRaptor реально побеждает:

  • Ваш вход — HTML, который вы не контролируете полностью. Отчёты, генерируемые пользователями, шаблоны третьих сторон, Markdown-из-CMS-рендерится-в-HTML. Не хотите писать JSON-mapper для произвольных входов.
  • Нужны функции CSS Paged Media, поддерживаемые Prince. Бегущие headers/footers по главам, сложный reflow сносок, именованные селекторы страниц, генерируемые оглавления, индексы. gPdf имеет структурированные эквиваленты для общего подмножества, но если вы живёте в селекторах @page :left, Prince — ваш друг.
  • У вас контент-команда, пишущая HTML/CSS, а не JSON. Не навязывайте JSON-workflow авторинга не-инженерной команде. Они вас возненавидят.
  • Async + callbacks + хранилище документов как сервис. DocRaptor хранит сгенерированные PDF и даёт вам подписанные URL для доставки. gPdf строго stateless — ваш код хранит результат.

Если вы в любом из этих вёдер, оставайтесь на DocRaptor. Это правильный инструмент.

Где gPdf — правильный выбор

Зеркальное отражение:

  • Ваши входы уже структурированные данные (строки БД, JSON API payload-ы, сообщения очереди).
  • Латентность важна — интерактивные checkout-flow, печать этикеток в реальном времени, генерация выписок по запросу.
  • Вам важна байт-идентичная воспроизводимость для тестов / audit trail / хранения электронных счетов.
  • Вы чувствительны к стоимости при любом объёме выше нескольких тысяч рендеров/месяц.
  • Нужны штрих-коды (GS1-128, QR, Data Matrix, PDF417, Aztec, MaxiCode) с суб-миллиметровой точностью.
  • Нужен PDF/A (1b/2b/3b/4) или вложения Factur-X / ZUGFeRD для compliance — особенно актуально для российского ЭДО (электронного документооборота) с УПД в формате XML и для интеграции с европейскими партнёрами по EN 16931.
  • Вы предпочитаете не запускать pipeline JSON-в-HTML-в-PDF, когда можете запустить pipeline JSON-в-PDF.

Конкретное замечание для российских команд

В контексте российского ЭДО (электронного документооборота) — обязательного для счетов-фактур (УПД) с 2014, для маркированных товаров с 2019, и расширяющегося на B2B с 2024 — gPdf производит как печатную форму, так и может прикрепить XML-структуру через PDF/A-3:

curl -X POST https://gpdf.com/api/v1/e-invoice/render \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "document": { "pages": [{ "size": "a4", "elements": [...] }] },
    "einvoice": {
      "format": "factur-x",
      "profile": "BASIC",
      "xml": "<rsm:CrossIndustryInvoice>...</rsm:CrossIndustryInvoice>"
    }
  }' \
  --output schet-faktura.pdf

Без post-pass Ghostscript, без второго инструмента для прикрепления XML, без лотереи валидации между шагами. Байты вывода байт-идентичны между версиями движка, поэтому ваш hash хранения для 5-летнего фискального обязательства может оставаться стабильным.

Миграция механическая, не стратегическая

Распространённая забота: «Переход означает переписать все наши шаблоны». Обычно нет. Большинство шаблонов HTML-в-PDF — 20% layout (что один раз становится JSON-структурой) и 80% интерполяция данных (что точно одинаково независимо от того, что принимает renderer).

Практический путь:

  1. Выберите один тип документа для миграции. Начните с самого высокого объёма — самая большая экономия, самый малый радиус взрыва.
  2. Возьмите интерфейс данных HTML-шаблона (переменные, которые он интерполирует) и напишите небольшую функцию mapToDocumentRequest(data).
  3. Итерируйте против Playground, пока вывод не совпадёт.
  4. A/B в продакшене: маршрутизируйте 5% трафика на gPdf две недели. Diff PDF. Сравните счета.
  5. Двигайтесь вперёд или назад на основе данных, а не вибраций.

TL;DR

DocRaptorgPdf
Лучше дляHTML → PDF для произвольного контентаJSON → PDF для структурированных документов
Цена (100K страниц/месяц)$89$5
Рендер p50250–800 мс3–8 мс
Edge-deployed❌ централизованный✅ 300+ Cloudflare colos
Async + storage✅ включено❌ stateless по дизайну
PDF/A + Factur-X / ZUGFeRD⚠️ через расширения Prince✅ встроено

Если ваши документы — структурированные данные, замаскированные под HTML для renderer-а, вы платите за шаг трансляции, который не должен существовать. Попробуйте Playground — опишите один из ваших счетов в JSON, отрендерите в браузере менее чем за 5 мс, посмотрите, совпадает ли разрыв с вашей интуицией.