Come creare PDF da componenti React [soluzione lato client]

Se hai mai avuto a che fare con un'app dashboard B2B, sai che le aziende adorano i report in formato pdf.

Foto di base di Lauren Richmond su Unsplash

Quando ho affrontato per la prima volta questo problema, avevamo una pagina di analisi, che volevamo convertire in pdf. Il mio istinto era quello di aggiungere un file print.css e lasciare che il browser gestisse tutto il lavoro sporco. Per farla breve, questo non funziona.

Con un foglio di stile specifico per la stampa, mi sono ritrovato a annullare la maggior parte dei miei stili specifici per il web. Il risultato finale non è stato neanche molto attraente. Inoltre, è difficile modellare i contenuti di un PDF come html. Ciò che rende bene nel browser sembra terribile su un PDF.

Abbiamo iniziato a generare PDF sul lato server, utilizzando un'istanza PhantomJS. Puoi vedere questo approccio lato server in azione su PFRepo: https://pfrepo.me. Viene utilizzato per generare la versione pdf dei curriculum web)

Un modo migliore è rendere il pdf direttamente sul frontend. L'approccio lato client è veloce (niente da trasmettere in rete), ha meno parti mobili (senza browser senza testa) e preciso. Ti consente anche di continuare a progettare HTML invece di pensare in termini di PDF.

La generazione di un pdf sul lato client è un processo in 3 passaggi:

  • Converti il ​​DOM in svg
  • Converti lo svg in png
  • Converti il ​​png in pdf

Sto usando React in questo esempio, ma lo stesso approccio può funzionare con Angular, Vue o qualsiasi altro sistema di frontend. Abbiamo solo bisogno di js alla vaniglia.

Nell'IDE sotto puoi vedere due pagine renderizzate. Uno presuppone che il nostro contenuto si adatti a una singola pagina e l'altro in cui la dimensione del contenuto potrebbe essere dinamica e richiedere più di una pagina.

Passaggio 1: converti il ​​DOM A4 in svg

html2canvas è una buona libreria per convertire DOM in svg. L'API è abbastanza semplice.

Conversione da HTML a svg

Passaggio 2: converti svg in png

Questo può essere fatto usando vanilla js:

const input = document.getElementById ('divIdToPrint');
html2canvas (ingresso)
  .then ((canvas) => {
    const imgData = canvas.toDataURL ('image / png');
  })
;

Passaggio 3: converti png in pdf

Ciò è ottenuto da una libreria chiamata jsPDF. L'utilizzo modifica il codice del passaggio 2 nel modo seguente:

html2canvas (ingresso)
  .then ((canvas) => {
    const imgData = canvas.toDataURL ('image / png');
    const pdf = new jsPDF ();
    pdf.addImage (imgData, 'PNG', 0, 0);
    pdf.save ( "download.pdf");
  });
;

Gestione di più pagine

Ok, quindi abbiamo la possibilità di stampare DOM in pdf, ma la nostra configurazione attuale può stampare solo singole pagine. E se avessimo più pagine?

Ci sono due modi per farlo:

> Il modo semplice

Stampa un pdf allungato e lascia che il sistema gestisca le interruzioni di pagina.

> La strada giusta

Fai qualche rapido calcolo matematico per capire quante pagine sono necessarie. Calcola gli offset e le altezze delle pagine ed esegui il processo a pagina singola su tutte le pagine.

Il risultato

L'IDE StackBlitz di seguito ha il codice e l'interfaccia utente in azione. Ho gestito più pagine nel modo più semplice dopo aver rinunciato nel modo giusto (che è presente nel codice).

Esistono altre soluzioni come React-PDF che introducono componenti ottimizzati che possono essere convertiti in pdf. Ho provato a lavorarci ma sento che il progetto è ancora molto nascente. Sentiti libero di provare anche questo approccio.

[25 agosto 2018] Aggiornamento 0; Svantaggi di questo approccio

Molte persone qui (e su reddit) hanno sottolineato che i pdf generati usando questo approccio non avranno il testo selezionabile. Se questo è un problema, potresti voler leggere questo post di William Kwok. Attraversa un'altra libreria che consente di generare componenti di reazione con testo selezionabile in pdf.

Se ti è piaciuto questo articolo e vuoi rimanere aggiornato, seguimi su: Medium, Github o Twitter

Ta