Le matériel, dont nous publions la traduction aujourd'hui, est consacré à la création de fichiers PDF dynamiques utilisant le code HTML comme modÚle. à savoir, nous parlerons de la façon de créer une simple facture pour le paiement de certains biens ou services, dont les données dynamiques incluses sont extraites de l'état de l'application React. La base de l'application React a été créée à l'aide de create-react-app, la partie serveur du projet est basée sur Node.js et le framework Express a été utilisé dans son développement.

L'auteur de ce document note qu'il a préparé une
vidéo qui montre le développement du projet. Si vous décidez de regarder la vidéo et de lire l'article, il est recommandé de le faire. Commencez par parcourir l'article, puis activez la vidéo et recréez le systÚme que vous envisagez. AprÚs cela, lisez simplement l'article.
Création de projet
Créez un répertoire de projet et accédez-y:
mkdir pdfGenerator && cd pdfGenerator
Créez une nouvelle application React:
create-react-app client
AprÚs avoir terminé la création de l'application, accédez au répertoire que vous venez de créer et installez les dépendances:
cd client && npm i -S axios file-saver
Créez un serveur Express. Pour ce faire, créez le dossier du
server
dans le répertoire du projet et accédez-y. Dans celui-ci, créez le fichier
index.js
et démarrez l'initialisation du projet:
mkdir server && cd server && touch index.js && npm init
Ici, pour former
package.json
, appuyez simplement sur
Enter
plusieurs fois. AprÚs cela, exécutez la commande suivante pour ajouter les dépendances nécessaires à la partie serveur du projet:
npm i -S express body-parser cors html-pdf
Maintenant, dans le fichier
client/package.json
, au-dessus de la section de description des dépendances, ajoutez ce qui suit:
"proxy": "http://localhost:5000/"
Cela vous aidera Ă travailler avec le serveur local Ă partir du code client.
Vous devez maintenant ouvrir deux fenĂȘtres du terminal.
Dans la premiĂšre fenĂȘtre, accĂ©dez au rĂ©pertoire
client
et exécutez la commande suivante:
npm start
Dans la deuxiĂšme fenĂȘtre, accĂ©dez au dossier du
server
et exécutez la commande suivante:
nodemon index.js
Configuration initiale du client
La partie client de notre projet sera trĂšs simple.
Pour commencer, dans le
src/App.js
partie client de l'application, nous importons les dépendances dans le code:
import axios from 'axios'; import { saveAs } from 'file-saver';
AprÚs cela, en haut de la description du composant, initialisez l'état:
state = { name: 'Adrian', receiptId: 0, price1: 0, price2: 0, }
Supprimons le balisage JSX standard créé dans le modÚle d'application à l'aide de
create-react-app
et renvoyé par la méthode
render()
. Insérez-y les éléments suivants:
<div className="App"> <input type="text" placeholder="Name" name="name" onChange {this.handleChange}/> <input type="number" placeholder="Receipt ID" name="receiptId" onChange={this.handleChange}/> <input type="number" placeholder="Price 1" name="price1" onChange={this.handleChange}/> <input type="number" placeholder="Price 2" name="price2" onChange={this.handleChange}/> <button onClick={this.createAndDownloadPdf}>Download PDF</button></div>
Créons la méthode
handleChange
, qui sera responsable de la mise à jour des données d'état de l'application liées aux champs d'entrée:
handleChange = ({ target: { value, name }}) => this.setState({ [name]: value })
Nous pouvons maintenant passer à la tùche de création d'un fichier PDF. Cette partie, qui est résolue au moyen du client, consiste à créer une demande POST au serveur. La demande envoie l'état de l'application:
createAndDownloadPdf = () => { axios.post('/create-pdf', this.state) }
Avant de continuer à travailler sur le cÎté client du projet, nous devons configurer les itinéraires sur le serveur. Cela permettra au serveur de recevoir des données du client, de générer un fichier PDF et de retransférer ce fichier au client.
Configuration initiale du serveur
La partie serveur du projet ne comprendra que deux routes. Un est nécessaire pour créer des PDF. La seconde sert à envoyer des fichiers au client.
Tout d'abord, importez les dépendances dans le fichier
index.js
:
const express = require('express'); const bodyParser = require('body-parser'); const pdf = require('html-pdf'); const cors = require('cors');
Nous initialisons l'application Express et configurons le port:
const app = express(); const port = process.env.PORT || 5000;
Configurez l'analyseur de requĂȘtes. Ce dont nous avons besoin sera disponible en tant que
req.body
de
req.body
. Nous allons également configurer CORS afin que notre erreur de
Cross-Origin Request Blocked
nâinterfĂšre pas avec notre travail:
app.use(cors()); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json());
AprÚs cela, démarrez le serveur:
app.listen(port, () => console.log(`Listening on port ${port}`));
Nous pouvons maintenant nous attaquer au code responsable de la création des PDF.
Créer un modÚle HTML pour les PDF
Nous avons besoin d'un modĂšle HTML Ă utiliser lors de la crĂ©ation de fichiers PDF. En crĂ©ant un tel modĂšle, des possibilitĂ©s infinies s'ouvrent devant nous. Tout ce qui peut ĂȘtre créé en utilisant du HTML pur et du CSS peut ĂȘtre reprĂ©sentĂ© sous forme de fichier PDF. CrĂ©ez le rĂ©pertoire des
documents
dans le dossier du
server
, accédez-y et créez-y le fichier
index.js
:
mkdir documents && cd documents && touch index.js
à partir de ce fichier, nous exportons une fonction flÚche qui renverra tout le code HTML nécessaire. Lorsque vous appelez cette fonction, vous pouvez utiliser les paramÚtres, que nous décrirons également ici.
module.exports = ({ name, price1, price2, receiptId }) => { ... }
Ici, je vais vous donner
un exemple de modÚle HTML, et vous le copiez simplement dans votre projet. Mais vous pouvez bien sûr créer votre propre modÚle.
index.js
code
index.js
du dossier
server/documents
au formulaire suivant:
module.exports = ({ name, price1, price2, receiptId }) => { const today = new Date(); return ` <!doctype html> <html> <head> <meta charset="utf-8"> <title>PDF Result Template</title> <style> .invoice-box { max-width: 800px; margin: auto; padding: 30px; border: 1px solid #eee; box-shadow: 0 0 10px rgba(0, 0, 0, .15); font-size: 16px; line-height: 24px; font-family: 'Helvetica Neue', 'Helvetica', color: #555; } .margin-top { margin-top: 50px; } .justify-center { text-align: center; } .invoice-box table { width: 100%; line-height: inherit; text-align: left; } .invoice-box table td { padding: 5px; vertical-align: top; } .invoice-box table tr td:nth-child(2) { text-align: right; } .invoice-box table tr.top table td { padding-bottom: 20px; } .invoice-box table tr.top table td.title { font-size: 45px; line-height: 45px; color: #333; } .invoice-box table tr.information table td { padding-bottom: 40px; } .invoice-box table tr.heading td { background: #eee; border-bottom: 1px solid #ddd; font-weight: bold; } .invoice-box table tr.details td { padding-bottom: 20px; } .invoice-box table tr.item td { border-bottom: 1px solid #eee; } .invoice-box table tr.item.last td { border-bottom: none; } .invoice-box table tr.total td:nth-child(2) { border-top: 2px solid #eee; font-weight: bold; } @media only screen and (max-width: 600px) { .invoice-box table tr.top table td { width: 100%; display: block; text-align: center; } .invoice-box table tr.information table td { width: 100%; display: block; text-align: center; } } </style> </head> <body> <div class="invoice-box"> <table cellpadding="0" cellspacing="0"> <tr class="top"> <td colspan="2"> <table> <tr> <td class="title"><img src="https://i2.wp.com/cleverlogos.co/wp-content/uploads/2018/05/reciepthound_1.jpg?fit=800%2C600&ssl=1" style="width:100%; max-width:156px;"></td> <td> Datum: ${`${today.getDate()}. ${today.getMonth() + 1}. ${today.getFullYear()}.`} </td> </tr> </table> </td> </tr> <tr class="information"> <td colspan="2"> <table> <tr> <td> Customer name: ${name} </td> <td> Receipt number: ${receiptId} </td> </tr> </table> </td> </tr> <tr class="heading"> <td>Bought items:</td> <td>Price</td> </tr> <tr class="item"> <td>First item:</td> <td>${price1}$</td> </tr> <tr class="item"> <td>Second item:</td> <td>${price2}$</td> </tr> </table> <br /> <h1 class="justify-center">Total price: ${parseInt(price1) + parseInt(price2)}$</h1> </div> </body> </html> `; };
server/index.js
incluons ce fichier dans le fichier
server/index.js
:
const pdfTemplate = require('./documents');
Créer des PDF
Rappelons que sur le serveur, nous allons créer deux routes. La route POST sera chargée de recevoir les données du client et de créer un fichier PDF. La route GET sera utilisée pour envoyer le fichier fini au client.
â itinĂ©raire create-pdf
Dans la route POST
create-pdf
, nous utiliserons la commande
pdf.create()
, faisant référence à l'objet importé du module
html-pdf
.
En tant que premier paramÚtre de la méthode
pdf.create()
, un modÚle HTML est utilisé, ainsi que les données reçues du client.
Pour renvoyer
pdf.create()
, nous appelons la méthode
toFile()
, en lui passant le nom que nous voulons attribuer au document PDF, ainsi que la fonction de rappel de flÚche. Cette fonction, en cas d'erreur, exécutera la commande
res.send(Promise.reject())
.
res.send(Promise.resolve())
tout se passe bien, elle exécutera la commande
res.send(Promise.resolve())
.
app.post('/create-pdf', (req, res) => { pdf.create(pdfTemplate(req.body), {}).toFile('result.pdf', (err) => { if(err) { res.send(Promise.reject()); } res.send(Promise.resolve()); }); });
RouteFetch-pdf Route
Dans le mĂȘme temps, nous crĂ©erons un itinĂ©raire qui sera utilisĂ© aprĂšs que, Ă la demande du client, un fichier PDF ait Ă©tĂ© créé avec succĂšs. Ici, nous prenons simplement le document fini et l'envoyons au client en utilisant
res.sendFile()
:
app.get('/fetch-pdf', (req, res) => { res.sendFile(`${__dirname}/result.pdf`) })
Fonction client createAndDownloadPdf
Nous pouvons maintenant revenir au code client et continuer Ă travailler sur la fonction
createAndDownloadPdf
. Ici, nous faisons une requĂȘte POST au serveur en utilisant le module
axios
. Maintenant, cette fonction ressemble Ă ceci:
createAndDownloadPdf = () => { axios.post('/create-pdf', this.state) }
Si aprĂšs avoir exĂ©cutĂ© une requĂȘte POST sur le serveur, un document PDF a Ă©tĂ© créé, nous devons exĂ©cuter une requĂȘte GET, en rĂ©ponse Ă laquelle le serveur enverra le document fini au client.
Pour implémenter ce schéma de comportement, nous, aprÚs avoir appelé
axios.post()
, appelons.
then()
. Cela nous permet de le faire en rĂ©ponse Ă la demande POST du client, nous renvoyons une promesse du serveur qui peut ĂȘtre rĂ©solue ou rejetĂ©e avec succĂšs.
Nous complétons la fonction avec le code suivant:
.then(() => axios.get('/fetch-pdf', { responseType: 'blob' })) .then(( res) => {})
Ici, vous pouvez faire attention au fait que
blob
utilisé comme
responseType
. Avant d'aller plus loin, parlons de ce que c'est.
Objets blob
Blob est un objet immuable reprĂ©sentant des donnĂ©es brutes. Ces objets sont souvent utilisĂ©s pour travailler avec des donnĂ©es qui peuvent ne pas ĂȘtre au format JavaScript natif. Ces objets sont des sĂ©quences d'octets qui stockent, par exemple, des donnĂ©es de fichier. Il peut sembler que l'objet
Blob
stocke un lien vers un fichier, mais en fait ce n'est pas le cas. Ces objets stockent des donnĂ©es avec lesquelles vous pouvez travailler. Par exemple, ils peuvent ĂȘtre enregistrĂ©s dans des fichiers.
AchĂšvement du projet
Maintenant que nous savons ce que sont les objets
Blob
, nous pouvons utiliser un autre appel
.then()
pour y
res.data
nouvel objet
Blob
, basé sur res.data. Lors de la création de cet objet, nous transmettrons un paramÚtre à son constructeur, indiquant que les données que l'objet va stocker sont de type
application/pdf
. AprÚs cela, nous pouvons utiliser la méthode
saveAs()
, qui a été importée du module
file-saver
, et enregistrer les données dans un fichier. Par conséquent, le code de la méthode
createAndDowndloadPdf
ressemblera à celui illustré ci-dessous:
createAndDownloadPdf = () => { axios.post('/create-pdf', this.state) .then(() => axios.get('fetch-pdf', { responseType: 'blob' })) .then((res) => { const pdfBlob = new Blob([res.data], { type: 'application/pdf' }); saveAs(pdfBlob, 'newPdf.pdf'); }) }
Voici Ă quoi ressemble l'interface du navigateur.
Application dans le navigateurAprÚs avoir rempli les champs et cliqué sur le bouton
Download PDF
, les données sont transférées vers le serveur et un document PDF est téléchargé depuis celui-ci.
TĂ©lĂ©chargez le PDFEt voici le document PDF lui-mĂȘme.
PDF généré par logicielRésumé
Nous avons examiné un mécanisme qui vous permet de créer par programme des fichiers PDF.
Voici un référentiel GitHub avec le code du projet. Nous espérons que les idées que vous avez rencontrées dans ce document trouveront une application dans votre développement.
Chers lecteurs! Comment résoudriez-vous le problÚme de la création de fichiers PDF par programme à l'aide de Node.js?