Meteor is a NodeJS framework that is increasing in popularity because it allows a developer to  develop in just one language, JavaScript on the client and JavaScript on the server and to develop applications that are real-time by default using Meteor's data everywhere principle and Web Sockets. These are just a couple of the reasons why Meteor is increasing in popularity and has recently reached version 1.0.

Mithril, whose name comes from a metal found on Middle-earth in the Lord of the Rings series, is a light-weight client-side MVC framework that uses virtual DOM "diffing" to make it fast. For those who are familiar with React.js framework, this is not a new idea, but on its website Mithril claims to be faster than React, Backbone, Angular, and jQuery. This article will not delve into execution time tests nor support or deny Mithril's claims. Rather, it will focus on how Mithril can be used with Meteor to ostensibly allow Meteor to load faster on the client and first impressions of using Mithril.

Meteor uses a built-in templating engine called Blaze that can be replaced by Mithril's templating engine fairly easily. Let's see how we can do this.

Meteor's power, or a big part of it, is its ability to update data on the screen in real-time. This is possible because of Web Sockets and Meteor's abstraction of Web Sockets in it's Distributed Data Protocol (DDP) and their "reactive data sources". As noted on Meteor's website:

DDP is like "REST for websockets". Like REST, it is a simple, pragmatic approach to providing an API. But it is websocket-based, unlike REST, allowing it to be used to deliver live updates as data changes.

To integrate into Meteor's reactive data sources to use with Mithril, we will tap into Meteor's Deps micro-library. Deps.autorun runs a function we can define anytime there is new data. Mithril comes with a convenience method called m that is used to compose virtual elements that can be rendered via m.render(). We can extend this to tap into the Deps.autorun with this code.


	m.reactive = function(controller) {
      return function(options) {
          var instance = {};

          var computation = Deps.autorun(function() {
              m.startComputation();
              controller.call(instance, options);
              m.endComputation();
          });

          instance.onunload = function() {
              computation.stop();
          };

          return instance;
        };
	  };

Here m.reactive takes a controller function as an argument and returns another controller function. Using controller.call(instance, options), we effectively copy properties on the controller to the instance and then can augment it. Deps.autorun registers a new callback that will run anytime there is new data in the Meteor Mongo database and we can effectively tell Mithril it's time to perform a "diff" by blanketing the controller.call(...) with m.startComputation() and m.endComputation(). Maybe it would be a good time to stop and briefly say what "virtual diffing" is.

Manual DOM manipulation is messy and costly in terms of time. A solution is to keep track of a virtual DOM by creating a virtual tree of the DOM elements and comparing that to the DOM elements currently rendereed. If anything needs to be changed, you can compare the updated virtual DOM with the currently rendered elements and update only those that need updating rather than re-rendering the entire page.

So, every time the data changes in the database, Deps.autorun will call it's callback function that had been registered and our DOM will be updated with the new data using Mithril's virtual DOM and diffing. Mithril has a convenient onunload handler method that will fire if for instance we navigate away to another page that doesn't use this controller. When it fires, it calls computation.stop() which means that we won't continue having the callback being called when Deps.autorun fires.

The above is an effective way to get ahold of Meteor's reactive data sources for use with Mithril. Now, if we are working on a project with one high-level controller and view, called say "App", we can use m.reactive on that and if all other views and controllers are nested below the App, it will make the whole application reactive.

App.controller = m.reactive(function (options) {
    var ctrl = this;
    ctrl.currentUser = Meteor.user();
    ...
});

While you can surely put the model, view and controller in separate files, one thing I really like about Mithril is that since all three are written in JavaScript, you can put them all in one file. Let's look at the three separately here though knowing that they could be in one file. Taking as an example a reply form to a question that is represented by a Mithril component called ReplyForm that allows for inputting a message in a textarea as well as uploading files to a cloud storage service which will return the download URL, here's what the model might look like.

ReplyForm.model = function(){
    this.files = m.prop([]);
    this.downloadUrls = m.prop([]);
};

m.prop is Mithril's getter-setter factory utility. It returns a function that stores information. this.files = m.prop([]) sets an array for this.files while this.files() will get the value for us.
In this model we have this.files that will store our file objects as we add them to a list and this.downloadUrls which will be an array of the download urls returned by our cloud storage in a callback function after a successful upload.

Next we have the controller:

ReplyForm.controller = function (options) {
  	var ctrl = this;
  	ctrl.uploads = m.prop(new ReplyForm.model());
  	ctrl.content = m.prop(options.content || '');      

  	ctrl.submit = function () {
  		// upload files
   	   upload(ctrl.uploads().files(), ctrl, options);
      	};
};

