Генерация PDF в веб-приложении: шаблоны, версии и выгрузка

Как спроектировать генерацию PDF: снимок данных, версии шаблонов, длинные таблицы, шрифты, очередь, безопасное скачивание и проверка.

Автор: , CEO и основатель, 404gen.

Генерация PDF в веб-приложении — это формирование документа из зафиксированных данных и определённой версии шаблона. Для рабочего процесса важны не только аккуратные страницы, но и воспроизводимость: какой заказ использован, когда создан файл, кто имеет доступ и что произойдёт при повторном запросе. Кнопка «скачать» не должна выдавать каждый раз другое содержание под одним номером.

Разберём требования для личного кабинета, CRM, ERP и SaaS: шаблоны, длинные таблицы, шрифты, очередь, хранение и визуальная приёмка. Речь о программной выдаче документов. Юридическое значение, подписи и обязательные реквизиты определяют отдельно; сам формат PDF не делает документ подписанным или юридически достаточным.

Печать страницы и документ из данных

Печать текущего экрана удобна для личной копии отчёта. Но экран может содержать раскрытую часть списка, временные фильтры и скрытые из-за прокрутки строки. Если бизнес ожидает полный документ с устойчивым номером, нужно формировать его из согласованного набора данных, а не случайного состояния браузера пользователя.

Сначала определите тип результата: одноразовый отчёт по фильтрам, документ конкретного заказа или архивная версия после утверждения. Для отчёта допустим новый расчёт при каждом запуске с указанием времени. Для утверждённого документа обычно требуется сохранить содержание версии. Одинаковая кнопка может скрывать совершенно разные требования к истории.

В учебном примере сервис готовит коммерческое предложение из 40 строк. Менеджер меняет состав и выпускает новую редакцию. Получатель должен видеть, к какой редакции относится скачанный файл, а старая ссылка — сохранять прежнее содержание либо ясно сообщать о замене по принятому процессу. Молчаливая подмена файла делает согласование неоднозначным.

Контракт данных до начала вёрстки

Шаблон получает подготовленные значения: стороны, строки, единицы, цены, итог и примечания. Не стоит заставлять его самостоятельно искать актуальный договор или вычислять скидку иначе, чем основное приложение. Бизнес-расчёт должен иметь единый источник, иначе HTML-экран и PDF начнут расходиться.

Для каждой величины определите формат и смысл: число, валюта, календарная дата, момент времени. Пустое значение, ноль и отсутствие применимости различаются. Если реквизит обязателен по правилам процесса, генерация должна остановиться до выпуска или явно отправить документ на уточнение, а не вставить случайный прочерк.

ЧастьЧто зафиксироватьПример ошибки
Исходные данныеВерсия заказа и выбранные строкиСостав изменился во время рендера
ШаблонНомер редакции и языкСтарая копия выглядит по-новому
РасчётГотовые суммы и округленияPDF считает иначе интерфейса
РесурсыШрифты и изображенияКириллица заменена квадратами
РезультатИдентификатор, время, доступЧужой файл открыт по ссылке

Снимок данных создаётся в понятный момент: запрос пользователя, утверждение или переход документа в определённое состояние. Если во время формирования менеджер продолжает редактировать заказ, файл всё равно должен соответствовать одной версии. Смешение заголовка от старой версии и строк от новой недопустимо, даже если итог выглядит правдоподобно.

Выбор способа формирования

HTML и печатные стили подходят, когда команда уже работает с веб-вёрсткой и документ похож на страницу с таблицами. Серверный браузер формирует PDF по отдельному маршруту или шаблону. При этом экранные стили не стоит переносить без адаптации: печатная страница имеет фиксированные границы и другой способ разбиения содержимого.

В Puppeteer метод Page.pdf работает с печатными CSS-правилами; параметры и поведение описаны в официальной документации Page.pdf. Конкретные настройки выбирают под документ и проверяют на используемой версии библиотеки, а не копируют из случайного примера.

Библиотека прямой сборки PDF может быть уместна для строго заданных форм, штрихкодов и контролируемых координат. Её цена — собственная работа с переносами, таблицами и шрифтами. Редактируемый офисный шаблон удобен, если макетом управляют сотрудники через установленный процесс, но конвертация также требует проверки итоговых страниц.

