Πώς να δημιουργήσετε έναν πίνακα HTML και ένα PDF με το Node & Google Puppeteer

Conoce la tierra.

Η κατανόηση του NodeJS εσωτερικά μπορεί να είναι λίγο τρομακτική (ξέρω ότι ήταν για μένα μια φορά). Ο κόμβος είναι μια πολύ ισχυρή γλώσσα και μπορεί να κάνει πολλά πράγματα.

Σήμερα ήθελα να αποκαλύψω τη δύναμη του ενσωματωμένου βοηθητικού εργαλείου του Node που ονομάζεται fs (σύστημα αρχείων)

Σύμφωνα με τα έγγραφα fs:

Η fsενότητα παρέχει ένα API για αλληλεπίδραση με το σύστημα αρχείων με τρόπο στενά μοντελοποιημένο γύρω από τις τυπικές λειτουργίες POSIX.

Που είναι απλώς ένας φανταχτερός τρόπος να πούμε ότι το σύστημα αρχείων είναι ένας τρόπος στο Node να αλληλεπιδρά με αρχεία τόσο για τις διαδικασίες ανάγνωσης όσο και για εγγραφή.

Τώρα το σύστημα αρχείων είναι ένα τεράστιο βοηθητικό πρόγραμμα στο NodeJS που έχει πολλά φανταχτερά χαρακτηριστικά. Σε αυτό το άρθρο, ωστόσο, θα συζητήσω μόνο 3:

  • Λήψη πληροφοριών αρχείου: fs.statSync
  • Διαγραφή αρχείου: fs.unlinkSync
  • Σύνταξη δεδομένων σε ένα αρχείο: fs.writeFileSync

Ένα άλλο πράγμα που θα καλύψουμε σε αυτό το άρθρο είναι το Google Puppeteer που είναι αυτό το πραγματικά δροσερό, λεπτό εργαλείο που δημιουργήθηκε από μερικούς φοβερούς λαούς στο Google.

Τι είναι λοιπόν ο μαριονέτας; Σύμφωνα με τα έγγραφα, λένε:

Το Puppeteer είναι μια βιβλιοθήκη κόμβων που παρέχει API υψηλού επιπέδου για τον έλεγχο κεφαλής χωρίς Chrome ή Chromium μέσω του πρωτοκόλλου DevTools. Μπορεί επίσης να ρυθμιστεί ώστε να χρησιμοποιεί πλήρες (χωρίς κεφαλή) Chrome ή Chromium.

Είναι βασικά ένα εργαλείο που σας επιτρέπει να κάνετε όλα τα δροσερά πράγματα που σχετίζονται με το πρόγραμμα περιήγησης στον διακομιστή. Όπως η λήψη στιγμιότυπων οθόνης ενός ιστότοπου, η ανίχνευση ιστότοπων και η δημιουργία περιεχομένου προ-απόδοσης για εφαρμογές μιας σελίδας. Μπορείτε ακόμη και να υποβάλετε φόρμες μέσω του διακομιστή NodeJS.

Και πάλι το puppeteer είναι ένα τεράστιο εργαλείο, οπότε θα καλύψουμε μόνο ένα μικρό αλλά πολύ δροσερό χαρακτηριστικό του puppeteer. Θα εξετάσουμε πώς να δημιουργήσουμε ένα ωραίο αρχείο PDF με βάση το αρχείο πίνακα HTML που δημιουργήσαμε. Στη διαδικασία θα μάθουμε για το puppeteer.launch () και θα κατανοήσουμε λίγο για τη σελίδα () & pdf ().

