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

[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...
5

é muito importante que o pdf seja gerado no backend?
pois muitas vezes é mais fácil gerar no front usando control+P

ou

function salvarpdf() { window.print(); }

até porque rodar o puppeteer na aws vai sair muito caro

1

Por enquanto sim, pois a api é utilizada pela WEB e por Aplicativo Mobile também.
Ele gera (ou espera-se) relatórios tanto na web quanto app (e são diferentes).
Se tiver alguma outra sugestão, agradeço!

-2

minha sugestão ainda é considerar fazer o pdf no frontend, na web é certo que funciona e o app pode abrir um link no navegador do celular pra gerar o PDF no front, vai te poupar processamento no backup. a api pode retornar o html e o front que pode ser puro renderiza o html e executa window.print()

0

Inviável e muito limitado. Suponhamos que esse pdf precisa ser baixado diretamente pelo usuário em qualquer Browser ou dispositivo. Ou que preciso disparar um email com ele anexado. Isso só é possível utilizando o back e é a forma lógica e correta para tal.

2

aqui você pode ver a compatibilidade da função window.print() ela é compatível com todos os navegadores em todos os dispositivos.

https://developer.mozilla.org/en-US/docs/Web/API/Window/print#browser_compatibility

é claro que pode existir casos em que ela não é a melhor opção, mas deve ser pensada como primeira escolha pois é a mais simples.

mesmo no caso do e-mail, ele pode conter um link que abre o navegador e gera o pdf. até porque isso é muito melhor e mais simples do que ter que gerar e anexar um arquivo.

as vezes a resposta mais simples é a melhor mesmo! se um dispositivo for tão antigo a ponto não suportar essa api ele provavelmente não lida bem com pdf também.

eu já precisei fazer um sistema de envio de certificados em pdf por e-mail e a melhor solução foi enviando o link pra uma página que usava a função print para salvarem o pdf. ninguém reclamou, foi usado em android, iOS e computadores. foi uma solução mágica, pois um sistema simples de envio de certificado foi simplesmente feito em php, em vez de querer complicar de mais e gerar o PDF no backend pra depois enviar.

2

Apenas compleementado... A um tempo atrás eu precisei otimizar as imagens dos produtos de um site que estava desenvolvendo, tentei por lambda e tive problema pra instalar uma lib na minha lambda, foi ai que tive uma ideia mais simple. Hoje em dia os hardwares mais simples já sao muito bons, foi entao que tive a ideia de fazer a otimização das imagens direto no navegador do usuário antes do upload, deu super certo e me economizou ter que ficar configurando mais um serviço na nuvem.

-1
3

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
2

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

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