Выбирайте способ по сложности документа, числу шаблонов, языкам, нагрузке и тому, кто будет вносить изменения. Нет смысла внедрять тяжёлый конструктор ради одной короткой формы. Но и набор абсолютных координат быстро становится хрупким, если примечания и строки имеют непредсказуемую длину.

Шаблоны и управление редакциями

Шаблон должен иметь собственную версию независимо от версии заказа. Изменение логотипа, формулировки или структуры таблицы влияет на результат генерации. В карточке файла храните обе ссылки: редакция данных и редакция шаблона. Это позволяет объяснить, почему два документа одного типа выглядят по-разному.

Для архивного документа храните сформированный файл и метаданные. Возможность повторно собрать его из исходников полезна, но не всегда гарантирует побайтовое совпадение после обновления рендера, шрифтов или системных зависимостей. Поэтому «у нас есть данные, значит файл всегда восстановим» — недостаточное основание для отказа от архива результата.

Подготовку новой версии выполняйте на тестовом наборе. Сравнивайте не только короткий образец, но и длинные названия, пустые поля, несколько страниц и разные языки. Затем выпускайте шаблон с датой начала применения. Уже сформированные документы не должны автоматически перерисовываться из-за обновления оформления.

Если пользователи меняют текстовые блоки, ограничьте доступные возможности и проверяйте содержимое. Произвольный HTML с внешними ресурсами усложняет безопасность и воспроизводимость. Для большинства документов достаточно структурированных полей и ограниченного форматирования, которое проходит проверку до публикации шаблона.

Длинные таблицы и разрывы страниц

Документ из трёх строк редко показывает настоящие проблемы. Нужны примеры с десятками строк, длинным названием и примечанием на несколько абзацев. Решите, повторяется ли заголовок таблицы, можно ли разрывать строку и где располагаются итог и подписи. Эти правила задают до визуальной полировки.

Модель печатной страницы, поля и разрывы описаны в спецификации W3C Paged media. Поддержка конкретных возможностей зависит от рендера. Поэтому наличие CSS-свойства в стандарте не заменяет проверку в выбранном инструменте и его версии.

Не пытайтесь всегда удерживать всю таблицу на одной странице. При большом объёме это создаст пустые полосы или слишком мелкий шрифт. Лучше разрешить предсказуемый перенос, повторять заголовки и сохранять логические группы. Если строка сама длиннее страницы, нужен отдельный сценарий, а не бесконечный запрет разрыва.

Блок итога не должен отрываться от своего обозначения, а подпись — перекрывать строки. Проверьте крайние случаи, когда перед итогом остаётся одна строка или несколько пикселей. Для документов с приложениями полезны явные разделы, номера страниц и понятное продолжение таблицы, чтобы распечатанная копия читалась без интерфейса.

Шрифты, кириллица и изображения

Серверный рендер не обязан иметь шрифты с компьютера дизайнера. Поставляйте нужные файлы вместе с приложением в рамках лицензии и проверяйте фактическую загрузку. Подмена гарнитуры меняет ширину строк и число страниц, даже если все буквы формально отображаются.

Проверьте кириллицу, латиницу, цифры, знак рубля, неразрывные пробелы и длинные идентификаторы. Табличные суммы должны сохранять читаемость, а текст — по возможности выделяться и копироваться корректно. PDF, собранный целиком из скриншота, может выглядеть аккуратно, но неудобен для поиска и дальнейшей работы.

Изображения загружайте из контролируемых источников с понятным временем ожидания. Если логотип не получен, генерация должна следовать определённому правилу, а не случайно выпускать то полный, то пустой документ. Для воспроизводимости важна версия ресурса, а не только меняющийся адрес «текущий логотип».

Не увеличивайте маленький растр до огромного размера ради чёткости. Подготовьте подходящий источник и проверьте результат при печати или обычном масштабе просмотра. Слишком тяжёлые картинки раздувают файл и очередь рендера. Оптимизация должна сохранять читаемость подписей и схем, а не только уменьшать число байтов.

Очередь формирования и состояние задачи

Короткую форму можно формировать в пределах обычного запроса, если нагрузка и время предсказуемы. Для больших отчётов удобнее задача: принята, выполняется, готова или завершилась ошибкой. Пользователь получает идентификатор и может вернуться к результату после закрытия вкладки, не создавая документ заново.

