saadq / node-latex

🧾 A utility for running LaTeX subprocesses in Node.
MIT License
58 stars 22 forks source link

Is the LaTeX Call Asynchronous #14

Closed jamesqquick closed 6 years ago

jamesqquick commented 6 years ago

This is not necessarily an issue, but didn't know of a better place for it. Is the following call synchronous or asynchronous?

latex(texDoc, opts)

From the looks of it, it's synchronous, but I would think this is potentially a long enough running function for it to make since to be asynchronous...?

saadq commented 6 years ago

So it kind of depends what you mean. It is "synchronous", but not in a way that it conflicts with Node's async model. Imagine doing something like

const file = fs.createReadStream('myfile.txt')

file.on('finish', () => {
  // Do stuff
})

createReadStream isn't asynchronous as described in that link, but it isn't an issue. Similarly, the output from the latex function is a stream where the output PDF is piped to:

const pdf = latex(texDoc)

pdf.on('finish', () => {
  // Do stuff
})

The way this module works is that it creates a latex child process asynchronously using the native spawn function as described here. Basically, the following happens:

  1. We create an output ReadableWritable stream here which is what the end user gets
  2. We run an async latex child process here which, when finished, stores the generated PDF in the user's tmp directory.
  3. We use a read stream to pipe the data from the PDF in the tmp directory to the output stream here.

So if you were wondering that this module breaks away from Node conventions or if it would block the event loop, you don't have to worry on that front. The whole process of latex running is done asynchronously, and once it has finished I just pipe the output PDF to the user. It's up to you how you use it, whether you want to pipe that PDF output stream to a createWriteStream to save it as a file or if you want to pipe it to a web server response, etc. Hope that clarified things, feel free to reopen or comment if you have any more questions/concerns.

jamesqquick commented 6 years ago

Yep, exactly what I'm looking for! Thank you for the very detailed response!

richardtorres314 commented 5 years ago

@saadq Thank you for this package! I have a question about piping the PDF output stream to a web server response: when doing so, what should be sent? I'm currently testing out the AdonisJS Node framework, but don't seem to get much success when attempting to serve the PDF from a browser. Currently, a user clicks a link that directs the user to the generated PDF. The function below is called:

async show({ params, request, response, view }) {
    const input = fs.createReadStream('input.tex');
    const output = fs.createWriteStream('output.pdf');
    const pdf = latex(input);
    pdf.pipe(output);
    response.download(output);
}

However, the browser simply returns with a 404. If I comment out the latex generating bit, the PDF renders just fine in the browser. The PDF is being generated correctly, but not served. Is this a synchronous problem? What is the correct way to serve the newly generated output of the latex compilation? Many thanks!

saadq commented 5 years ago

Hey @richardtorres314,

You should be able to be able to just pipe the pdf stream to your http response. The way I do this in my Koa app is just by setting response.body to the stream: . My generatePDF() function just calls latex() on the tex file and returns it.

With AdonisJS, it looks like the proper way to do it would be to do pdf.pipe(response.response) as shown here: https://github.com/adonisjs/adonis-framework/issues/183#issuecomment-225532225

On the client side, I do a fetch to get the PDF blob. I then create a url from that blob via URL.createObjectURL. You can use that url however you wish, like passing it to an <embed> tag or using pdfjs.