My thoughts on Mithril.js
Tags: mithriljs, javascript, webdev
Published: 2022-05-03 13:21:33

[Mitril.js](https://mithril.js.org) is a client-side JavaScript framework (similar to React, Vue, Svelte, etc.)

My current go-to client-side framework is [Svelte](https://svelte.dev) - which is amazing. The only real downside is that it cannot be used without build-tools.

So when I noticed that Mithril.js can be used without any build-tools (plain vanilla JavaScript) AND it has a tiny runtime (10 kB) AND it has real components - I was intrigued.

Having (real) components, sets it apart from other no-build / small runtime frameworks (like [Alpine.js](https://alpinejs.dev) and [Vue-Petite](https://github.com/vuejs/petite-vue)), because this allows for the creation of advanced full-size SPAs.

Basically Mithril.js covers both scenarios - "progressive enhancement" (like Alpine.js and Vue-Petite) and full-size SPA (like React, Vue, Svelte).

Could this be the one?
The single tool for everything?
The holy grail?

So I played around with Mithil.js over the weekend, to see what it was like.

With Mithril.js, you generate HTML using a [hyperscript](https://github.com/hyperhype/hyperscript) dialect like this:

```JaveScript
m("div", {style:"color:red"},
  m("a", {href:"/page2"}, "click here"))
```

which generates

```html
<div style="color:red">
  <a href="/page2">click here</a>
</div>
```

Alternatively, you can use [JSX](https://facebook.github.io/jsx) syntax (like with React), but then you need build-tools.

Another option is using the [htm](https://github.com/developit/htm) library to generate the hyperscript - which would allow the use of JavaScript [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) for a development style closer to JSX or the HTML templates used with Vue / Svelte.
The problem with this is that the templates would be re-compiled (by htm) on every single interaction with the app - which I imagine would seriously slow things down.

So the way I see it, the optimal way to use Mithril.js (without build tools) is to write the hyperscript style code by hand - which actually isn't too difficult once you get used to it.
The biggest problem is keeping track of closing parentheses/brackets with deeply nested elements.

### Reactivity / UI updates

Unlike the major frameworks (Reach, Vue, Svelte, etc.) Mithril.js does not update the UI in response to changes in application state / variables.

Instead, it updates the UI after each UI event has been handled (or whenever you tell it to by calling `m.redraw()`).

On each update it re-renders everything to a new virtual DOM, then diffs this to the previous version, and finally updates the real DOM with the differences.

This works surprisingly well. Dynamic and automatic UI updates - without any kind of state tracking. Very nice!

### Test project

I recently created a small SPA with Svelte here: <https://simpledns.plus/dmarc-wizard> (an in-browser tool to generate DMARC-records - an e-mail security thing).

So to try out Mithril.js, I re-created the same SPA using Mithril.js - see <https://simpledns.plus/dmarc-wizard-mithril> (should look and work exactly the same).

The JavaScript source code (which is also the production code) is available at <https://simpledns.plus/scripts/dmarc-wizard-mithril.js>


### Things that I really like

- Ability to cover both "progressive enhancement" and full-size SPA scenarios (see above).

- That no state management system is needed / included (see above).

- Everything, even HTML, is expressed in plain JavaScript. No "magic". This makes debugging in the browser much easier, makes code refactoring easier, and reduces the need for VSCode extensions etc.

- The possibility of using tiny render functions, for things that would require a separate a component (and file) in Svelte. This encourages and makes it a lot easier to be adhere to the DRY principle (don't repeat yourself).


### Things that really should be removed

- Mihtril.js (v. 2.0.4) includes a wrapper for ajax calls based on XHR. They even make a selling point out of this in the very first sentence on the web-site.  
This is 2022 - all browsers now have `fetch`, and support async/await making `fetch` easy to use.
Promoting XHR as a feature makes it sound rather outdated.
And I would rather have an even leaner base framework.

- Mithril.js also includes a routing feature based on "hash-bang URLs" - also a selling point in the first sentence on the web-site.  
This is of course nice to have - but routing is not needed for progressive enhancements scenarios (where I see Mithril.js having potential), and developers might prefer other routing schemes (like non-hash history-push/pop).
So please remove this / make it optional (making the base framework even leaner).

- Mithril.js includes a polyfill for Promise.  
This is 2022 - all browsers now support promise.
So please remove this / make it optional (making the base framework even leaner).

### Conclusion

Mithril.js has some really nice and unique features.

But, while the hyperscript syntax is doable for small widgets, I wouldn't want to use it in larger projects.

I just don't think that the hyperscript syntax is as readable as for example Vue / Svelte templates (standard HTML with as few additions).

And keeping track of those closing parentheses/brackets with deeply nested elements, just drove me nuts.

As the JSX docs put it (about [something else](https://facebook.github.io/jsx/#sec-why-not-JXON), but with the same issue):

> Unfortunately, the balanced braces do not give great syntactic hints for where an element starts and ends in large trees. Balanced named tags is a critical syntactic feature of the XML-style notation.

So to use Mithril.js, I would probably need JSX, which requires build tools. And if I have to use build tools anyway, then I still prefer Svelte...