This code controls our reply form, and the user actions taken from the view. We set this to our variable ctrl for readability. In ctrl.uploads, we use the contructor function from the model to create an instance of our ReplyForm.model. Each reply form gets it's own instance of the model (we could have multiple replies to a question and multiple questions on a page) and is distinct in memory. We have several other getter-setter functions using m.prop and then a submit method. Within it, we call an uploads function not shown here (for simplicity) which handles the logic of uploading to a cloud file storage service (could be Amazon AWS S3, Google Cloud, Dropbox, or other). Note that to access the array of file objects that are waiting to be uploaded, we have to call ctrl.uploads().files() which is the give-away that we are dealing with two getter-setter functions. One is ctrl.uploads which accesses the this.files in our model which is our 2ns getter-setter. I like how easy and intuitive Mithril makes interactions between the controller and the model. I hadn't mentioned it yet here but an easy way to pass information down or up along nested views is using extra parameters. In the example above, we passed in options to the controller function which is an object. We could pass in the parent controller itself in that options object and make changes to the parent based on logic in the child and vice versa. Best practice is probably just to pass in the elements of the controller that are of interest to the child rather than the entire controller.

Lastly, we'll look at the view. As I said before, the view can be stored in the same JavaScript file as the model and the controller. "What", you say? "But a view is html, right?" Well, yes and no. What Mithril does is abstracts the creation of the DOM elements in the view. At first, the syntax might be a little hard to wrap your head around but you will quickly see the advantages of being able to manipulate the virtual DOM with JavaScript and Mithril.

Let's start by seeing what the view looks like visually on the DOM. This is a simple form which allows a user to enter a message and optionally upload files to a cloud service (like an Amazon S3 bucket) for easy download by end users. The form below allows the user to load various files and then upload them all at once. Next to some of the DOM elements, I've added the element name with classes for more clarity on what is happening when you read the code in the Mithril view.

ReplyForm.view = function (ctrl, options) {
    return m('.reply-form', [
        m('textarea', {
            value: ctrl.content(),
            onchange: m.withAttr('value', ctrl.content),
            placeholder: 'Enter your reply here. Markdown supported.'
        }),
        m('form.upload-container', [
            m('div.file-list', [
                m('h4', 'Files to Upload on Submit'),
                m('i.font-md', 'Add to Upload list'),
                ctrl.uploads().files().map(function(file, index){
                    return m('div.file-name', [
                        m('span', file.name),
                    ]);
                }),
                m('input.file-upload[type=file]'),
                m('button.upload-submit[type=submit]', { 
                    onclick: function(el){
                        el.preventDefault();
                        getFileToUpload();
                    }
                }, 'Add to Upload List' )
            ])
        ]),
        m('button.btn.btn-primary', { onclick: ctrl.submit() }, 'Submit'),
    ]);
};

This probably looks daunting but we'll go through it line by line. At the highest level it creates a div which contains a textarea element, an input for selecting files for upload, and some buttons.

Notice that ReplyForm.view is simply a function that will be passed the corresponding controller. We also pass it options which you might recall is an object that was passed in by the parent component when it instantiated the ReplyForm. The way Mithril handles placing elements on the DOM is with a return statement and calling m('',...).

The top level element is a DIV with the class "reply-form". Notice how with Mithril, we simply call m('.reply-form', [...]) to create the DIV (we could also have written div.reply-form'). And then we pass an array to the m component as the second argument within which all of the nested elements will be placed. So, we use an array in Mithril for nested elements.

Within the reply-form div, we have a textarea element followed by a form element, which has its own nested elements, and then a button for submitting the form. Notice how the mithril m call to create the textarea element can take (optional) a second argument which is an object containing the properties on the element we want to set. In this case, the object looks like this.

{
    value: ctrl.content(),
    onchange: m.withAttr('value', ctrl.content),
    placeholder: 'Enter your reply here. Markdown supported.'
}

The two-way data binding for the value is set with the onchange event and m.withAttr which is Mithril's way of updating ctrl.content when anything changes. Placeholder text is set using the placeholder property.

If the 2nd argument passed to m when creating an element is not an object, Mithril assumes there are no extra properties you want to add to the element. If the second (or third) argument is an array, Mithril assumes these will be the nested elements (as previously mentioned). Otherwise, if the second (or third) argument is a string, Mithril uses this to set the value property on the element.

On lines 12 - 16, note how we are using map to create span elements with the data within the array stored in ctrl.uploads().files(). This is an elegant way in Mithril to use functional programming to create DOM elements from a data set.

I find Mithril's syntax easy to use and intuitive after spending a little time playing with it. And I really like using JavaScript for everything.

Feel free to comment below or leave feedback.