Here's some code to use duktape, a lightweight JavaScript interpreter
to run katex when implementing a custom static site generator [as I
am doing for this website ]. This seems to be way more lightweight
than relying on Node, since we don't need to pay for inter-procedure-calls.
I haven't benchmarked my static site generator against others, but I would be surprised if it is much faster, since it is written entirely in C, and avoids anything 'expensive'.
#include "duktape.h"#include <stdio.h>#include <assert.h>typedef long long ll;void vduk_print_stack(duk_context *ctx, const char *fmt, va_list args){ char *outstr = nullptr; vasprintf(&outstr, fmt, args); assert(outstr); printf("\nvvv%svvv\n", outstr); printf("[TOP OF STACK]\n"); const int len = duk_get_top(ctx); for(int i = 1; i <= len; ++i) { duk_dup(ctx, -i); printf("stk[-%2d] = %20s\n", i, duk_to_string(ctx, -1)); duk_pop(ctx); } printf("^^^^^^^\n");}void duk_print_stack(duk_context *ctx, const char *fmt, ...) { va_list args; va_start(args, fmt); vduk_print_stack(ctx, fmt, args); va_end(args);}int main() { const char *latex_to_compile = "\\int_0^\\infty f(x) dx"; const char *broken_latex_to_compile = "\\int_0^\\infty \\foobar f(x) dx"; // FILE *fkatex = fopen("/home/bollu/blog/katex/katex.min.js", "rb"); FILE *fkatex = fopen("/home/bollu/blog/katex/katex.min.js", "rb"); if (fkatex == nullptr) { assert(false && "unable to open katex.min.js"); } fseek(fkatex, 0, SEEK_END); const ll len = ftell(fkatex); fseek(fkatex, 0, SEEK_SET); char *js = (char *)calloc(sizeof(char), len + 10); const ll nread = fread(js, 1, len, fkatex); assert(nread == len); duk_context *ctx = duk_create_heap_default(); duk_push_string(ctx, "katex.min.js"); // for error message if (duk_pcompile_string_filename(ctx, 0, js) != 0) { fprintf(stderr, "===katex.min.js compliation failed===\n%s\n===\n", duk_safe_to_string(ctx, -1)); assert(false && "unable to compile katex.min.js"); } else { fprintf(stderr, "===katex.min.js successfully complied===\n"); duk_print_stack(ctx, "Stack afer compilation", __LINE__); duk_call(ctx, 0); printf("program result: %s\n", duk_safe_to_string(ctx, -1)); } // https://wiki.duktape.org/howtofunctioncalls duk_print_stack(ctx, "%d", __LINE__); if(duk_peval_string(ctx, "katex") != 0) { printf("eval failed: %s\n", duk_safe_to_string(ctx, -1)); assert(0 && "unable to find the katex object"); } else { duk_print_stack(ctx, "%d", __LINE__); } duk_print_stack(ctx, "%d", __LINE__); duk_push_string(ctx, "renderToString"); duk_push_string(ctx, latex_to_compile); duk_print_stack(ctx, "%d", __LINE__); if(duk_pcall_prop(ctx, -3, 1) == DUK_EXEC_SUCCESS) { printf("===katexed output:===\n%s\n", duk_to_string(ctx, -1)); } else { printf("unable to katex: %s\n", duk_to_string(ctx, -1)); assert(false && "unable to katex input"); } return 0;}