📜 ⬆️ ⬇️

What I love is Mithril (aka MithrilJS)

Hello dear readers. If you opened this post, it means that spider web development (that is, the web front-end development, I wanted to say) is touching you. And before you start throw tomatoes thank the narrator, please read ... at least to the middle.


For writing the article I was pushed by simple reasons: there is a war for the hearts and minds of developers, and many respected software giants consider it their duty to alleviate the developer's fate (which is good, by the way). At the same time, do not hesitate to break his brain and nervous system (and this is not very). So to say, in the name of the happiness of future generations. Maybe I’m wrong, but I want to share with you information about a tool that I discovered long ago and haven’t been eating cacti like those mice: Mithril (MithrilJS) .


In principle, Mithril is not a silver bullet or a life-giving cross, but it is worth trying and using.


In a nutshell, this is a React-like framework without problems associated with managing a state, with routing and convenient methods of server requests out of the box. The API is very compact and fits on one page. The framework promotes the Piton principle "there must be one single and obvious way of acting." It is compact (6kb gzip) and fast.


“Pff”, the React-developer will think, “everything is like a React, why then is it necessary?”


I give the answer: when you program on React, you think not so much about the logic of the application, but about how to curb the furious control of the state of the application. Throw a tomato at me if it is not. Flux, Redux, MobX, state in components, higher order components, stateless components, component functions, etc. etc. Do not forget that we still need to choose a router (or make the simplest one) and a library for server interaction.


"Hey, use redux-saga, redux-thunk, react-easy-redux-saga-inegrator-with-router-and-holy-shit! And don't forget to create-react-app from the FB itself so that the project settings are easier" .
"Hey, you take Angular, it's a framework, not some kind of templating engine. But don't forget to compile the templates right away so that the bundle size is less than 2MB. wow, we even have one pepper in the team who understood how to make pipes on it. "


Hmm ...


And I just want to make a SPA. Maybe even on ES5. Maybe even without Webpack / Grunt / Gulp / Browserify / TypeScript / Flow. To connect the script on the page and drove.
"Yes you are a heretic! Burn him!" - many will exclaim.


Stop.


To be honest, I do not write SPA on ES5, but I write small scripts. And if this is not part of a large project, I would like to someday just be able to open the script and modify it, and not look with tears at the bundle and think where to look for the sources of the three-line script (which I didn’t even write).


About Mithril more


This is really React-like. Here we can say retrained. JS-first, everything is a javascript ... Yes, an option. We will work out this version.


Here is what the code on Mithril looks like. I will write on ES5. You can easily add imports, replace var with let and const, omit unnecessary functions, and use arrow functions if necessary.


I just want this post to be read by everyone, not just you, respected ninjas.


// store.js var store = { todosOrdered: [1], todoDetails: { // default for example 1: { title: '  ', isActive: true } } }; // components/Todo.js //        //     //    //     function handleTodoCheck(id) { store.todoDetails[id].isActive = !store.todoDetails[id].isActive } function handleTodoTitleChange(id, value) { //       console.log('id=' + id + ";value=" + value); store.todoDetails[id].title = value } //    var Todo = { //   view: function (vnode) { var id = vnode.attrs.id; //    var todo = store.todoDetails[id]; //          return( //  - //    CSS-,     'div.todo' m('.todo', { //   //    class: todo.isActive ? "active" : "no-active" }, [ m('input', { 'type': 'checkbox', onchange: handleTodoCheck.bind(null, id) //      }), m('input', { value: todo.title, //       onchange: m.withAttr('value', handleTodoTitleChange.bind(null, id)) }) ]) ) } } // components/Todos.js var Todos = { view: function (vnode) { return( m('.todos', //    store.todosOrdered.map(function(todoId) { //      return m(Todo, {id: todoId}) }), ) ) } } 

Here, as it were, everything about drawing and state management. Add salt and pepper to taste.
We have a hierarchy of components (one component - one task), they interact with the user and update our view.


In this example, there is a parent-child relationship, but it could have been without it. There are no pure functions and a time machine.


But everything is very simple, there is logging and it is clear what is happening. If desired, everything can be provided with additional debugging information.


If I want to do type checking, then I use TypeScript and perform argument type checking using interfaces. Like this:


 interface TodoAttrs { id: number } //   ";",       // const    ,  const Todo = { view(vnode) { let attrs: TodoAttrs = vnode.attrs //   1 let id = attrs.id .... const Todos = { view(vnode) { return( //  ,   store.todosOrdered.map(todoId => m(Todo, <TodoAttrs>{id: todoId})) //   2 ) } } 

I ask the snobs not to rush at me and not scold for a contrived example. It is clear that he is far-fetched. But in Mithril, everything is really easy - he is very close to authentic JS:


  1. A component is an object with a view function that returns a VirtualDOM tree. There are life cycle hooks, if necessary (oninit, etc.)
  2. When the arguments are changed, the component is redrawn.
  3. When you change the external objects referenced by the view () method of the component from other components, the component is redrawn.
  4. If you have done some magic outside the components and want to update them, call m.redraw (). The necessary components will be redrawn.
  5. Profit.

In the end, what do we see here? (I mean, including the listing above) A few correct, in my opinion things:


  1. We are not mad about how to exchange information between components. React + Redux? React + MobX? Or is it enough to Higher Order Componens? Maybe better Vue + Vuex? .. Why ?! (I already cry and cry). Take an external object (or several) and use it as a state storage.
  2. Adherents html-first (hi Vue and Riot, and Angular) as an answer to a possible question on the syntax:
    and what does DSL eventually turn into to implement loops, conditions, variable bindings, event listeners, etc.? What will it become in a couple of years and a couple of major updates of the framework? In my opinion, in not very obvious syntax with "variables inside text". And this is critical. And the application (and templates) on Mithril is easy to debug.

Separately about JSX


You can easily use JSX (as well as Babel, Webpack and everything else), the manual is in the official documentation.


On JSX it will look like this:


 // components/Todos.jsx const Todos = { view(vnode) { return( <div className="todos"> {store.todosOrdered.map(todoId => <Todo id={todoId} />)} </div> ) } } 

In general, compared with hyperscript type m('span.cool', "I'm cool") , the taste and color of all markers are different. I use hyperscript (such a title, yes), and the author of the framework recommends.


And further


Generally, Mithril has 8k stars on the githaba at the time of publication - maybe not so much, but more than in some highly discussed programming languages. The framework is mature: the current repository on the githaba from 2014, more than two hundred contributors and the latest update a few days ago.


I urge you to read the documentation and use the convenient functional tool in work, especially since there is nothing special to read compared to the folio "Angular for Professionals" (here I can not help but stop and rejoice that the creators of this wonderful tool made it so that later you can earn on training. Take an example, as they say).


I want to remind you that Mihtril has a routing


 m.route('/man', ManPage) 

And a convenient method for server requests


 m.request({ method: "POST", url: "/todo", data: {id: id, title: title}, //    withCredentials: true, //   }) .then(function(data) { // data -   JSON console.log(data) }) 

How to connect? Just 6kb gzip:


 <script src="https://unpkg.com/mithril"></script> 

Everything described above will work.


Well, or npm with all the whistles, of course.
There is a very lively community in gitter


If there is interest, I can (try) to translate the documentation. Indeed, I believe that Mithril is worth it.


I ask you not to scold me for using anglicisms, because, at the end of it, we have been working on computers for a long time, and not on computers.


That's all I wanted to say. Thank.


If where I made a mistake / did not make out / did not understand / did not appreciate, I am ready for constructive criticism.


Yes, I forgot, here are the links to the available benchmarks:
https://lhorie.imtqy.com/todomvc-perf-comparison/todomvc-benchmark/
https://developit.imtqy.com/preact-perf/


GitHub Repository


')

Source: https://habr.com/ru/post/341708/


All Articles