Metalsmith Plugins for Server-side KaTeX Processing
In a prior post, I briefly described the Metalsmith tool-chain I use to render my blog as a collection of static pages (no repeated server fetches, and minimal client-side Javascript). The tool-chain continues to work just fine, though my postings are still very sporadic. Recently, I spent some time trying to improve the Markdown support for formatting of LaTeX math expressions. The implementation I had running relied on two separate Markdown schemes, one supported in IPython files and the other in regular Markdown files. Since this was becoming a burden for me to remember which to use, I decided to clean up the KaTeX processing to only use one Markdown style involving ‘$’ tokens.
IPython Processing
The Jupyter framework supports the presence of LaTeX commands surrounded by $
or $$
tokens. The text wrapped by a single-$
will appear inline with the rest of the text in the current paragraph, while text wrapped with a double-$
will appear on its own in a bigger format and centered on the page. This makes it very easy to enter math equations such as and symbols such as .
Unfortunately, the notebookjs code I rely on to render the IPython files into HTML does not support such extension to Markdown, and so I worked out a scheme where I changed the delimiters and then relied on in-browser Javascript to ultimately do the rendering using the KaTeX package. In order to bring the processing back into the tool-chain, I needed to write something that would perform the KaTeX expansion without harming the normal Markdown processing done by notebookjs
.
The solution I came up with was a pre-processor called notebookjs-katex. It only works on IPython Markdown cells, transforming any embedded $...$
or $$...$$
spans into HTML generated by the KaTeX library. Since notebookjs
will accept and ignore embedded HTML, this seems to be doing just fine. Here is how I use it in my Metalsmith build script:
var KatexFilter = require("notebookjs-katex");
var kf = new KatexFilter();
...
var ipynb = JSON.parse(fs.readFileSync('/path/to/notebook.ipynb'));
kf.expandKatexInNotebook(ipynb); // (1)
...
var notebook = notebookjs.parse(ipynb); // (2)
var html = notebook.render().outerHTML;
You can see an example of the new KaTeX plugin at work here.
Markdown Processing
The Markdown processor I use in my tool-chain is the Remarkable package. It is fast and supports a variety of useful Markdown extensions. Although it does not natively support math expression tagging, it does support expansion via plugins. Since I found no existing plugins for KaTeX rendering, I decided to roll my own and call it — surprise! — remarkable-katex.
To use the plugin is incredibly easy since there are no customization options yet:
var Remarkable = require('remarkable');
var plugin = require('remarkable-katex');
var md = new Remarkable();
md.use(plugin);
End Result
Removing the in-browser rendering proved to be less work than I had originally thought. Now all KaTeX processing takes place in the site build script, page load time is reduced and there is no more flashing due to the in-browser KaTeX processing. Segregating the code into separate NPM modules makes the build script code a bit cleaner — and perhaps someone else will be able to use it as well.
Finally, some math formatting examples (taken from TiddlyWiki KaTeX Demo page.
Example 1
Example 2
Example 3
Example 4
Inline Examples
The equation looks familiar. Since , we are done. Unfortunately, in the interval to we have no data.