MathJax processing on the server-side
This is a post about MathJax expression rendering on the server-side
The first attempt
First, we need the MathJax files, as a Ruby dependency. There is an excellent gem source called Rails Assets which essentially brings Bower to Ruby. Thus, adding it as a source then rails-assets-MathJax as a dependency, we automatically get all the needed files.
The next thing we need is a HTTP server that our PhantomJS browser will fetch the site from. For it I’ve used WEBrick, as it comes with standard Ruby. Basically we need to start the server, mount the MathJax assets to a directory, then make an HTML page that contains out MathML expression. We need to do this in a separate thread because we need it running in the background. After that we need to poll and wait for the server to start.
And we can have server_started? like this:
Lastly, we need to mount an HTML file with the expression, like this:
Getting the HTML
After we have the server ready, we need to actually fetch it, wait for MathJax to render, then grab the HTML. I’ve used Capybara and after the setup, the relevant parts are:
This loads the page, waits for MathJax, then extracts the results.
Using the result
The resulting HTML can be directly included into the page, but don’t forget to include the fonts too. You can use the MathJax CDN, but since you already have them as part of the rails-assets-MathJax gem, it’s best to use them instead. For the CDN, you might want to use something similar to this:
Conclusion of the first attempt
The described solution works quite well, it really does the job. After everything was set up, I’ve noticed that the expression in a browser looks the same as before (that’s the good part), but Pocket still don’t show anything (and that’s the bad part). So in conclusion it successfully transitioned the processing to the server-side (although it compromises some compatibility of MathJax to older browsers) it did not solve the original problem.
The second attempt
The second thought is instead of generating the HTML content, let’s capture an image of the rendered expression. This will surely work in every article reader, and it will look the same, so there will be no cross-browser issues. The first thing I tried it PhantomJs, but sadly it does not support custom fonts (here’s a GitHub issue) as of the current version. Version 2 will support them, but it is not available for all platforms at the moment.
The stack will then use Chrome in Xvfb, so it will not actually pop up a browser window, but it will behave exactly like one. Also we need some PNG processing to crop the screenshot, Chunky PNG will do the job well.
We will reuse most of the code from the first attempt, there are only some additions we need to make. First, we need to start Xvfb. Fortunately there is an excellent gem for this, reducing it to a Headless.ly block. Then we need to reconfigure Capybara to use Chrome instead of PhantomJs.
Taking and cropping the screenshot
And that’s it, we have the image of the expression and we can substitute all MathML with it.
Conclusion of the second attempt
This imaging solution works quite well, you can check at the earlier posts in this blog. I needed some tweaks like a minimal width, some padding and custom CSS, you can find the documentation and the end result at Github. The downside is that it requires some software that is unlikely to be present on every machine, and it’s kinda slow. When PhantomJS 2 will be generally available, I’ll look into it whether it can substitute a real browser.