Wasm extensions

Hello.

I have been toying with my site recently to try different things. (Inclduing a small wasm package (called via JS) to justify some Arabnic poetry so it looks nice. I also experimented a bit with adding OpenGraph images for each article, but I found that the way to do it now would require a fair bit of processing the site structure outside of zola itself, either before or after zola build.

However, if there was a way for zola (or tera) to call extension functions in the template one could create a wasm module that calls typst (or whatever) , it would be then fairly possible.

speaking of typst, here is their plugin architecture: Plugin Function – Typst Documentation . It is simple from the implementation side, which I have used in a simple plugin (i would link but the forum wouldnt let me, but it uses the same module for kashida as it happens). I did something similar for rustybuzz, implementing the wasm shaper api.

The design question i think, besides whether yall want to go in that direction or not is what functions to expose to wasm, and how to call it from either zola or tera’s side.

This is a related post I found : Generate Preview Images . Now I am wondering if it is possible to call zola shortcodes from the toml frontmatter

So, browsing the zola codebase, I think the main gateay for making this happen is to use Tera’s register_function. Basically, after loading the WASM module, the exported functions are enumerated (with their signature). Instances of a hypothetical PluginFunction type (which implements the Tera Function trait) are created for each of these WASM functions, and .. Bob’s your uncle.

As a first experiment, I’d restrict exported functions to strictly take strings (or [u8]), and have the template user pass the output of things like get_page and page.description and what have you. The output would be similarly a stream of bytes, the encoding of which is determined by the plugin author. (could be an image ..)

So far, this closely mirrors the Typst architecture, incidentally, and it is specifically for pure functions only with no interaction with the file system, unless ..

No need for WASI shenanigans at all, but Zola could expose a number of functions that WASM modules can import. One possible idea of these functions would be create_file to create a file. create_file would take as input the file content (say a created image) and a desired file name and/or extension; and give as output the final path which then can be passed on to the exported functions. Implementation of this function is opaque to the module, but could for example create plugins/ directory in public where these files are saved. Any further capabilities to the plugin system would simply be more exposed functions to the modules (say a json site map .. the sky is the limit).

Plugins could even be registered wither with shortcode functions or global functions (with different exposed functions, maybe?). Say plugins in plugins directory register with globals and in plugins/shortcodes register with shortcods.

I’d be happy to work on this if y’all like the idea. It is not difficult work (I’ve done it before) just a bit time consuming.

There’s [Idea] Add lua or rhai function/filter/tests · Issue #87 · Keats/tera2 · GitHub as an issue but I don’t think i want to go full WASM?

I dont know enough about either Lua or Rhea runtimes to give you a comparison, but wasm is not that much overhead. (Like I’ve said I’ve done ie before).

The Typst implementation, for example, is as short as it gets and it is only complicated by Typst’s own parallel compilation thing and managing the runtime’s ownership.

Wasm is completely secure (only uses functions you expose), and is powerful enough to cover almost every use case. (Including OpenGraph images and MathML syntax in that other thread).

But it is much harder to write vs dropping a small readable file in a Zola folder for your own filter/test/fns, that’s the main thing people have been asking for.

Like I said, I dont know Rhai or Lua to make a fair comparion (and I dont know what others were asking for. I only know what I need).

I did some experimentation the past couple of days in scratch repos just to see how the code might potentially look like from either end. I wrote a summary of it in this article: Abdul Rahman Sibahi | Adding WASM Plugins to Your App

Obviously this leaves plenty of decision space like how the ABI and API looks like. this is just a sketch or a proof of concept.

One potential improvement to Tera that would make this a lot easier is to allow positional arguments in functions, or at least have arguments be stored in the same order they’re declared when the function is called, so iterating over args yields the arguments in order, instead of having to come up with a naming scheme.