Ключ повторного запроса должен учитывать исходную версию, шаблон и параметры. Двойное нажатие может вернуть ту же задачу. Новый набор фильтров или новая редакция должны создавать другой результат. Если ключ строится только по пользователю, один отчёт способен подменить другой; если его нет совсем, очередь заполнится дублями.

При временной ошибке задача повторяется ограниченно с сохранением причины. Не нужно бесконечно запускать тяжёлый рендер на некорректных данных. Разделите проблемы источника, отсутствующий ресурс, сбой инструмента и недостаток памяти. Пользователь видит понятный итог, а оператор — технические сведения без чувствительных данных.

Ограничьте параллельность и объём одного задания. Большой отчёт одного клиента не должен занимать все ресурсы и останавливать обычные документы других. Для первой версии полезнее явный предел и предложение уточнить фильтр, чем обещание любого объёма, которое заканчивается случайным падением сервиса.

Хранение и безопасное скачивание

Доступ проверяется при запросе результата, а не только при создании. Пользователь может потерять роль или сменить организацию после генерации. Непредсказуемый адрес файла не заменяет авторизацию. Если используется временная ссылка, определите срок, область действия и способ получения новой после истечения.

Разделяйте файлы разных организаций по идентификаторам и правам. Параметр в URL нельзя считать подтверждением принадлежности. Сервер загружает метаданные документа, проверяет разрешение и только затем выдаёт содержимое. То же касается фоновой задачи: она должна работать в зафиксированном контексте, а не под текущим случайным пользователем процесса.

Срок хранения зависит от назначения документа и принятой политики. В интерфейсе полезно различать архивный документ и временный отчёт, который можно сформировать снова. Удаление временного файла не должно ломать историю бизнес-операции: метаданные и причина недоступности могут сохраняться отдельно от содержимого.

Имя скачиваемого файла должно быть читаемым и безопасно сформированным из разрешённых значений. Не позволяйте произвольному вводу менять пути хранения или заголовки ответа. В журнале достаточно идентификатора задачи, версии и результата; полное содержимое документов и реквизитов обычно не нужно для диагностики каждой генерации.

Внешние данные и изоляция рендера

Рендерер обрабатывает недоверенные строки как данные, а не как команды или произвольную разметку. Название товара с угловыми скобками должно печататься текстом. Если шаблон допускает ссылки и изображения, проверяйте их отдельно. Автоматический доступ рендера к любому адресу создаёт нежелательные зависимости и возможность обращения к внутренним ресурсам.

Для серверного браузера предусмотрите изолированное окружение с ограниченными полномочиями, временем работы и сетевыми источниками. Ему не нужны административные ключи всей системы. Сбой одного документа должен завершаться ошибкой задачи, а не менять основной процесс приложения или раскрывать содержимое соседних документов.

Фиксируйте версии инструмента и шрифтов в сборке. После обновления прогоняйте контрольный набор, особенно длинные таблицы и нестандартные символы. Ускорение за счёт пропуска ожидания ресурсов допустимо только после доказательства, что результат остаётся полным. Ранний скриншот пустого блока нельзя считать оптимизацией.

Если документ включает пользовательские файлы, не смешивайте их бесконтрольно с HTML-шаблоном. Для вложений нужен отдельный процесс проверки и понятный способ добавления. Объединение страниц также проверяется визуально: ориентация, масштаб и порядок могут измениться даже при успешной технической операции.

Проверка результата: данные и внешний вид

Автоматическая проверка может подтвердить наличие страниц, извлечённого текста, ожидаемых сумм и метаданных. Она полезна, но не видит всех наложений и некрасивых переносов. Поэтому контрольные документы нужно открыть или отрендерить в изображения и просмотреть каждую страницу, особенно границы таблиц и финальные блоки.

Соберите набор: пустой допустимый отчёт, один элемент, много строк, максимальное примечание, длинное название без пробелов, несколько валют при поддержке и отсутствующая картинка. Для каждого известны ожидаемые данные и допустимое поведение. Нельзя считать пустой файл правильным только потому, что библиотека вернула успешный код.

Проверьте повтор: тот же запрос, новая версия данных, новая версия шаблона и потеря ответа после создания. Старый документ остаётся доступен по своему идентификатору, а новый имеет понятную связь. При отменённом праве скачивание должно отказать даже по ранее сохранённой прямой ссылке, если она не является специально выданным ограниченным доступом.

