Генерация PDF отчётов на TypeScript с библиотекой pdf-lib
В современной веб-разработке часто возникает необходимость создавать документы в формате PDF — от простых чеков и квитанций до сложных аналитических отчётов с графиками. TypeScript, как строго типизированное расширение JavaScript, предоставляет отличные возможности для работы с PDF. Среди множества библиотек выделяется pdf-lib — мощный, полностью клиентский инструмент, не требующий серверных зависимостей.
В этой статье мы подробно разберём, как использовать pdf-lib для генерации PDF-отчётов на TypeScript, включая установку, базовые операции и продвинутые приёмы.
Что такое pdf-lib?
pdf-lib — это библиотека с открытым исходным кодом, написанная на TypeScript, которая позволяет создавать и редактировать PDF-документы прямо в браузере или в среде Node.js. Её главные преимущества:
- Полная поддержка TypeScript (все типы включены)
- Работа без внешних зависимостей (нет необходимости в Puppeteer или wkhtmltopdf)
- Возможность работы с существующими PDF (слияние, вставка страниц)
- Поддержка кириллицы и любых шрифтов
- Встраивание изображений (PNG, JPG, SVG)
- Создание форм и аннотаций
Установка и настройка
Установка производится стандартным менеджером пакетов:
npm install pdf-lib
# или
yarn add pdf-lib
Для работы с TypeScript дополнительных действий не требуется — все типы уже включены в пакет.
Базовый пример: создание простого отчёта
Рассмотрим создание минимального PDF-документа с заголовком и текстом:
import { PDFDocument, StandardFonts, rgb } from 'pdf-lib';
async function createSimpleReport() {
// 1. Создаём новый PDF-документ
const pdfDoc = await PDFDocument.create();
// 2. Добавляем страницу (формат A4: 595.28 x 841.89 пунктов)
const page = pdfDoc.addPage([595.28, 841.89]);
// 3. Подключаем стандартный шрифт
const font = await pdfDoc.embedFont(StandardFonts.Helvetica);
// 4. Рисуем заголовок
page.drawText('Отчёт о продажах за Q1 2025', {
x: 50,
y: 800,
size: 24,
font: font,
color: rgb(0, 0.2, 0.6),
});
// 5. Рисуем основной текст
page.drawText('Общая выручка: 1 234 567 руб.', {
x: 50,
y: 760,
size: 14,
font: font,
color: rgb(0, 0, 0),
});
// 6. Сохраняем документ в Uint8Array
const pdfBytes = await pdfDoc.save();
return pdfBytes;
}
Работа с таблицами и данными
Для создания табличных отчётов потребуется немного больше логики. Вот пример генерации таблицы с данными:
import { PDFDocument, StandardFonts, rgb } from 'pdf-lib';
interface SaleRecord {
product: string;
quantity: number;
price: number;
}
async function createTableReport(data: SaleRecord[]) {
const pdfDoc = await PDFDocument.create();
const page = pdfDoc.addPage([595.28, 841.89]);
const font = await pdfDoc.embedFont(StandardFonts.Helvetica);
const boldFont = await pdfDoc.embedFont(StandardFonts.HelveticaBold);
const startX = 50;
let startY = 800;
const rowHeight = 25;
const colWidths = [200, 100, 100, 100]; // Наименование, Кол-во, Цена, Сумма
// Заголовок таблицы
const headers = ['Наименование', 'Количество', 'Цена', 'Сумма'];
page.drawText(headers[0], { x: startX, y: startY, size: 12, font: boldFont });
page.drawText(headers[1], { x: startX + colWidths[0], y: startY, size: 12, font: boldFont });
page.drawText(headers[2], { x: startX + colWidths[0] + colWidths[1], y: startY, size: 12, font: boldFont });
page.drawText(headers[3], { x: startX + colWidths[0] + colWidths[1] + colWidths[2], y: startY, size: 12, font: boldFont });
startY -= rowHeight;
// Строки данных
for (const record of data) {
const total = record.quantity * record.price;
page.drawText(record.product, { x: startX, y: startY, size: 11, font });
page.drawText(String(record.quantity), { x: startX + colWidths[0], y: startY, size: 11, font });
page.draw