@sissijs/muh

Muh

Muh (say: Moo!) stands for "mustached hypertext" and is the template language that runs Sissi, the static site generator. It is put into a single package so it can be re-used in other projects as well.

Muh comes in 2 flavors. Both of them live in the @sissijs/muh package.

@sissijs/muh includes everything. A full-fledged processTemplateFile function that supports SmolYAML/JSON frontmatter, layout files, basic preprocessing such as (a minimal) markdown, handling css imports and resolving <html-include src=""> directives. In roughly 10KB of JavaScript.

@sissijs/muh/template is just the template function that implements the mustache syntax. It also provides the built-in filters for formatting dates/numbers, and built-in helper functions. The helper functions provided are small wrappers around fetch, namely fetchText() and fetchJson(). All that is contained in roughly 4KB of JavaScript.

Sizes are measured with minification and without compression.

TypeScript declarations and API documentation are autogenerated from JSDoc.

The syntax is {{ moo }} where moo can be any arbitrary JavaScript. JavaScript is evaluated in a safe context. The only globals it can access are the ones you provide, plus a few built-ins.

When the evaluated expression is a promise, it is automatically resolved (or rejected). When the evaluated expression is a function, it is automatically invoked without parameters.

Under the hood, it uses node:vm, which makes it a node-only library (for now). It should work in Deno 2, as it provides some backwards-compatibility to node.js.

You can apply filters to your mustache expressions using the pipe notation. There are a few built-in filters:

{{ content | safe }} // dont escape html
{{ promise | async }} // resolve promises
{{ result | json }} // print json
{{ article.date | date: 'de' }} // 25.12.2024 (for first Christmas Day 2024)
{{ price | currency: 'de', 'euro' }} // 1.234,56 €
{{ fetchJson('/api/articles') | async | limit: 5 | each: templateFunction }}
{{ include('article.html', {title: 'Article Title'}) | safe }}
{{ '<' | htmlentities }} // &lt;
{{ ' ' | urlencode }} // %20

There are a few built-in helper functions:

{{ fetchJson('https://yesno.wtf/api') | async | json }}
{{ fetchText('https://some-html.api/api/weather') | async }}

{{ include('partial.html', {title: 'some additional data'}) }}

HTML-files can use <html-include src="partial.html" title="some additional data"/> directives. Additional attributes are passed to the include's data.

There is a basic markdown processor for markdown files involved. Markdown files also interprete the <html-include> directive.

Also, CSS import directives are resolved.

All file types mentioned above can also work with the mustache syntax.

const result = await processTemplateFile(
'<h1>{{ title }}</h1>',
'index.html',
{title: 'Test'}
);

console.log(result) // <h1>Test</h1>