Mitril.js is a client-side JavaScript framework (similar to React, Vue, Svelte, etc.)
My current go-to client-side framework is Svelte - 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 and Vue-Petite), 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 dialect like this:
m("div", {style:"color:red"},
m("a", {href:"/page2"}, "click here"))
which generates
<div style="color:red">
<a href="/page2">click here</a>
</div>
Alternatively, you can use JSX syntax (like with React), but then you need build-tools.
Another option is using the htm library to generate the hyperscript - which would allow the use of JavaScript 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 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.
The following is based on my experiences doing that.
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 havefetch
, and support async/await makingfetch
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, 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...