Για να δώσουμε και πάλι μια σύντομη επισκόπηση, πράγματα που θα καλύψουμε:

  • Δημιουργία stub δεδομένων (για τιμολόγια) χρησιμοποιώντας ένα ηλεκτρονικό εργαλείο.
  • Δημιουργία πίνακα HTML με λίγο στυλ με παραγόμενα δεδομένα σε αυτόν, χρησιμοποιώντας ένα αυτοματοποιημένο σενάριο κόμβου.
  • Μάθετε σχετικά με τον έλεγχο εάν υπάρχει ένα αρχείο ή δεν χρησιμοποιεί το fs.statSync
  • Μάθετε σχετικά με τη διαγραφή ενός αρχείου χρησιμοποιώντας το fs.unlinkSync
  • Μάθετε σχετικά με τη σύνταξη ενός αρχείου χρησιμοποιώντας το fs.writeFileSync
  • Δημιουργία αρχείου PDF αυτού του αρχείου HTML που δημιουργήθηκε χρησιμοποιώντας το Google puppeteer
  • Κατασκευάζοντάς τα σε σενάρια npm, για χρήση αργότερα; ;
Επίσης πριν ξεκινήσουμε εδώ είναι ολόκληρος ο πηγαίος κώδικας του σεμιναρίου, για να ακολουθήσει ο καθένας. Δεν χρειάζεται να γράψετε τίποτα, αλλά πρέπει να γράψετε κώδικα μαζί με αυτό το σεμινάριο. Αυτό θα αποδειχθεί πιο χρήσιμο και θα καταλάβετε περισσότερα. ΚΩΔΙΚΟΣ ΠΗΓΗΣΗΣ ΤΟΜΕΑΡΙΚΟΥ

Πριν ξεκινήσουμε, βεβαιωθείτε ότι έχετε εγκαταστήσει τουλάχιστον τα ακόλουθα στο μηχάνημά σας

  • Έκδοση κόμβου 8.11.2
  • Node Package Manager (NPM) έκδοση 6.9.0

Δεν χρειάζεται, αλλά μπορείτε επίσης να παρακολουθήσετε ένα εισαγωγικό βίντεο (το πρώτο μου φτιάχτηκε) που μιλά για τα βασικά στην ανάγνωση, τη συγγραφή και τη διαγραφή ενός αρχείου στο NodeJS. Αυτό θα σας βοηθήσει να κατανοήσετε αυτό το σεμινάριο. (Παρακαλώ δώστε μου σχόλια). ;

Ας αρχίσουμε

Βήμα 1:

Στο τερματικό σας πληκτρολογήστε τα εξής:

npm init -y

Αυτό θα ξεκινήσει ένα κενό έργο για εσάς.

Βήμα 2:

Δεύτερον, στον ίδιο φάκελο, δημιουργήστε ένα νέο αρχείο που ονομάζεται data.jsonκαι έχετε μερικά πλαστά δεδομένα σε αυτό. Μπορείτε να χρησιμοποιήσετε το ακόλουθο δείγμα JSON.

Μπορείτε να λάβετε τα πλαστά δεδομένα JSON stub από εδώ . Για τη δημιουργία αυτών των δεδομένων, έχω χρησιμοποιήσει ένα φοβερό εργαλείο που ονομάζεται //mockaroo.com/ Είναι ένα εργαλείο δημιουργίας δεδομένων στο διαδίκτυο.

Τα δεδομένα JSON που χρησιμοποιώ έχουν μια δομή όπως αυτή:

[ {}, {}, { "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 }, {}, {} ]
Μπορείτε να κατεβάσετε τον πλήρη πίνακα JSON για αυτό το σεμινάριο από εδώ .

Βήμα 3:

Στη συνέχεια δημιουργήστε ένα νέο αρχείο που ονομάζεται buildPaths.js

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

Έτσι path.resolveθα ακολουθήσει μια σχετική διαδρομή και θα μας επιστρέψει την απόλυτη διαδρομή αυτού του συγκεκριμένου καταλόγου.

Έτσι path.resolve('./build.html');, για παράδειγμα, θα επιστρέψω κάτι τέτοιο:

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

Βήμα 4:

Στον ίδιο φάκελο δημιουργήστε ένα αρχείο που ονομάζεται createTable.jsκαι προσθέστε τον ακόλουθο κώδικα:

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 Id Invoice Name Price Invoice Created Due Date Vendor Address Vendor 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).

Ένα πράγμα που πρέπει να σημειωθεί εδώ ίσως να μην χρειαζόμαστε το Βήμα 4, όπου ελέγξουμε εάν υπάρχει το αρχείο και αν το διαγράφει. Αυτό συμβαίνει επειδή το writeFileSync το κάνει αυτό για εμάς. Μόλις το πρόσθεσα στον κώδικα για μαθησιακούς σκοπούς.

Βήμα 7:

Στο τερματικό σας, μεταβείτε στη διαδρομή φακέλου όπου έχετε createTable.jsκαι τον τύπο

$ npm run ./createTable.js

Μόλις εκτελέσετε αυτό το σενάριο, θα δημιουργήσει ένα νέο αρχείο στον ίδιο φάκελο που ονομάζεται build.htmlΜπορείτε να ανοίξετε αυτό το αρχείο στο πρόγραμμα περιήγησής σας και θα μοιάζει με αυτό.

Ωραίο, σωστά; Μέχρι εδώ καλά. ;

Επίσης, μπορείτε να προσθέσετε ένα npm scriptστο πακέτο σας. Json ως εξής:

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

Με αυτόν τον τρόπο αντί να γράφετε npm run ./createTable.js, μπορείτε απλά να πληκτρολογήσετε npm run build:table.

Επόμενο: δημιουργία PDF από το δημιουργημένο HTMLαρχείο.

Βήμα 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.

Πρώτα στη μέθοδο init () ονομάζουμε τη μέθοδο printPdf () που είναι και πάλι μια μέθοδος ασύγχρονης, οπότε πρέπει να περιμένουμε την απάντησή της. Η μέθοδος printPdf () μας επιστρέφει μια παρουσία PDF που στη συνέχεια γράφουμε σε ένα αρχείο στη γραμμή 33.

Τι κάνει λοιπόν η printPdf()μέθοδος; Ας σκάψουμε βαθιά σε αυτό.

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;

Αρχικά ξεκινάμε μια παρουσία χωρίς πρόγραμμα περιήγησης χρησιμοποιώντας puppeteer κάνοντας τα εξής:

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

το οποίο στη συνέχεια χρησιμοποιούμε για να ανοίξουμε μια ιστοσελίδα:

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

Μόλις ανοίξουμε μια κενή σελίδα, μπορούμε να πλοηγηθούμε σε μια σελίδα. Δεδομένου ότι η ιστοσελίδα μας είναι τοπικά στο σύστημά μας, απλά

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

Εδώ waitUntil: 'networkidle0;είναι σημαντικό, γιατί λέει στον κουκλοπαίκτη να περιμένει 500 / ms έως ότου δεν υπάρχουν πλέον συνδέσεις δικτύου.

Σημείωση: Γι 'αυτό χρησιμοποιήσαμε το path.resolve () για να πάρουμε απόλυτες διαδρομές, γιατί για να ανοίξουμε την ιστοσελίδα με το puppeteer, χρειαζόμαστε μια απόλυτη διαδρομή.

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:

Και αυτό είναι, τελειώσαμε.

Έχετε μάθει τα εξής:

  • Πώς να ελέγξετε εάν υπάρχει αρχείο / πληροφορίες αρχείου tet (στον κόμβο)
  • Πώς να διαγράψετε ένα αρχείο στον κόμβο
  • Πώς να γράψετε σε ένα αρχείο
  • Πώς να χρησιμοποιήσετε το Google Puppeteer για να δημιουργήσετε ένα αρχείο PDF

Καλή μάθηση, θα ήθελα πολύ να ακούσω τις σκέψεις σας για αυτό το άρθρο. Μπορείτε να επικοινωνήσετε μαζί μου στο twitterεπισης.