Создание PDF с помощью Node JS и React


Введение

Возможно, вы слышали термин «рассылка», связанный с Microsoft Word. Для тех, кто не знает, это в основном заключается в создании стандартного документа и оставлении в нем некоторых полей, в которых будут происходить те или иные изменения автоматизированным способом. Идея этого поста очень похожа. С помощью Node JS, а точнее с помощью фреймворка express и библиотек html-pdf-node, ejs и React, мы построим на практике генератор PDF.

Шаг 1

Проект будет иметь следующую структуру файлов. Сначала создайте только папку «app». Остальные будут создаваться в течение этого урока.

app/
├─ backend/
│  ├─ node_modules/
│  ├─ public/
│  ├─ package.json
│  ├─ package-lock.json
│  ├─ src/
│  │  ├─ example.ejs
│  │  ├─ index.js
│  │  ├─ services/
│  │  │  ├─ createPDF.js
│  ├─ .gitignore/
├─ frontend/
│  ├─ node_modules/
│  ├─ public/
│  ├─ package.json
│  ├─ package-lock.json
│  ├─ src/
│  │  ├─ App.jsx
│  │  ├─ index.css
│  │  ├─ main.jsx
│  ├─ .gitignore
│  ├─ index.html
│  ├─ vite.config.js

Войдите в полноэкранный режим Выход из полноэкранного режима

Мы начнем с Back-end, установив некоторые пакеты, необходимые для проекта. После этого создайте папку «backend». Мы начнем с файла «package.json», который будет содержать несколько важных сведений о нашем приложении. Откройте терминал в этой папке и выполните приведенную ниже команду:

npm init -y

Далее мы установим остальные пакеты, которые будем использовать в этом проекте:

npm i nodemon cors express ejs html-pdf-node

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

  • nodemon: поможет запустить наш сервер Node JS в процессе разработки. Его замечательная особенность заключается в том, что он автоматически перезапускает наш сервер по мере внесения изменений или ошибок.
  • cors: используется для добавления HTTP-заголовков, которые позволяют приложениям из разных источников взаимодействовать друг с другом.
  • express: это позволит создать сервер, на котором будут построены наши API.
  • ejs: поможет создавать HTML-страницы с использованием javascript прямым способом.
  • html-pdf-node: поможет преобразовать html-файл в pdf.

Теперь, для Front-end, мы будем использовать React JS с помощью ViteJS. Для этого необходимо выполнить следующую команду внутри папки «app». После запуска появится несколько вариантов установки, выберите «React», а затем снова «React».

npm create vite@latest frontend --template react

Выполните две следующие команды для установки зависимостей Front-end.

cd frontend

Шаг 2

Завершив шаг 1, мы начнем разработку логики в папке services с создания файла createPDF.js, следуя структуре, рассмотренной в начале.
В приведенном ниже коде через комментарии будут кратко описаны причины и то, что делается в каждой части:

const html_to_pdf = require("html-pdf-node");
const ejs = require("ejs");

async function createPDF(file, ejsVariables) {
  let html;
  // A constante url irá ajudar caso a gente queira utilizar imagens que estão disponíveis na pasta public do backend no nosso arquivo ejs
  const url = process.env.URL || "http://localhost:3001";

  ejs.renderFile(
    // Nome do arquivo ejs que será transformado
    file,
    // Objeto contendo as váriaveis para substituir no arquivo ".ejs"
    { ...ejsVariables, url },
    (err, content) => {
      if (err) {
        throw new Error(
          "Can't render the file, probably some variables are missing"
        );
      }
      // Vamos armazenar o html após a conversão na variável html
      html = { content };
    }
  );

  // Algumas opções para o pdf que irá ser gerado. Caso precise de algo mais específico, favor consultar a documentação: https://github.com/mrafiqk/html-pdf-node
  const options = { format: "A4" };

  // Aqui será gerado o buffer do nosso pdf
  const pdfBuffer = await html_to_pdf.generatePdf(html, options);

  return pdfBuffer;
}

module.exports = {
  createPDF,
};

Войдите в полноэкранный режим Выход из полноэкранного режима

После этого нам нужно будет создать экземпляр нашего сервера и API для отправки этого документа пользователю. Для этого просто скопируйте приведенное ниже содержимое и вставьте его в файл «index.js» в папке «src»:

const express = require("express");
const cors = require("cors");
const { createPDF } = require("./services/createPDF");
const path = require("path");

const PORT = process.env.PORT || 3001;

const app = express();

app.use(cors());
app.use(express.json());
// Pasta onde ficarão os arquivos estáticos, como fotos
app.use(express.static("public"));

app.post("/generate-pdf", async (req, res) => {
  const FILE_PATH = path.join(__dirname, "/example.ejs");
  const pdfBuffer = await createPDF(FILE_PATH, { ...req.body });

  // Iremos setar o header com o tipo de arquivo enviado
  res.setHeader("Content-Type", "application/pdf");
  // Por fim, enviar o arquivo
  res.end(pdfBuffer);
});

