Development by Mithril. Practice, experience and pitfalls



    Synopsis


    This article is based on development experience, an application of a system constructing typical Landing-pages according to parameters predefined in the control panel. The article will describe why Mithril was chosen for application development, its properties, advantages and what pitfalls can be found when using this wonderful tool.

    Who might be interested in this article?


    This article may be of interest to those who study the use of micro-frameworks for solving certain problems that require convenient supported tools, with an easy and practical architecture, and not loaded with a common shell. In addition, Mithril as a tool despite its small size has high performance - which is also an important factor when choosing the right development tool. Interesting?

    Why exactly Mitrhil? Motivation for use



    Briefly about Mithril itself - what is it and what is in it.


    Mithril is an MVC micro-framework whose display model is based on the Virtual DOM, which also adds rendering performance for large applications, or for widgets that are compact but complex in terms of the rendering logic. Mithril has everything you need to call yourself a complete framework. There is a system for working with logic - controllers, tools for working with the binding of model data, and a complete system for working with rendering. It also provides utilities that allow, at a low level, precise control over the time and type of content redrawing (for example, for complex asynchronous operations), and compact additions:
    • Router - which allows you to bind components as pages to a specific address in the browser.
    • Web Services - methods that allow you to work with online data requests via http (s), in which the adaptation behavior for the framework features is built-in.

    All of these components and components allow you to develop applications on mithril that will cover 90% of the needs while writing code.

    Why did you choose Mithril?


    During the development of the architecture, the choice was between the client and the server organization, given that the system itself was essentially minimally loaded with data, and all of them were typical, processing all requests, additional overlays in the form of processing templates, their output, and the client waiting for a response - were extremely unpleasant factors, since in our time the download speed and “instant” readability of the content is extremely important, and the extra load on the equipment is an extra cost.

    Therefore, we soon discarded the server implementation option, and began to consider options for client-side tools that would allow us to solve with a small amount of blood (and extra spent nerve cells) a range of tasks:
    1. Tool performance.
    2. Convenient data organization.
    3. Management and speed of drawing.
    4. Browser support: starting with IE9, as well as mobile browsers.
    5. Convenient and practical logic control, without redundant “applied” interactions
    6. Maximum compactness of the tool, without excessive functionality.
    7. Coming from the previous statement - the maximum “vanilla” of the instrument.
    8. Quick connection to the development of new developers not familiar with the tool.
    9. The ability to adapt in the future, taking into account SEO.
    10. Component-independent development - without the need for monolithic solutions.


    Among the tools under consideration, we considered many libraries like - Angular , Angular Light , Backbone , Knockout , React . We also considered not only ready-made frameworks and complex tools, but also separately template systems, data libraries, etc.

    Reasons for sifting out other tools

    Why were all of these options discarded during analysis? Here is a short overview of the list in which these tools were not relevant in the selection.
    Angular and React are not suitable immediately because of their redundancy, because 99% of their functionality and organization are not needed in the process.
    Backbone - was eliminated due to excessively redundant logic, which remained atavism of distant times, and development on it would put us before the choice of almost direct control of all content, and the generally implicit logic structure.
    Knockout- An excellent library, but too large for the set of manipulations that are embedded in it, there are a lot of them and initially they are designed for a large amount of code for rendering in templates (with connection with data in logic and models). The control of logic as well as in Backbone is very specific, although it allows you to work adequately with data and binding. In our application, this functionality was redundant - and it was decided to abandon this option as well.
    Angular light- A micro analogue of angular with declared similar logic, including templates, and "lazy" directives and components. From the original logic and behavior of the directives from angular there are not so many, a simplified but similar template system, a comparison system in the tree and initialization of directives - by tag, class, attribute, and the similarity of $ scope binding. A good tool - but it has a rather specific and not very flexible component construction logic, and there were also initial difficulties in understanding its exact operation. This option remained spare and working until the very end.

    Mithril

    When mithril fell into the sight of the choice of a tool - it was already a quite mature and successful project of a set of tools for writing applications without frills, but with full functionality. This tool did not have those atavisms or excessive template logic like Backbone or Knockout - in fact, mithril was a small shell over DOM elements, most of the events of which were directly tied to DOM methods, with a little sugar added in the form of a Virtual DOM and bound to an object controller logic. At the same time, data binding, and most of the excesses were excluded from the logic - which opened up maximum flexibility for implementation. He collected all the minimalism and practicality that is necessary when developing capacious and extensible applications. Unlike Angular Light, it had a more transparent component logic,

    Bringing beauty - sugar, convenience, utility


    By default, the development of components on mithril is really a process in which absolutely nothing rules, for greater convenience of development, you can use many different tools and libraries to your liking, but I think that there is a basis that will be useful to everyone who begins to develop their applications on mithril.

    General Tips, Templates, Classes, and OOP

    Templates
    By default, in Mithril, as in React, it is rather inconvenient to organize the writing of template nodes, even despite the simplification system for building the DOM element query:

    // Объект контейнера с атрибутом "class" элемента.
    m('div', { "class": "container-class" }, [
      // .. и дочерним элементом заголовка, в в котором задан статичный аттрибут через упрощение шаблона. Со значением.
      m('h1[withattr="attr"]', {  onclick: function(event) {  /*  манипуляции для события */  } }, 'Header')  
    ]);
    

    This feature is especially felt if you are used to using regular HTML, and do not want to bother with the complexities of the mithril display architecture. There is a special transformer for this - MSX , and shells for it - such as the most convenient babel-plugin-mjsx in my opinion for the Babel compiler.
    Which allows you to use similar designs that we are so familiar with from React JSX:

    { /.../ } }>Header


    In my opinion, this option (MSX) will be very convenient to use with this kit:
    gulp + browserify + babelify + msx .
    Here is a usage example.

    // Опции и конфигурация компилятора Babel с необходимыми нам опциями и флагами.
    var Compiler = babelify.configure({ 
      // Флаги компилятора интегрированные в babel core
      optional: [
        'es7.exponentiationOperator',
        'es6.spec.blockScoping',
        'es7.exportExtensions',
        'es7.classProperties',
        'es7.comprehensions',
        'es7.decorators'
      ],
      // Дополнительные кастомные плагины преобразований
      plugins: [{
        transformer: MSX, // Собрать MSX 
        position: "before" // Вызвать до основной компиляции
      }]
    });
    gulp.task('babel-msx', function() {
      browserify([ /* файлы для компиляции*/ ])
        .transform(Compiler).bundle() // Интеграция промежуточного трансформера Browserify
        .pipe(source('bundle.js'))
        .pipe(gulp.dest('build/'));
    });
    


    Classes and OOP
    In 2015, ES6 ( or its extended draft sugar version ES2015 “ES7” ) and ESL compilers like Babel or Typescript that converted it to ES5 began to become especially popular : many wanted to fully start using its maximum features, including support classes, decorators, and more. Already existing frameworks (for example, Angular 2.0 ) began to adapt to new realities , and also appeared - like for example Aurelia , and therefore the use of all the features, and the flexibility of the tools for these features - for many can be an important factor in the development.

    By default, Mithril is organized inside a regular object, which can be an independent component in the architecture, and the organization’s special features for use as classes are not implemented in them, for reasons of the same minimalism, but this does not mean that you cannot expand or adapt to Object Development in this instrument.

    In the simplest case, you just need to use the component object as an instance of the class - for example, like this:
    
    /*  Класс компонента */
    class Component {
      constructor(opts) {
        /* связывание экземпляра с даными инициализации... */
        this.opts = opts;
        /* связать функции с областью экземпляра */
        this.controller = this.controller.bind(this);
        this.view = this.view.bind(this);
      }
      /* контроллер компонента */
      controller(props) {
        return {
          paramOne: this.opts.paramOne
        };
      }
      /* метод отрисовки компонента*/
      view(ctrl, props, children) {
        return (
          


    This is the easiest way to use classes in Mithril - but nevertheless it is still not an ideal option, in which it is also worth considering some features, for example, do not store absolutely all the data in an instance, and suppose they are stored in view - so you do not illusory risk say goodbye to data during subsequent redrawing - so the logic and data are better to keep separately. At the same time, storing data and manipulating them in the controller is also not the best way out - then you will have to create a whole dependency tree, in case you have to transfer data deep into the component hierarchy, which will not add simplicity and support to the already “vanilla” code.

    For example, you can use it when building the Flux Store application or any other storage that you prefer to use - and adapt it inside the component, then you will have a clear hierarchy of data storage, processing, and a clear border of abstract event operations inside the instance - like the index of the activated tab, etc. Event actions you can bind to the renderer, rendering, and even create a makeshift semblance of a living cycle in React with their componentWillMount, componentDidMount etc.

    Architectural features, pitfalls, personal notes


    Drawing

    Mithril is based on the Virtual DOM and this is one of its distinguishing features, which gives it its speed and performance, but considering that it is a minimalistic framework - there are some features in its rendering system that initially may surprise developers a bit, for example, those who already had some experience in React . For example, in Mithril, you cannot control the redrawing of a single node or component separately from all other components - as you could do for example in React. And this imposes some difficulties with understanding - so it’s worthwhile to understand how redrawing works in Mithril.
    There are 2 types of redrawing available in user access:

    m.startComputation / m.endComputation- methods that allow you to work with the organization of the state when redrawing, literally - they indicate the segments of the first snapshot of the VDOM tree, and the second snapshot, after that both snapshots are compared, and after the changes found, they form a patch - which changes the data pointwise. This is useful, for example, when loading asynchronous data, in which case you take the first snapshot before starting operations, and take the last snapshot after you get the result. Of the features, it is worth noting that the methods globally compare the entire tree as a whole, even if you called them in any particular component, so you should take care when developing so that redrawing does not affect other components in the tree. Here is a simple use case:
    function asyncGetAndRedraw() {
        /* Создаем снимок до целевого действия */
        m.startComputation();
        /* Асинхронная операция */
        SomeAsyncOperation({ ...args }).then(function promised(data) {
           /* обновление данных (которые используются в представлении) */
           setTarget = data;
           /* создание снимка после целевых действий, сравнение с первым снимком, патч представления */
           m.endComputation();
        });
    };
    


    m.redraw is a method for hard rendering, when this method is called, no comparison is made, the method completely redraws the entire tree of components, it should be used with extreme caution - because when redrawing it does not take into account the existing state of the components.

    Using plain HTML in components

    This is a rather dangerous and not recommended operation, but there are times when you need to insert a line of template pure HTML, and the m.trust method will help with this , here's how to use it.

    m.render("body", [
        m("div", m.trust("

    Clean Html

    ")) ]);


    Finally


    In this short article, I examined what might be of interest to the Mithril micro-framework when developing web applications, what advantages it has, comparative analysis with other tools (for personal assessment and needs), as well as some sugar and notes on the use of this framework by ordinary people . From the above, I think it is worth emphasizing that Mithril is primarily intended for writing compact, capacious web applications (for example widgets) that need maximum efficiency and conciseness in the development - coupled with performance. Although if you carefully consider the architecture, add your implementations, methods, and a couple of superclasses and decorators as shells - this tool will not let you down on large projects and web applications. The article stated my opinion and observations on the use of mithril - if you also have experience using this system or the subtleties that you discovered for yourself - it would be very interesting to know about them. I hope that the article was interesting and useful to read.

    Additionally


    An official site.
    Github framework page
    Useful articles about using Mithril

    Also popular now: