PDF létrehozása HTML-ből a Node segítségével.js pedig Bábjátékos
a Teljes Stack Fejlesztő a RisingStack
ebben A cikkben megmutatom, hogyan lehet létrehozni egy PDF dokumentum egy erősen stílusú Reagálni oldal használata Csomópont.js, Puppeteer, headless Chrome & Docker.
háttér: Néhány hónappal ezelőtt a RisingStack egyik ügyfele arra kért minket, hogy fejlesszünk ki egy olyan funkciót, ahol a felhasználó PDF formátumban kérheti a React oldalt. Ez az oldal alapvetően egy jelentés / eredmény az adatvizualizációval rendelkező betegek számára, amely sok SVG-t tartalmaz. Továbbá, volt néhány speciális kérések, hogy manipulálják az elrendezés, valamint, hogy néhány átrendezése a HTML elemek. Tehát a PDF-nek az eredeti React oldalhoz képest eltérő stílusúnak és kiegészítésnek kell lennie.
mivel a hozzárendelés egy kicsit bonyolultabb volt, mint amit egyszerű CSS szabályokkal meg lehetett volna oldani, először megvizsgáltuk a lehetséges implementációkat. Lényegében 3 fő megoldást találtunk. Ez a blogpost végigvezeti Önt ezeken a lehetőségeken és a végső megvalósításokon.
egy személyes megjegyzés, mielőtt elkezdenénk: ez elég egy szóváltás, így csat fel!
Tartalomjegyzék:
- Ügyféloldal vagy Háttéroldal?
- 1. Lehetőség: Képernyőkép készítése a DOM-ból
- 2. lehetőség: csak PDF könyvtárat használjon
- végleges 3.lehetőség: bábos, fej nélküli Chrome csomóponttal.js
- stílusmanipuláció
- Fájl küldése az ügyfélnek, majd mentse el
- a bábos segítségével Docker
- 3 + 1 opció: CSS nyomtatási szabályok
- összefoglaló
kliens oldal vagy szerver oldal?
lehetséges PDF fájl létrehozása mind az ügyféloldalon, mind a szerver oldalon. Azonban valószínűleg több értelme van, hogy hagyja, hogy a backend kezelje, mivel nem akarja használni az összes olyan erőforrást, amelyet a felhasználó böngészője kínálhat.
még így is, továbbra is megoldásokat mutatok mindkét módszerhez.
1. Lehetőség: Készítsen képernyőképet a DOM
első látásra, ez a megoldás a legegyszerűbbnek tűnt, igaznak bizonyult, de saját korlátai vannak. Ha nincsenek speciális igényei, mint például a választható vagy kereshető szöveg a PDF-ben, akkor ez egy jó és egyszerű módja annak, hogy létrehozzon egyet.
Ez a módszer egyszerű: hozzon létre egy képernyőképet az oldalról, majd tegye egy PDF fájlba. Elég egyszerű. Ehhez a megközelítéshez két csomagot használtunk:
Html2canvas, hogy képernyőképet készítsünk a DOM
jspdf-ből, egy könyvtárból, amely PDF-t generál
kezdjük a kódolást.
npm install html2canvas jspdf
import html2canvas from 'html2canvas'import jsPdf from 'jspdf' function printPDF () { const domElement = document.getElementById('your-id') html2canvas(domElement, { onclone: (document) => { document.getElementById('print-button').style.visibility = 'hidden'}}) .then((canvas) => { const img = canvas.toDataURL('image/png') const pdf = new jsPdf() pdf.addImage(imgData, 'JPEG', 0, 0, width, height) pdf.save('your-filename.pdf')})
és ennyi!
győződjön meg róla, hogy vessen egy pillantást ahtml2canvas
onclone
módszer. Hasznos lehet, ha a kép elkészítése előtt gyorsan kell pillanatfelvételt készíteni és manipulálni a DOM-ot (pl. a Nyomtatás gomb elrejtése). Nagyon sok használati esetet látok ehhez a csomaghoz. Sajnos a miénk nem volt, mivel a PDF készítést a háttéroldalon kellett kezelnünk.
2. lehetőség: Csak egy PDF könyvtárat használjon
erre a célra több könyvtár van az NPM – en, mint például a jsPDF (fent említett) vagy a PDFKit. A probléma velük, hogy újra kell hoznom az oldal struktúráját, ha ezeket a könyvtárakat akarom használni. Ez határozottan fáj a karbantarthatóságnak, mivel minden későbbi változtatást alkalmaznom kellett volna mind a PDF sablonra, mind a React oldalra.
vessen egy pillantást az alábbi kódra. A PDF dokumentumot kézzel kell létrehoznia. Most már át lehet lépni a DOM-on, és kitalálni, hogyan lehet lefordítani az egyes elemeket PDF-re, de ez egy unalmas munka. Kell lennie egy könnyebb útnak.
doc = new PDFDocumentdoc.pipe fs.createWriteStream('output.pdf')doc.font('fonts/PalatinoBold.ttf') .fontSize(25) .text('Some text with an embedded font!', 100, 100) doc.image('path/to/image.png', { fit: , align: 'center', valign: 'center'}); doc.addPage() .fontSize(25) .text('Here is some vector graphics...', 100, 100) doc.end()
Ez a töredék a PDFKit dokumentumokból származik. Hasznos lehet azonban, ha a cél egy PDF fájl, nem pedig egy már létező (és folyamatosan változó) HTML oldal konvertálása.
végleges opció 3: bábos, Fej Nélküli króm csomóponttal.js
mi a bábos? A dokumentáció szerint:
egy csomópont könyvtár, amely magas szintű API-t biztosít a Chrome vagy a Chromium vezérléséhez a DevTools protokoll felett. A Puppeteer alapértelmezés szerint fej nélkül fut, de konfigurálható teljes (nem Fej Nélküli) Chrome vagy Chromium futtatására.
Ez alapvetően egy böngésző, amely futtatható Node.js. Ha elolvassa a dokumentumokat, az első dolog, amit a Bábjátékosról mond, az az, hogy képernyőképeket és PDF-eket készíthet az oldalakról”. Kiváló! Ezt kerestük.
telepítsük anpmi i puppeteer
– t, és hajtsuk végre a használati esetünket.
const puppeteer = require('puppeteer') async function printPDF() { const browser = await puppeteer.launch({ headless: true }); const page = await browser.newPage(); await page.goto('https://blog.risingstack.com', {waitUntil: 'networkidle0'}); const pdf = await page.pdf({ format: 'A4' }); await browser.close(); return pdf})
Ez egy egyszerű funkció, amely egy URL-re navigál, és létrehoz egy PDF fájlt a webhelyről.
először elindítjuk a böngészőt (a PDF generációt csak fej nélküli módban támogatjuk), majd megnyitunk egy új oldalt, beállítjuk a nézetablakot, majd navigálunk a megadott URL-re.
awaitUntil: ‘networkidle0’
beállítás azt jelenti, hogy a Puppeteer úgy véli, hogy a navigáció akkor fejeződik be, ha nincs legalább 500 ms hálózati kapcsolat. (ellenőrizze az API docs-kat további információkért.)
ezután a PDF fájlt egy változóba mentjük, bezárjuk a böngészőt, majd visszaadjuk a PDF fájlt.
Megjegyzés: Apage.pdf
metódusoptions
objektumot kap, ahol a fájlt a “path” opcióval is lemezre mentheti. Ha az elérési út nincs megadva, a PDF nem kerül mentésre a lemezre, helyette puffert kap. Később, megbeszélem, hogyan tudja kezelni.)
abban az esetben, ha először be kell jelentkeznie egy PDF létrehozásához egy védett oldalról, először meg kell navigálnia a bejelentkezési oldalra, ellenőriznie kell az űrlap elemeit azonosító vagy név esetén, ki kell töltenie őket, majd be kell nyújtania az űrlapot:
await page.type('#email', process.env.PDF_USER)await page.type('#password', process.env.PDF_PASSWORD)await page.click('#submit')
mindig tárolja a bejelentkezési hitelesítő adatokat a környezeti változókban, ne kódolja őket!
Stílusmanipuláció
erre a stílusmanipulációra is van megoldás. A PDF létrehozása előtt stíluscímkéket helyezhet be, a Puppeteer pedig létrehoz egy fájlt a módosított stílusokkal.
await page.addStyleTag({ content: '.nav { display: none} .navbar { border: 0px} #print-button {display: none}' })
küldje el a fájlt az ügyfélnek, majd mentse el
Oké, most létrehozott egy PDF fájlt a backend-en. Mi a teendő most?
ahogy fentebb említettem, ha nem menti a fájlt lemezre, puffert kap. Csak el kell küldenie azt a puffert a megfelelő tartalomtípussal az elejére.
printPDF.then(pdf => {res.set({ 'Content-Type': 'application/pdf', 'Content-Length': pdf.length })res.send(pdf)
most egyszerűen kérést küldhet a kiszolgálónak, hogy megkapja a generált PDF fájlt.
function getPDF() { return axios.get(`${API_URL}/your-pdf-endpoint`, { responseType: 'arraybuffer', headers: { 'Accept': 'application/pdf' } })
a kérés elküldése után a puffernek el kell kezdenie a letöltést. Most az utolsó lépés a puffer konvertálása PDF fájlba.
savePDF = () => { this.openModal(‘Loading…’) // open modal return getPDF() // API call .then((response) => { const blob = new Blob(, {type: 'application/pdf'}) const link = document.createElement('a') link.href = window.URL.createObjectURL(blob) link.download = `your-file-name.pdf` link.click() this.closeModal() // close modal }) .catch(err => /** error handling **/) }
<button onClick={this.savePDF}>Save as PDF</button>
ennyi volt! Ha rákattint a Mentés gombra, a PDF-fájlt a böngésző menti.
a Bábjátékos használata a Docker-rel
azt hiszem, ez a megvalósítás legnehezebb része-Tehát hadd mentsek meg néhány órányi Googlingot.
a hivatalos dokumentáció kimondja, hogy”a fej nélküli Chrome fel-és futtatása a Dockerben trükkös lehet”. A hivatalos dokumentumoknak van egy hibaelhárítási szakasza, ahol az írás idején megtalálhatja az összes szükséges információt a bábos telepítéséről a Docker segítségével.
Ha Puppeteer-t telepít az alpesi képre, győződjön meg róla, hogy kissé lefelé görgeti az oldal ezen részét. Ellenkező esetben előfordulhat, hogy nem tudja futtatni a legújabb bábos verziót, és az shm használatát is le kell tiltania egy zászló használatával:
const browser = await puppeteer.launch({ headless: true, args: });
ellenkező esetben a bábos alfolyamat elfogy a memóriából, mielőtt még megfelelően elindulna. További információ erről a fenti hibaelhárítási linken.
3 + 1. Lehetőség: CSS nyomtatási szabályok
azt gondolhatnánk, hogy a CSS nyomtatási szabályok egyszerű használata fejlesztői szempontból egyszerű. Nincs NPM modul, csak tiszta CSS. De hogyan boldogulnak, amikor a böngészők közötti kompatibilitásról van szó?
a CSS nyomtatási szabályok kiválasztásakor minden böngészőben tesztelnie kell az eredményt, hogy megbizonyosodjon arról, hogy ugyanazt az elrendezést biztosítja-e, és nem 100% – ban.
például egy szünet beillesztése egy adott elem után nem tekinthető ezoterikus Használati esetnek, mégis meglepődhet, hogy megoldásokat kell használnia a Firefox használatához.
hacsak nem csatakemény CSS bűvész, akinek sok tapasztalata van a nyomtatható oldalak létrehozásában, ez időigényes lehet.
nyomtatási szabályok nagy, ha meg tudja tartani a nyomtatási stíluslapok egyszerű.
nézzünk egy példát.
@media print { .print-button { display: none; } .content div { break-after: always; }}
Ez a fenti CSS elrejti a nyomtatás gombot, és minden div
után beszúr egy oldaltörést a content.
van egy nagyszerű cikk, amely összefoglalja, hogy mit tehet a nyomtatási szabályokkal, és milyen nehézségek vannak velük, beleértve a böngésző kompatibilitását.
mindent figyelembe véve, a CSS nyomtatási szabályok nagyszerűek és hatékonyak, ha PDF-t szeretne készíteni egy nem olyan összetett oldalról.
összefoglaló: PDF HTML-ből csomóponttal.js pedig Bábjátékos
Szóval, nézzük gyorsan végig a lehetőségeket fedezett itt generáló PDF fájlokat HTML-oldalak:
- Screenshot a DOM: Ez akkor lehet hasznos, amikor létre kell hozni pillanatképek egy oldalon (például, hogy hozzon létre egy miniatűr), de elmarad, ha sok adatot kell kezelni.
- csak PDF könyvtárat használjon: ha PDF fájlokat programozottan kell létrehoznia a semmiből, ez tökéletes megoldás. Ellenkező esetben meg kell őriznie a HTML-és PDF-sablonokat, ami határozottan nem megy.
- : Annak ellenére, hogy viszonylag nehéz volt a Docker-en dolgozni, ez adta a legjobb eredményt a használati esetünkhöz,valamint a legegyszerűbb kódot is írni.
- CSS nyomtatási szabályok: ha a felhasználók elég képzettek ahhoz, hogy tudják, hogyan kell nyomtatni egy fájlt, és az oldalak viszonylag egyszerűek, ez lehet a leginkább fájdalommentes megoldás. Ahogy a mi esetünkben láttuk, nem volt.
Boldog nyomtatás!
kapcsolódó témák
csomópont.js oktatóanyagok kezdőknek / @RisingStack
Leave a Reply