Comment générer un tableau HTML et un PDF avec Node et Google Puppeteer

Conoce la tierra.

Comprendre NodeJS en interne peut être un peu intimidant (je sais que c'était pour moi une fois). Node est un langage très puissant et il peut faire beaucoup de choses.

Aujourd'hui, je voulais découvrir la puissance de l'outil utilitaire intégré de Node appelé fs (système de fichiers)

Selon la documentation fs:

Le fsmodule fournit une API pour interagir avec le système de fichiers d'une manière étroitement modélisée autour des fonctions POSIX standard.

Ce qui est juste une façon élégante de dire que le système de fichiers est un moyen dans Node d'interagir avec les fichiers pour les opérations de lecture et d'écriture.

Maintenant, le système de fichiers est un énorme utilitaire dans NodeJS qui possède de nombreuses fonctionnalités sophistiquées. Dans cet article, cependant, je ne parlerai que de 3:

  • Obtenir des informations sur les fichiers: fs.statSync
  • Suppression d'un fichier: fs.unlinkSync
  • Ecrire des données dans un fichier: fs.writeFileSync

Une autre chose que nous aborderons dans cet article est Google Puppeteer qui est cet outil vraiment cool et astucieux créé par des gens géniaux chez Google.

Alors qu'est-ce que le marionnettiste? Eh bien, selon les documents, ils disent:

Puppeteer est une bibliothèque de nœuds qui fournit une API de haut niveau pour contrôler Chrome ou Chromium sans tête via le protocole DevTools. Il peut également être configuré pour utiliser Chrome ou Chrome complet (sans tête).

C'est donc fondamentalement un outil qui vous permet de faire toutes les choses intéressantes liées au navigateur sur le serveur. Par exemple, obtenir des captures d'écran d'un site Web, explorer des sites Web et générer du contenu de pré-rendu pour les applications d'une seule page. Vous pouvez même soumettre des formulaires via votre serveur NodeJS.

Encore une fois, le marionnettiste est un outil énorme, nous ne couvrirons donc qu'une petite mais très intéressante fonctionnalité de marionnettiste. Nous verrons comment générer un joli fichier PDF basé sur notre fichier de table HTML généré. Dans le processus, nous en apprendrons davantage sur puppeteer.launch () et en apprendrons un peu plus sur page () et pdf ().

Donc, pour donner à nouveau un bref aperçu, nous allons couvrir les choses:

  • Génération de talons (pour les factures) à l'aide d'un outil en ligne.
  • Création d'un tableau HTML avec un peu de style avec des données générées, à l'aide d'un script de nœud automatisé.
  • Apprendre à vérifier si un fichier existe ou ne pas utiliser fs.statSync
  • En savoir plus sur la suppression d'un fichier à l'aide de fs.unlinkSync
  • Apprendre à écrire un fichier à l'aide de fs.writeFileSync
  • Création d'un fichier PDF de ce fichier HTML généré à l'aide de Google marionnettiste
  • Les transformer en scripts npm, à utiliser plus tard? ?
Avant de commencer, vous trouverez également l'intégralité du code source du didacticiel, que tout le monde pourra suivre. Vous n'avez rien à écrire, mais vous devez écrire du code avec ce didacticiel. Cela s'avérera plus utile et vous comprendrez mieux. CODE SOURCE DU TUTORIEL

Avant de commencer, veuillez vous assurer qu'au moins les éléments suivants sont installés sur votre machine

  • Nœud version 8.11.2
  • Node Package Manager (NPM) version 6.9.0

Vous n'avez pas besoin de le faire, mais vous pouvez également regarder une vidéo d'introduction (ma première jamais réalisée) qui parle des bases de la lecture, de l'écriture et de la suppression d'un fichier dans NodeJS. Cela vous aidera à comprendre ce tutoriel. (Veuillez me faire part de vos commentaires). ?

Commençons

Étape 1:

Dans votre terminal, saisissez ce qui suit:

npm init -y

Cela initialisera un projet vide pour vous.

Étape 2:

Deuxièmement, dans le même dossier, créez un nouveau fichier appelé data.jsonet contenez des données simulées. Vous pouvez utiliser l'exemple JSON suivant.

Vous pouvez obtenir les données de stub JSON simulées à partir d' ici . Pour générer ces données, j'ai utilisé un outil génial appelé //mockaroo.com/ C'est un outil générateur de données en ligne.

Les données JSON avec lesquelles je vais avoir une structure comme celle-ci:

[ {}, {}, { "invoiceId": 1, "createdDate": "3/27/2018", "dueDate": "5/24/2019", "address": "28058 Hazelcrest Center", "companyName": "Eayo", "invoiceName": "Carbonated Water - Peach", "price": 376 }, { "invoiceId": 2, "createdDate": "6/14/2018", "dueDate": "11/14/2018", "address": "6205 Shopko Court", "companyName": "Ozu", "invoiceName": "Pasta - Fusili Tri - Coloured", "price": 285 }, {}, {} ]
Vous pouvez télécharger le tableau JSON complet pour ce didacticiel à partir d' ici .

Étape 3:

Ensuite, créez un nouveau fichier appelé buildPaths.js

const path = require('path'); const buildPaths = { buildPathHtml: path.resolve('./build.html'), buildPathPdf: path.resolve('./build.pdf') }; module.exports = buildPaths;

Donc, nous path.resolveallons prendre un chemin relatif et nous retourner le chemin absolu de ce répertoire particulier.

Donc path.resolve('./build.html');, par exemple, retournera quelque chose comme ceci:

$ C:\\Users\\Adeel\\Desktop\\articles\\tutorial\\build.html

Étape 4:

Dans le même dossier, créez un fichier appelé createTable.jset ajoutez le code suivant:

const fs = require('fs'); // JSON data const data = require('./data.json'); // Build paths const { buildPathHtml } = require('./buildPaths'); /** * Take an object which has the following model * @param {Object} item * @model * { * "invoiceId": `Number`, * "createdDate": `String`, * "dueDate": `String`, * "address": `String`, * "companyName": `String`, * "invoiceName": `String`, * "price": `Number`, * } * * @returns {String} */ const createRow = (item) => ` ${item.invoiceId}${item.invoiceName}${item.price}${item.createdDate}${item.dueDate}${item.address}${item.companyName} `; /** * @description Generates an `html` table with all the table rows * @param {String} rows * @returns {String} */ const createTable = (rows) => `  ${rows} 
Invoice IdInvoice NamePriceInvoice CreatedDue DateVendor AddressVendor Name
`; /** * @description Generate an `html` page with a populated table * @param {String} table * @returns {String} */ const createHtml = (table) => ` table { width: 100%; } tr { text-align: left; border: 1px solid black; } th, td { padding: 15px; } tr:nth-child(odd) { background: #CCC } tr:nth-child(even) { background: #FFF } .no-content { background-color: red; } ${table} `; /** * @description this method takes in a path as a string & returns true/false * as to if the specified file path exists in the system or not. * @param {String} filePath * @returns {Boolean} */ const doesFileExist = (filePath) => { try { fs.statSync(filePath); // get information of the specified file path. return true; } catch (error) { return false; } }; try { /* Check if the file for `html` build exists in system or not */ if (doesFileExist(buildPathHtml)) { console.log('Deleting old build file'); /* If the file exists delete the file from system */ fs.unlinkSync(buildPathHtml); } /* generate rows */ const rows = data.map(createRow).join(''); /* generate table */ const table = createTable(rows); /* generate html */ const html = createHtml(table); /* write the generated html to file */ fs.writeFileSync(buildPathHtml, html); console.log('Succesfully created an HTML table'); } catch (error) { console.log('Error generating table', error); }

I know that is a lot of code, but let’s divide it into chunks and start understanding it piece by piece.

Go to line 106 (github gist)

In our try/catch block we first check if the build file for HTML exists in the system or not. This is the path of the file where our NodeJS script will generate our HTML.

if (doesFileExist(buildPathHtml){} calls doesFileExist() method which simply returns true/false. For this we use

fs.statSync(filePath);

This method actually returns information about the file like the size of the file, when the file was created, and so on. However if we provide it an invalid file path, this method returns as a null error. Which we use here to our benefit and wrap the fs.statSync() method in a try/catch. If Node is successfully able to read the file in our try block, we return true — otherwise it throws an error which we get in our catch block and returns false.

If the file exists in the system we end up deleting the file using

fs.unlinkSync(filePath); // takes in a file path & deletes it

After deleting the file, we need to generate rows to put in the table.

Step 5:

So first we import data.json which we do at line 3 & then on line 115 we iterate each item using map(). You can read more about Array.prototype.map() here.

The map method takes a method createRow which takes in an object through each iteration and returns a string which has content like this:

"invoice idinvoice nameinvoice priceinvoice created dateinvoice due dateinvoice addressinvoice sender company name"
const row = data.map(createdRow).join('');

The join('') part is important here, because I want to concatenate all of my array into a string.

An almost similar principle is used for generating a table on line 117 & then the html table on line 119.

Step 6:

The important part is where we write to our file on line 121:

fs.writeFileSync(buildPathHtml, html); 

It takes in 2 parameters: one is the build path (string) and the html content (string) and generates a file (if not created; and if it is created, it overwrites the already existing file).

Une chose à noter ici, nous pourrions ne pas avoir besoin de l'étape 4, où nous vérifions si le fichier existe et s'il le fait, puis le supprimons. C'est parce que writeFileSync fait cela pour nous. Je viens d'ajouter cela dans le code à des fins d'apprentissage.

Étape 7:

Dans votre terminal, allez dans le chemin du dossier où vous avez le createTable.jset tapez

$ npm run ./createTable.js

Dès que vous exécutez ce script, il créera un nouveau fichier dans le même dossier appelé build.htmlVous pouvez ouvrir ce fichier dans votre navigateur et il ressemblera à quelque chose comme ça.

Cool non? Jusqu'ici tout va bien. ?

Vous pouvez également ajouter un npm scriptdans votre package.json comme ceci:

"scripts": { "build:table": "node ./createTable.js" },

De cette façon, au lieu d'écrire npm run ./createTable.js, vous pouvez simplement taper npm run build:table.

Ensuite: générer un PDF à partir du HTMLfichier généré .

Étape 8:

First things first we need to install a fancy tool, so go in your terminal in your application folder and type in

npm install puppeteer

Step 9:

In the same folder where you have files createTable.js , buildPaths.js & data.json, create a new file called createPdf.js and add content to it like below:

 const fs = require('fs'); const puppeteer = require('puppeteer'); // Build paths const { buildPathHtml, buildPathPdf } = require('./buildPaths'); const printPdf = async () => { console.log('Starting: Generating PDF Process, Kindly wait ..'); /** Launch a headleass browser */ const browser = await puppeteer.launch(); /* 1- Ccreate a newPage() object. It is created in default browser context. */ const page = await browser.newPage(); /* 2- Will open our generated `.html` file in the new Page instance. */ await page.goto(buildPathHtml, { waitUntil: 'networkidle0' }); /* 3- Take a snapshot of the PDF */ const pdf = await page.pdf({ format: 'A4', margin: { top: '20px', right: '20px', bottom: '20px', left: '20px' } }); /* 4- Cleanup: close browser. */ await browser.close(); console.log('Ending: Generating PDF Process'); return pdf; }; const init = async () => { try { const pdf = await printPdf(); fs.writeFileSync(buildPathPdf, pdf); console.log('Succesfully created an PDF table'); } catch (error) { console.log('Error generating PDF', error); } }; init();

As we did with createTable.js script, let’s break this down into chunks and start understanding this script step by step.

Let’s start with line 40: here we call a method init() which calls the method on line 30. Onething to focus on is that our init() method is an async method. Read more on this async function.

Tout d'abord dans la méthode init (), nous appelons la méthode printPdf () qui est à nouveau une méthode asynchrone, nous devons donc attendre sa réponse. La méthode printPdf () nous renvoie une instance PDF que nous écrivons ensuite dans un fichier à la ligne 33.

Alors, que fait la printPdf()méthode? Creusons profondément dedans.

const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto(buildPathHtml, { waitUntil: 'networkidle0' }); const pdf = await page.pdf({ format: 'A4', margin: { top: '20px', right: '20px', bottom: '20px', left: '20px'} }); await browser.close(); return pdf;

Nous lançons d'abord une instance de navigateur headless en utilisant puppeteer en procédant comme suit:

await puppeteer.launch(); // this returns us headless browser

que nous utilisons ensuite pour ouvrir une page Web:

await browser.newPage(); // open a blank page in headless browser

Une fois que nous avons une page vierge ouverte, nous pouvons accéder à une page. Puisque notre page Web est localement dans notre système, nous

page.goto(buildPathHtml, { waitUntil: 'networkidle0' });

Ceci waitUntil: 'networkidle0;est important, car cela dit au marionnettiste d'attendre 500 / ms jusqu'à ce qu'il n'y ait plus de connexions réseau.

Remarque: C'est pourquoi nous avons utilisé path.resolve () pour obtenir des chemins absolus, car pour ouvrir la page Web avec puppeteer, nous avons besoin d'un chemin absolu.

After we have a web page opened in the headless browser on the server, we save that page as a pdf:

await page.pdf({ });

As soon as we have a pdf version of the web page, we need to close the browser instance opened by puppeteer to save resources by doing this:

await browser.close();

& then we return the pdf saved, which we then write to the file.

Step 10:

In your terminal type

$ npm ./createPdf.js

Note: Before running the above script, ensure that you the build.html file generated by createTable.js script. This ensures we always have the build.html prior to running the createPdf.js script. In your package,json do the following.

"scripts": { "build:table": "node ./createTable.js", "prebuild:pdf": "npm run build:table", "build:pdf": "node ./createPdf.js" },

Now if you run $ npm run build:pdf it will execute the createTable.js script first and then createPdf.js script. You can read more on NPM scripts on their official docs.

When you run

$ npm run build:pdf

It will run and create a build.pdf which will look like this:

Et voilà, nous avons terminé.

Vous avez appris ce qui suit:

  • Comment vérifier si un fichier existe / informations sur le fichier tet (dans Node)
  • Comment supprimer un fichier dans Node
  • Comment écrire dans un fichier
  • Comment utiliser Google Puppeteer pour générer un fichier PDF

Bon apprentissage, j'aimerais avoir votre avis sur cet article. Vous pouvez me joindre sur twitterainsi que.