Замерьте время от запроса до готовности, размер файла и память на обычном и предельном объёме. Покажите разницу между ожиданием очереди и самим рендером. Это помогает выбрать реальное улучшение: уменьшить ресурсы, пересмотреть шаблон, ограничить объём или добавить отдельные исполнители, а не вслепую наращивать сервер.

Пилот и поддержка шаблонов

Начните с одного типа документа и согласованного примера данных. Зафиксируйте владельца содержания, владельца оформления и того, кто принимает итог. Разработчик может обеспечить правильный вывод поля, но не определить за компанию обязательную формулировку. Без владельца шаблон быстро обрастает противоречащими друг другу пожеланиями.

Выпускайте изменения через контрольные образцы и понятную дату применения. Для срочной правки сохраняйте причину и набор документов, к которым она относится. Не заменяйте архивные файлы молча. Если требуется перевыпуск, он должен быть виден пользователю и связан с прежней версией.

Следите за ошибками по шаблонам, источникам и объёму, а не только за общим числом скачиваний. Скачивание не подтверждает, что файл прочитан, принят или использован. Для бизнес-процесса могут понадобиться отдельные события согласования, которые нельзя выводить из самого факта выдачи PDF.

После стабильного пилота добавляйте другие документы, переиспользуя контракт задач и доступа. Содержание и печатная компоновка остаются отдельными для каждого типа. Универсальный генератор полезен там, где действительно общие механизмы; одинаковая форма для всех документов часто ухудшает читаемость.

Один контрольный документ для согласования

Перед разработкой соберите обезличенный образец с пояснениями: какие поля обязательны, какие блоки условны и где допускается перенос. Отметьте различия между макетом и настоящими правилами. Например, подпись внизу первой страницы может быть художественным решением, которое не работает для таблицы на пять страниц.

Назначьте критерии приёмки содержимого отдельно от оформления. Первая проверка подтверждает номера, суммы, версии и состав; вторая — читаемость, поля, переносы и отсутствие наложений. Обе нужны, потому что красивый документ может содержать неверные данные, а правильные данные — оказаться обрезанными на печати.

Сохранённый контрольный набор становится основой проверки следующих изменений. Если добавлен новый язык или поле, расширьте примеры и повторите просмотр затронутых страниц. Не требуется вручную открывать все исторические документы, но крайние случаи должны оставаться частью выпуска каждого шаблона.

Частые вопросы

Можно ли просто печатать экран браузера?

Для личной копии текущего вида — да, если это соответствует задаче. Для устойчивого документа с полным составом и версией лучше отдельный контракт данных и печатный шаблон. Состояние раскрытых блоков на экране не должно случайно определять официальный состав результата.

Нужно ли хранить готовые PDF?

Для архивных версий обычно важно сохранять сам результат и метаданные. Повторный рендер после обновления зависимостей может отличаться. Временные отчёты можно хранить иначе, но пользователь должен понимать срок доступности и возможность повторного формирования.

Почему PDF отличается от макета?

Частые причины — другой шрифт, неготовые ресурсы, печатные стили и длинные данные. Проверять нужно в реальном серверном рендере на контрольных примерах. Успешная генерация и совпадение числа страниц сами по себе не подтверждают качество компоновки.

Делает ли PDF документ подписанным?

Нет. Формат файла не равен электронной подписи и не устанавливает юридическое значение. Если процесс требует подписания или обязательных реквизитов, это отдельные требования с собственными средствами проверки и согласования.

Как избежать дублей при повторном нажатии?

Использовать устойчивый ключ задачи, связанный с версией данных, шаблоном и параметрами. Повтор возвращает существующий результат или состояние работы. Новая редакция создаётся явно и получает собственный идентификатор.

Связанные материалы

Рядом с генерацией документов полезно рассмотреть выгрузку Excel и работу с файлами в сервисе. Общими остаются права, очередь и история, а формат результата требует собственной проверки.

На странице интеграций и автоматизации можно обсудить выпуск документов из CRM или ERP. Для первичного разбора нужны обезличенный пример, крайние объёмы и правило, в какой момент содержание становится зафиксированной версией.

404gen — креативное digital-агентство полного цикла, работаем удалённо по всей России.

Телефон: +7 993 729-59-59 (пн–пт, 10:00–19:00 МСК). WhatsApp: +7 913 141-20-96. Telegram: @aporkulevich. Почта: ap@404gen.ru.