RapiPdf icon indicating copy to clipboard operation
RapiPdf copied to clipboard

Use with node.js

Open itpropro opened this issue 5 years ago • 4 comments

Hello, Is there an example on how we could use this in node js? It would be a great functionality for microservice and serverless applications.

itpropro avatar May 27 '20 16:05 itpropro

this being a web-component based solution, there isn't any good tooling AFAIK that can render web-components on server

That being said keep an eye on this space, We do have it planned out in our roadmap, but need to wait for lit-ssr to be in some usable form

anther approach would be to factor out the core-engine and create a CLI, it can be done using lit-html-server. I am open for a PR in this direction too

mrin9 avatar May 27 '20 19:05 mrin9

If you need this now, it's possible to do with jsdom. Load up the index.html in there, and mock window.URL.createObjectURL in the DOM and you'll get a blob back with the PDF content.

I'm afraid I don't have a code example but this is what I've been using for the past couple of days. It's just a pain to get the blob output to a file afterwards, but things like this should work so long as you're getting globals from the jsdom window.

andyrooger avatar Jun 09 '20 13:06 andyrooger

For what it's worth, we were able to use RapiPdf in Node.js with something like this:

const fs = require('fs');
const jsdom = require('jsdom');
const virtualConsole = new jsdom.VirtualConsole();
const {JSDOM} = jsdom;

const script = fs.readFileSync('./node_modules/rapipdf/dist/rapipdf-min.js', 'utf-8');

const json = fs.readFileSync('api.json', 'utf-8');
const obj = JSON.parse(json);
const dom = new JSDOM(`
<!doctype html>
<script>${script}</script>
<rapi-pdf id="thedoc"></rapi-pdf>
`, {
    virtualConsole,
    runScripts: 'dangerously'
});
const {document} = dom.window;
dom.window.onopen = function () {};
dom.window.URL.createObjectURL = (blob) => {
    const reader = new dom.window.FileReader();
    reader.addEventListener('loadend', () => {
        fs.writeFileSync('out.pdf', Buffer.from(reader.result));
    });
    reader.readAsArrayBuffer(blob);
};
document.addEventListener('DOMContentLoaded', async () => {
    const rapiPdf = document.querySelector('rapi-pdf');
    rapiPdf.generatePdf(obj);
});

Unfortunately, it stopped working with Node.js 18. Further inspection revealed that the custom element type rapi-pdf failed to register due to a JavaScript error when loaded by jsdom.

JS DOM error: Error: Uncaught [TypeError: Cannot redefine property: onmessage]
    at reportException (...\docs\node_modules\jsdom\lib\jsdom\living\helpers\runtime-script-errors.js:66:24)
    at processJavaScript (...\docs\node_modules\jsdom\lib\jsdom\living\nodes\HTMLScriptElement-impl.js:240:7)
    at HTMLScriptElementImpl._innerEval (...\docs\node_modules\jsdom\lib\jsdom\living\nodes\HTMLScriptElement-impl.js:173:5)
    at ...\docs\node_modules\jsdom\lib\jsdom\living\nodes\HTMLScriptElement-impl.js:114:12
    at ResourceQueue.push (...\docs\node_modules\jsdom\lib\jsdom\browser\resources\resource-queue.js:53:16)
    at HTMLScriptElementImpl._fetchInternalScript (...\docs\node_modules\jsdom\lib\jsdom\living\nodes\HTMLScriptElement-impl.js:113:21)
    at HTMLScriptElementImpl._eval (...\docs\node_modules\jsdom\lib\jsdom\living\nodes\HTMLScriptElement-impl.js:167:12)
    at HTMLScriptElementImpl._poppedOffStackOfOpenElements (...\docs\node_modules\jsdom\lib\jsdom\living\nodes\HTMLScriptElement-impl.js:130:10)
    at JSDOMParse5Adapter.onItemPop (...\docs\node_modules\jsdom\lib\jsdom\browser\parser\html.js:175:43)
    at Parser.onItemPop (...\docs\node_modules\parse5\dist\cjs\parser\index.js:158:90) {
  detail: TypeError: Cannot redefine property: onmessage
      at about:blank:55:149568
      at about:blank:55:149574
      at Object.<anonymous> (about:blank:55:150731)
      at Object.<anonymous> (about:blank:55:150783)
      at D (about:blank:6:7214)
      at r (about:blank:6:568)
      at Object.<anonymous> (about:blank:55:54348)
      at Object.<anonymous> (about:blank:55:54589)
      at D (about:blank:6:7214)
      at r (about:blank:6:568),
  type: 'unhandled exception'
}
...\docs\use_rapipdf.js:43
    rapiPdf.generatePdf({});
            ^

TypeError: rapiPdf.generatePdf is not a function
    at Document.<anonymous> (...\docs\use_rapipdf.js:43:13)
    at Document.callTheUserObjectsOperation (...\docs\node_modules\jsdom\lib\jsdom\living\generated\EventListener.js:26:30)
    at innerInvokeEventListeners (...\docs\node_modules\jsdom\lib\jsdom\living\events\EventTarget-impl.js:350:25)
    at invokeEventListeners (...\docs\node_modules\jsdom\lib\jsdom\living\events\EventTarget-impl.js:286:3)
    at DocumentImpl._dispatch (...\docs\node_modules\jsdom\lib\jsdom\living\events\EventTarget-impl.js:233:9)
    at fireAnEvent (...\docs\node_modules\jsdom\lib\jsdom\living\helpers\events.js:18:36)
    at dispatchEvent (...\docs\node_modules\jsdom\lib\jsdom\living\nodes\Document-impl.js:452:9)
    at ...\docs\node_modules\jsdom\lib\jsdom\living\nodes\Document-impl.js:457:11
    at new Promise (<anonymous>)
    at onDOMContentLoad (...\docs\node_modules\jsdom\lib\jsdom\living\nodes\Document-impl.js:455:14)

Node.js v18.16.0

There might be a way to fix this particular problem, but I wouldn't know where to look at the moment.

Update: See jsdom/jsdom#3546

Enet4 avatar May 10 '23 13:05 Enet4