Quick start guide for any node-based SPA with Mithril

A few weeks ago, I was tasked with creating a single-page application for a company. Like with any other project that I'm tasked with, I set down and did some thinking. Knowing that such a big project won't be an easy task, I did some brainstorming and came up with the following guidelines for this particular project:

  1. Simple application structure
  2. Simple and easy to get into
  3. Low dependancy
  4. Small footprint

Let's break it down. The reasoning behind point one and two is development speed. Keeping simple structure and working on something that's easy to get into, greatly decreases the amount of time required to study. I also wanted to keep things very simple and KISS so point three. The more dependancy you tie yourself to, the more information you have to keep in head while programming. In addition, since this was a single-page application that I know won't be run on fast computers (understatement of the year), I added point four.

Please note that these were the terms I came for this particular project. Each application or project requires a different solution and there is never a one sure-fire way for everything. In any case, with those guidelines firmly placed, I head out onto the internet to do my research.

Choosing the right framework

Right from the start, we can exclude Angular. Even without having done much of any work in Angular, I saw quite a large amount of trends going on and on about Angular's steep learning curve, complex documentation, many gotcha's and lots of other things. This article summarises pretty well an alarming amount of things that immediately turn me off from using Angular.

A few that did catch my eye though were Backbone and React. Backbone has a pretty simple api with very small codebase but it does very little by itself. This left me with React which I was beginning to like... until I met Mithril.

Mithril is similar to React in terms of how it handles the DOM updating. However what I liked about Mithril was firstly that it has amazing speed, has a much simpler application structure ideology that I can get behind of and finally, is simpler than using React. As an added bonus, it has request handling and couple of other features missing in React in a much smaller size footprint (5KB gzipped O_O). Since that nails pretty much all points the above guidelines, I ended up choosing mithril.

Compiling the files (and how I fell in love with npm)

For SPA, it's pretty important to be able to break down your application into smaller pieces during development and easily compile them together for production. For this I set out to search for methods that provide the means for compiling javascript files, stylus and all other resources I might have.

Currently there are two popular task runners on the internet: Grunt and Gulp. Unfortunately neither really fit my paradigm of simplicity. At my old workplace, one coworker created a grunt script for compiling asset resources for particular project. The script was long, complicated and complex and according to him, took a long time to create. The popular alternative is gulp which has a more programming-friendly structure. But even that can complicate your application pretty quickly, not to mention having to dive into yet another huge library and the documentation that come with it.

I won't be going into how installing tons of plugins and complicating the dependancy to no ends for a simple compiling feature and instead open your eyes to the wonders of npm.

Npm actually has scripting features but what's cool about it though, is it runs every command in the project's environment. This also includes all the node_modules... modules and their binary files. Combine that with the fact that many of the asset compilers for node come with command utility and we've got an extremely simple yet powerful tool in our hands.

For those sceptics out there, I would like to point out this wonderful article that explains the wonders of npm for this purposes and how you should never use grunt or gulp.

I'll show you how easy it is to make create a task to compile all stylus files and javascript files straight from inside package.json (taken from nfp_www's package.json). I'll even add msx compiler (mithril's equivalent of jsx for React) in the mix since we'll be using mithril:

{
  ...
  "scripts": {
    "build:styl": "stylus -I node_modules assets/styl/main.styl --out dist/css",
    "build:msx": "msx -x jsx --no-precompile assets/js/ assets/js/",
    "build:js": "npm run build:msx && browserify assets/js/main.js -o dist/js/main.js",
    "build": "npm run build:js && npm run build:styl",
  }
}

The beauty of this:

  • Very few dependancies.All of the above scripts only require msx, browserify and stylus to be installed.
  • Clean project directory.Don't need Gruntfile.js or install grunt/gulp globally or anything like that.
  • Much easier to debug and troubleshoot.

And there you have it, in a few minutes, we've completely created all the compiling features we could possible want without the added load of learning yet another library or task/build systems or polluting our project files.

The server

Of course, having the files and being able to open them on the browser are two completely separator job. However polluting my front-end mithril application with lots of back-end server files was not my idea of fun ride. I actually tried it at first and the outcome to my project dir was... not my idea of simple: https://github.com/nfp-projects/nfp_www/tree/7e25dea4e0dfb285353efc8bb85464ddbed0f408.

For that I decided to continue using npm scripting capabilities and make my own server package that can be run entirely in command-line.

Enter: Spserver - Single Page Server.

Now, instead of spending time and space on back-end server logic (which would either way be obsolete on production when using nginx) I can just do this:

sudo npm install -g spserver  
spserver -f assets/index.html -s dist -p 3000  

Abobve command will serve static files from ./dist folder and use ./assets/index.html as the default response for all other requests (allows us to utilize mithril's route mode pathname).

That's it. One package, one single command and we've got a running server to develop on in any enviroment or setup.

Bower? Npm got your back

I don't think I want to get into why I think bower is a bad idea. With almost every single library available on npm and using browserify to compile your main javascript file, you won't need bower (in most cases).

Need lodash? Just npm install lodash and use var _ = require('lodash'); in your code. Simple as that.

It also makes the compiling step a lot easier since you don't need to download bunch of bower components, combine those seperately from your main project file or ant step like that.

Result

Following the above step, we should have everything we need in just a few minutes to make our own MVC/MVVM/SPA/:

Root  
│   package.json
│   README.md
│   LICENSE
├───assets
│   │   index.html
│   │
│   ├───js
│   │       main.js
│   │
│   └───styl
│           main.styl
├───dist
│   ├───js
│   └───css
└───node_modules

Just look at that simpleness and cleanliness.

Now we just need to add some html to the index.html and some mithril code into our main.js to start building our application. For an example application structure, check out my nfp_www project.

As an example, here's something to get you quickly up and running assuming you're using the above example folder structure and package.json sample:

Install Mithril for browserify

npm install mithril --save  

main.js

var m = require('mithril');

function layout() {  
  return m("div", {class:"container"}, [
          m("div", {id:"header"}, "This is the header"), 
          m("main", {id:"content"}, "This is the content"), 
          m("footer", {id:"footer"}, "This is the footer")
         ]);
}

m.render(document.body, layout());  

index.html

<!doctype html>  
<html lang="en">  
  <head>
    <meta charset="utf-8"> 
    <title><%- name %></title>
    <link rel="stylesheet" href="css/main.css">
  </head>
  <body>
    <script src="/js/main.js"></script>
  </body>
</html>  

Run \o/

npm run build  
spserver -f assets/index.html -s dist -p 3000 
Show Comments