Найти тему

Генерация pdf-документа на стороне клиента с помощью библиотеки @react-pdf/renderer

Оглавление

Моё приложение на гитхабе:
https://github.com/SeverInvest/html-to-pdf

Задача: из шаблона генерировать pdf-документ (для примера: акт выполненных работ)

Дизайн сделал самый простенький
1) фрейм, в котором показывается сгенерированный документ
2) кнопка сохранения документа на локальный диск

Во фрейме реализован скролл (из коробки).
Во фрейме реализован скролл (из коробки).

Использована библиотека @react-pdf/renderer

Ссылка на документацию разработчика: https://react-pdf.org/

Из интересного:

Для создания шаблона документа можно использовать только ограниченное количество тегов. Причем все теги - это специальные теги библиотеки (чем то отдаленно напоминают стандартные теги html)

Вот их перечень (https://react-pdf.org/components#document):

  1. Document - этот компонент представляет сам PDF-документ. Он должен быть корневым в вашей структуре древовидных элементов и ни при каких обстоятельствах не должен использоваться как дочерний элемент другого компонента react-pdf. Кроме того, в нем должны быть только дочерние элементы типа <Page />.
  2. Page - представляет отдельную страницу внутри PDF-документов или их подмножество, если используется функция переноса. <Document /> A может содержать столько страниц, сколько вы хотите, но гарантирует, что страница не будет отображаться внутри какого-либо компонента, кроме Document .
  3. View - наиболее фундаментальный компонент для построения пользовательского интерфейса, предназначенный для вложения в другие представления и может иметь от 0 до многих дочерних элементов. Именно в нем я прописывал все стили для текстов.
  4. Image - компонент React для отображения сетевых или локальных (только для узла) изображений в формате JPG или PNG, а также строк изображений в кодировке base64.
  5. Text - компонент React для отображения текста. Текст поддерживает вложение других текстовых или ссылочных компонентов для создания встроенного стиля.
  6. Link - компонент React для отображения гиперссылки. Ссылки могут быть вложены внутрь текстового компонента или находиться внутри любого другого допустимого примитива.
  7. Note - компонент React для отображения аннотации примечания внутри документа.
  8. Canvas - компонент React для свободного рисования любого содержимого на странице.
  9. PDFViewer - программа просмотра PDF в формате Iframe для документов, сгенерированных на стороне клиента.
  10. PDFDownloadLin - привязанный тег, позволяющий генерировать и загружать PDF-документы "на лету".
  11. BlobProvide - Простой и декларативный способ получения данных blob-объекта документа без отображения их на экране.

Все компоненты - это style-components. В React они используются довольно часто и прочитать про них можно тут https://styled-components.com/
Но, если Вы привыкли, что при использовании библиотеки styled-components - стилизуете каждый компонент (привязка стилей к компоненту). То здесь стили привязываются к классам и классы можно использовать во многих компонентах. А также комбинировать их.

Проще показать:

import { StyleSheet } from '@react-pdf/renderer';
export default function Act() {
const styles = StyleSheet.create({
page: {
marginTop: 20,
backgroundColor: '#fff',
fontFamily: 'Inter',
fontSize: 10,
fontWeight: 400,
lineHeight: 1.5,
},
});
return (
...
);
};

Применение стилей в самом компоненте:
<Page size="A4" style={styles.page}>
Можно комбинировать с дополнительными стилями:
<Page size="A4" style={[styles.page, {padding: 10}]}>
Или сразу прописывать стили в компоненте:
<View style={{ marginLeft: 30, textAlign: "left", marginTop: 10, marginRight: 30 }}>

Проблема со кириллическими шрифтами. По умолчанию их там нет. Нужно устанавливать самостоятельно. Поддерживается ttf (другие не проверял)
Так импортируется шрифт на страницу. Каждый шрифт нужно импортировать отдельно.
import FontInterRegular from '../../vendor/fonts/Inter-Regular.ttf';
Регистрация шрифта уже внутри функции:
Font.register({ family: 'Inter', src: FontInterRegular });
Применение шрифта непосредственно в стилях
fontFamily: 'Inter',

Со стилями тоже интересно. Их очень мало. И для создания таблиц только флексы. Гридов нет.

Вот их перечень:

Valid CSS properties:

Flexbox

  • alignContent
  • alignItems
  • alignSelf
  • flex
  • flexDirection
  • flexWrap
  • flexFlow
  • flexGrow
  • flexShrink
  • flexBasis
  • justifyContent

Layout

  • bottom
  • display
  • left
  • position
  • right
  • top
  • overflow
  • zIndex

Dimension

  • height
  • maxHeight
  • maxWidth
  • minHeight
  • minWidth
  • width

Color

  • backgroundColor
  • color
  • opacity

Text

  • fontSize
  • fontFamily
  • fontStyle
  • fontWeight
  • letterSpacing
  • lineHeight
  • maxLines
  • textAlign
  • textDecoration
  • textDecorationColor
  • textDecorationStyle
  • textIndent
  • textOverflow
  • textTransform

Sizing/positioning

  • object-fit
  • object-position

Margin/padding

  • margin
  • marginHorizontal
  • marginVertical
  • marginTop
  • marginRight
  • marginBottom
  • marginLeft
  • padding
  • paddingHorizontal
  • paddingVertical
  • paddingTop
  • paddingRight
  • paddingBottom
  • paddingLeft

Transformations

  • transform:rotate
  • transform:scale
  • transform:scaleX
  • transform:scaleY
  • transform:translate
  • transform:translateX
  • transform:translateY
  • transform:skew
  • transform:skewX
  • transform:skewY
  • transform:matrix
  • transformOrigin

Borders

  • border
  • borderColor
  • borderStyle
  • borderWidth
  • borderTop
  • borderTopColor
  • borderTopStyle
  • borderTopWidth
  • borderRight
  • borderRightColor
  • borderRightStyle
  • borderRightWidth
  • borderBottom
  • borderBottomColor
  • borderBottomStyle
  • borderBottomWidth
  • borderLeft
  • borderLeftColor
  • borderLeftStyle
  • borderLeftWidth
  • borderTopLeftRadius
  • borderTopRightRadius
  • borderBottomRightRadius
  • borderBottomLeftRadius

И всё. Кончились. Как хочешь, так и твори)))

Само приложение App:

Компоненты можно кастомизировать с помощью классов
Компоненты можно кастомизировать с помощью классов

Из интересного:
есть хук - usePDF, основная функция которого генерация на лету pdf-документа в момент инициализации.
функция обновления (setInstance) - не изменяет документ, а только обновляет. Запускается без аргументов:
setInstance();

P. S. И ещё пришлось дополнительно установить такую библиотеку @babel/plugin-proposal-private-property-in-object

Резюме: если нужно сделать быстро - то это неплохое решение)