简体   繁体   中英

Run Node.JS server in Ruby - Kramdown math engine

Problem

Hi, I am using Jekyll and Kramdown to render posts in written in markdown to HTML. My posts contains a lot of math. I am using KaTeX gem. This is in my _config.yml file:

kramdown:
  math_engine: katex

It works but its that this is slow as hell. Whole blog takes around 250 seconds to render. It is caused by using execjs library to run katex.js . This is part of the code:

ExecJS.compile(open(PATH_TO_JS).read).call("katex.renderToString", toRender, {displayMode: dm))

Potential solution

I have found guy on github who made Node.JS it repeatedly. I implemented his solution and render time dropped from 250 seconds to 6 seconds. But when I saw the code itself my eyes started bleeding. His solution uses stdio to communicate with Node.JS server. This is example of his code:

_plugins/katex.rb:

require 'execjs'

module Jekyll
  module Tags
    class KatexBlock < Liquid::Block

      def initialize(tag, markup, tokens)
        super
        @markup = markup
      end

      def render(context)
        File.open("scripts/katex_server/in", 'w') {
          |file| file.write("#{@markup}\n" + super(context))
        }

        return File.read("scripts/katex_server/out")
      end
    end
  end
end

Liquid::Template.register_tag('latex', Jekyll::Tags::KatexBlock)

scripts/katex_server/server:

#!/bin/node

const katex = require('./katex.min.js');
const readline = require('readline');
const fs = require('fs');
const path = require('path');

function recursive_stream() {
    var is = fs.createReadStream(path.join(__dirname, 'in'));

    is.on("data", function(data) {
        request = data.toString();
        parameters = request.split("\n")[0];
        request = request.substring(parameters.length + 1);
        parameters = parameters.trim().split(/\s"/);

        os = fs.createWriteStream(path.join(__dirname, 'out'))
        os.end(katex.renderToString(request, {
            displayMode: parameters.includes("display")
        }));

        recursive_stream();
    }); 
}

recursive_stream();

Question

How to run Node.JS server INSIDE ruby script? How to use it to render latex using katex.js ?

  • TL;DR: How to make node.js server communicate with ruby script?

Thank you for your help

As far as I understood your problem from the description, you need to find a way to use katex.js in your ruby app.

For this you don't have to run node.js inside of your ruby application. Instead, you can create another web service in node.js which would provide HTTP endpoint for use of this library. If in the future you decide to use docker and kube.netes, you will have a great horizontal scalability out of the box with this approach. This approach also decouples the services quite nicely, unlike the solution of embedding one into the other, which introduces a lot of dependencies on your ruby server.

To create such a web service you don't even need to change his code a lot, just define the endpoint and wrap his code into it.

Then, on the ruby side you would have an http call, like Faraday.get('url_of_your_service').body to get the rendered template. This would work fast, because the nodejs web server would mostly be either on the same machine or in the same cluster, in case you use something like kube.netes/aws.

Also you could process the markdown once and cache the end result and just display that. Depending on your read/write ratio this could solve your speed problem.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM