Executando verificação de segurança...
1

[Ajuda] Renderizar PDF a partir de HTML com Node.js

Situação: tenho alguns templates em html + css e estava usando Puppeteer.
Localmente estava dando certo, porém rodo minha api na AWS, ao upar a api com o puppeteer, dá erro, e configurar o chromium/lambda no estado atual não é possível para mim.

Estou tentando utilizar o html-pdf e html-pdf-node, porém está quebrando as imagens e até divs, fica cortado pela metade nas páginas. O css parece não funcionar muito bem com essa lib, os exemplos utilizam até bootstrap, achei que ajudaria, mas em partes apenas.

Alguém teria alguma outra sugestão ou dica ?

const pdf = require("html-pdf-node");
const generatePDF = async (htmlContent, format, landscape) => {
  const options = {
    format, // Tamanho do papel, como "A4" ou "Letter"
    landscape, // Orientação: true para paisagem, false para retrato
    preferCSSPageSize: true,
    printBackground: true,
  };

  // Criação do PDF a partir do HTML
  const file = { content: htmlContent };
  try {
    const pdfBuffer = await pdf.generatePdf(file, options);
    return pdfBuffer;
  } catch (error) {
    throw new Error(`Erro ao gerar PDF: ${error.message}`);
  }
};

Utilizo esse código, que diz que resolve a quebra, porém sem sucesso 100%

 /* Evita quebras de elementos dentro de uma página */
      .no-break,
      .header,
      .checklist-item,
      .value-item {
        page-break-inside: avoid;
        break-inside: avoid;
      }
Carregando publicação patrocinada...
2
1

Por enquanto vou fazer o que o colega Pedroaf0 falou...
Tenho uma parte admin onde posso gerar o relatório e faço esse window.print;
Mas não é o ideal como o welovetech disse.
Um diferencial do sistema vai ser essa geração de relatório a partir do aplicativo mobile.
Mas como não escalei ainda, é bem viável

2
1
2

Tenho um usecase parecido com o seu em minha aplicação B2B, onde usuarios podem construir seus PDFs. Inicialmente parti para uma abordagem construindo esse PDF no frontend, e usando diversas ferramentas que o convertiam para que o usuário pudesse fazer o download.

Decidimos tentar essa abordagem fazendo uma POC, e logo vimos as infinitas limitações que esse tipo de solução teria.

Construimos então toda a lógica no backend, o que se mostrou um completo sucesso. Utilizamos a lib pdfkit. Acho que não há melhor do que ela hoje. Eu não recomendo tentar transformar HTML diretamente em um PDF, isso vai levar a diversas inconsistencias visuais, quebra de linhas incorretas, overlap de conteudos, quebra de paginas incorretas e etc, o que aconteceu conosco em nossas diversas POCs dessa feature.

Com o pdfkitconseguimos criar todo tipo de PDF personalizado. Recomendo dar uma olhada: https://pdfkit.org/

Como comentou que vai rodar em lambdas, recomendo tomar cuidado ao lidar com muitas imagens bufferizadas nas paginas, isso geralmente acarreta em um uso excessivo de memória. Sucesso no projeto.

1

Então estou utilizando em partes esse PDFkit, mas o puppeteer por exemplo renderiza o html/css bem bonito e sem quebras, melhor solução até agora, tirando o Pdfkit.
O PDFkit é realmente bom, vou falar que seria por desinteresse ou falta de conhecimento técnico meu, me irritei fazendo os templates kkkkkkkkk

Apesar de tudo, estou utilizando o Pdfkit também.
Muito obrigado Jorge!

2

Uma coisa que pensei é verificar com o windom.print se a página html + css está sendo a mesma dessa lib que utilizado com nodejs. Se for, pode ser que resolva com algumas linhas de css.

Se não der certo. veja na biblioteca issues abertas/fechadas no repositório. veja se já tiveram esse problema.

1

Use --no-sandbox dentro de args ao instanciar seu Browser. Veja sobre outras configurações de Sandbox como --disable-setuid-sandbox, pois elas interagem diretamente com as configurações de superusuário do Chrome.

1
1

Boa tarde! Vc pode utilizar a configuração headless = true para remover a janela do browser que funciona com servidores sem interface gráfica. Segue a função para gerar qualquer pdf que utilizo com o pupperteer

async function generatePDF(url,puppeteerConf={}) 
{
    if(browser==false)
        browser = await puppeteer.launch({ headless: true, ignoreHTTPSErrors: true }); // Puppeteer can only generate pdf in headless mode.
    const pdfConfig = Object.assign({
        format:'A4',
        landscape:true,
        printBackground:true
    }, puppeteerConf);
    var returnedPdf = null;
    const page = await browser.newPage().catch(err => { 
        if(browser)
            browser.close();
        browser=false;
        throw 'newPage crash:'+err;
    });
    return new Promise( (resolve, reject) => {
        page.on('error', (err) => {
            try {
                page.close();
            } catch(e) { };
            reject('page crash:'+err);
        });
        
        page.goto(url, {waitUntil: 'networkidle0', timeout: 25000} )
        .then( () => {
        if(typeof page['emulateMediaType']=='function')
            page.emulateMediaType('screen');
        else
            page.emulateMedia('screen');
        })
        .then( () => page.pdf(pdfConfig) )
        .then( pdf => { returnedPdf = pdf })
        .then( () => page.close() )
        .then( () => { resolve(returnedPdf); })
        .catch(err => {
            reject(err);
        });
    });
}
1

Voce pode também utilizar o Libre Office ao invés do pupeeeter. É mais eficiente, e voce pode usar chields para executar os comandos. Só nao sei se ele consegue abrir o HTML, teria que testar

0
-2