Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to generate server-side PDF of Angular app?

We have an Angular (v4) app that generates a form from JSON data received by our API combined with images from a file store. Each client using the app has a number (in the hundreds) of forms containing different data and images. A feature has been requested which will allow a client to export their forms as PDFs in a zip.

The strategy we're exploring for the solution is that when an export request is received for a client, the server will load each form that client can access in a headless browser, Angular will build the form and then the server will ask the browser to generate a PDF screenshot. Then those PDFs will be zipped up and sent to the client via email or download link.

The issue that we're having is that generating a screenshot of the Angular app from the server-side is failing.

As a simpler test site we've also been trying to get any of these tools to work with the current Angular documentation site - https://angular.io/guide/quickstart . All attempts have failed so far:

  • wkhtmltopdf - Gets to our loading user info spinner, but no content arrives, even after waiting for 90 seconds. We get errors in the JS output.

    This is the command we've been using to snap the Angular docs site which just generates a white PDF:

    ~/render/wkhtmltox/bin$ ./wkhtmltopdf --debug-javascript --no-stop-slow-scripts --javascript-delay 90000 https://angular.io/guide/quickstart angular_quickstart.pdf 
    Loading pages (1/6)
    Warning: undefined:0 TypeError: setting a property that has only a getter
    Counting pages (2/6)                                               
    Resolving links (4/6)                                                       
    Loading headers and footers (5/6)                                           
    Printing pages (6/6)
    Done             
    
  • PhantomJS - Appears to do a bit better than wkhtmltopdf because it can get to our "loading content" spinner which means that the app knows a user it logged in. However, even when waiting and polling for DOM changes, we get no changes after the initial load.

    When working with the Angular docs site, this also fails with a white screen:

    ~/render/phantomjs-2.1.1-linux-x86_64$ bin/phantomjs examples/rasterize.js https://angular.io/guide/quickstart angular_quickstart.pdf 
    ReferenceError: Can't find variable: WeakMap
    
      https://angular.io/main.f0610805f4aad19da4be.bundle.js:1 in cDNt
      https://angular.io/inline.2826385ad3e299c6d1c1.bundle.js:1 in n
      https://angular.io/main.f0610805f4aad19da4be.bundle.js:1
      https://angular.io/inline.2826385ad3e299c6d1c1.bundle.js:1 in n
      https://angular.io/inline.2826385ad3e299c6d1c1.bundle.js:1 in webpackJsonp
    
  • Puppeteer - We haven't dug into headless Chrome fully, but initial tests with https://try-puppeteer.appspot.com/ and the Angular docs site have failed with:

    Error running your code. Error: Navigation Timeout Exceeded: 30000ms exceeded
    

Could someone point me in the direction of a working solution that can screenshot the Angular docs and generate a PDF from that? Hopefully we'll then be able to adapt that solution to work with our app. Please make sure your solution can screenshot the Angular docs running on Angular 5.

We're mainly a Python shop when it comes to the server-side tech, but we could install node and run docker containers for a solution that works reliably.

like image 913
jamesc Avatar asked Nov 06 '17 12:11

jamesc


1 Answers

Probably most simple way is using Chrome:

 chrome.exe --headless --enable-logging --disable-gpu --print-to-pdf="D:\temp\file.pdf" https://angular.io/guide/quickstart

See Create PDF section https://developers.google.com/web/updates/2017/04/headless-chrome

like image 129
kemsky Avatar answered Oct 13 '22 02:10

kemsky