app.listen(PORT, () => console.log(`Server is running on port ${PORT}`));

Войдите в полноэкранный режим Выход из полноэкранного режима

Шаг 3

С этого момента мы можем разработать наш файл «example.ejs», который будет содержать структуру HTML и переменные, которые будут заполняться автоматически. Стоит отметить, что этот шаг потребует от вас проведения тестов по мере разработки страницы, поскольку PDF не всегда будет создаваться так же, как HTML.
Еще одним важным моментом является то, что переменные, используемые в файле, всегда должны быть отправлены на Back-end. Если у вас есть необязательное поле, отправьте этому свойству значение «null» или что-то подобное.

<!-- example.ejs -->
<!DOCTYPE html>
<html lang="pt">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>PDF Generator</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }
      h1,
      h3,
      p {
        margin: 10px 0 10px 10px;
      }
    </style>
  </head>
  <body>
    <img style="width: 100%" src="<%= url %>/images.png" />
    <h1>Dono do documento: <%= name %></h1>
    <h3>Objetivo do documento:</h3>
    <p style="font-size: 24px">Esse documento tem como objetivo gerar um PDF</p>
    <% if (references) { %>
    <h3>Referências:</h3>
    <p><%= references.join(", ") + '.' %></p>
    <% } %>
  </body>
</html>

Войдите в полноэкранный режим Выход из полноэкранного режима

Теперь наш Back-end почти готов. Нам все еще нужно настроить nodemon для запуска нашего сервера. Для этого добавьте приведенную ниже строку в часть scripts файла package.json.

  "scripts": {
    "dev": "nodemon src/index.js"
  },
Войдите в полноэкранный режим Выход из полноэкранного режима

Если вы хотите протестировать его, вы уже можете запустить сервер с помощью приведенной ниже команды внутри папки «backend»:

npm run dev

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

Шаг 4

На этом этапе мы создадим простую структуру в папке «frontend» для выполнения запроса. Просто скопируйте и вставьте приведенные ниже коды в нужные файлы (вы можете заменить уже имеющиеся файлы).

В файле «App.jsx»:

export default function App() {
  // Informações utilizadas nas variáveis dos arquivos .ejs
  const data = {
    name: "SEU NOME",
    references: ["https://ejs.co/", "https://github.com/mrafiqk/html-pdf-node"],
  };

  const generatePdf = (e) => {
    e.preventDefault();

    fetch("http://localhost:3001/generate-pdf", {
      headers: {
        "Content-type": "application/json; charset=UTF-8",
      },
      method: "POST",
      body: JSON.stringify(data),
    })
      .then((res) => res.blob())
      .then((blob) => {
        // Criando uma url de acesso as informações
        const url = window.URL.createObjectURL(blob);
        const a = document.createElement("a");
        a.href = url;
        a.download = "example.pdf";
        // Necessário para funcionar em todos os browsers
        document.body.appendChild(a);
        a.click();
        a.remove();
      });
  };

  return (
    <div className="App">
      <form onSubmit={generatePdf}>
        <button type="submit">Download Here!</button>
      </form>
    </div>
  );
}

Войдите в полноэкранный режим Выход из полноэкранного режима

В файле «main.tsx

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import "./index.css";

ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

Войдите в полноэкранный режим Выход из полноэкранного режима

В файле index.css


:root {
  font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
  font-size: 16px;
  line-height: 24px;
  font-weight: 400;
}

body {
  margin: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  min-width: 100vw;
  min-height: 100vh;
  background-color: #8187f5;
}

button {
  border-radius: 8px;
  border: 1px solid transparent;
  padding: 0.6em 1.2em;
  font-size: 1em;
  font-weight: 500;
  font-family: inherit;
  background-color: #1a1a1a;
  cursor: pointer;
  transition: border-color 0.25s;
}
button:hover {
  border-color: #646cff;
}
button:focus,
button:focus-visible {
  outline: 4px auto -webkit-focus-ring-color;
}

@media (prefers-color-scheme: light) {
  :root {
    color: #213547;
    background-color: #ffffff;
  }
  a:hover {
    color: #747bff;
  }
  button {
    background-color: #f9f9f9;
  }
}

Войдите в полноэкранный режим Выход из полноэкранного режима

Готово! С этого момента вы можете запустить Front-end с помощью команды ниже, а также Back-end, если вы не запустили его в предыдущих шагах. Зайдите в браузер по URL-адресу, сгенерированному в терминале после выполнения команды. Вы увидите кнопку загрузки, при нажатии которой будет загружен PDF-файл.
Наблюдение заключается в том, что изображение не появится, потому что его нет на вашем компьютере. Я оставлю код приложения в конце этого сообщения, чтобы вы могли взять его из папки backend/public и сохранить в том же месте в своем коде, если захотите протестировать его.

npm run dev

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

Код Git Hub: Ссылка

Оцените статью
devanswers.ru
Добавить комментарий