Riot.js — The 1kb client-side MVP library
Tero Piirainen • 2013-11-01
An incredibly fast, powerful yet tiny client side library for building large scale web applications.
Riot.js is a client-side Model-View-Presenter (MVP) library that weighs less than 1kb. Despite the small size, all the building blocks are there: a template engine, router, event library and a strict MVP pattern to keep things organized. On a finished application the views are automatically updated when the underlying model changes.
Here is how Riot stack up to some of the popular client-side frameworks.
Less application code
Here's the amount of keystrokes to build the Todo MVC application:
MVP design pattern
Riot uses Model-View-Presenter (MVP) design pattern to organize your code so that it's modular, testable and easy to understand.
Just like in MVC (Model View Controller) or MVVM (Model View ViewModel), the purpose is to separate your application logic from the view, but MVP is simpler. Let's take MVC for comparison:
MVC is more complex. The many arrows form a circle. The role of the controller is not clear, and the pattern can be interpreted in many different ways. In fact, this is the root cause for the explosion of client-side frameworks.
MVP, on the other hand, has less room for interpretation. The role of each part is clear. It works for big and small projects, and is the best pattern for unit tests.
Let's see how MVP works in Riot.
Riot models define your application. It's your business logic exposed to outer world with a well-thought API. A completely isolated, testable unit that can be run in browser and server (node.js). Here is one for the Todo app.
You have the freedom to build your models in your preferred way using the
prototype object or the object constructor
Observables are they key for separating the model from the rest of your application:
After the above call the given object is able to notify others when something crucial happens. The views can re-render themselves or the users of the API users can make their extensions by listening to the changes.
Observables are the key to splitting your app into maintainable components. It's a classic design pattern to separate the Model from the View (4).
"We want a loosely coupled architecture with functionality broken down into independent modules with ideally no inter-module dependencies. Modules speak to the rest of the application when something interesting happens and an intermediate layer interprets and reacts to these messages." — Addy Osmani, Creator of TodoMVC
"The more tied components are to each other, the less reusable they will be, and the more difficult it becomes to make changes to one without accidentally affecting another" — Rebecca Murphey, author of jQuery Fundamentals
A good event library is the single most important feature in a client-side framework. And this is where Riot places the biggest focus.
The observable call adds following methods to the given object:
trigger(event_names, args...)— trigger a named event with optional arguments
on(event_names, fn)— call the given function when a particular event is triggered
one(event_names, fn)— call the given function once when a particular event is triggered. additional events cause no action
off(event_names)— stop listening to a specified event
The difference between jQuery events is that there is no
Event object (6) because it's not relevant outside the DOM. You can also send and receive arguments nicely without wrapping them to an array:
Observables were introduced in 1988 by Smalltalk and have been used to build user interfaces ever since. It's a design pattern, not a framework. Events and listeners are the essence of good code with separated concerns. They should be a core part of your mindset.
Let me put this in another way:
You don't need a framework to write modular client-side applications.
View is the visible part of your application. Text, images, tables, buttons, links and the like. The HTML and the CSS.
Riot views are as dummy as possible. No conditional statements, loops, or data binding. No custom attributes or custom elements. These should be absent from the view. Views are something you can expect from any HTML developer.
There are only "templates" — fragments of HTML that can be inserted in the view at runtime. These templates contain variables that are substituted with data using the extremely fast Riot template engine.
Here's one for a single TodoMVC entry:
This kind of "logicless HTML" has no weak spots or testable surface. It's faster and passes W3C validator.
The actual logic is inside the presenter.
Presenter has all the user interface logic. It listens to what happens on the View (click, scroll, keyboard, back button etc) and on the Model (things are added, removed or modified) and it updates both view and model accordingly. This "middleman" explicitly defines how the user interface behaves. Here's one for the Todo app:
I have put all the logic inside a single presenter, but there can be multiple presenters performing a separate task. For example, I could have put all the logic for a single todo entry in a separate file.
Feel free to decide the role of each presenter that makes the most sense for your application. This can be based on the role on the UI (sidebar, account, header...) or based on functionality (login, join, create, remove...).
There is a depressing misbelief that jQuery leads to "spaghetti code". Nothing could be further from the truth. What people refer to as spaghetti is in fact a mixture of model and view code. To avoid it, simply separate your model code from the view with observables. You don't need a framework for that.
MVP pattern with jQuery is everything you need to build user interfaces.
The worst thing you can do is to ditch jQuery for the wrong reasons. It's a high level API that produces elegant and readable code. The expressive syntax is concise and requires few keystrokes. There is a huge community, extensive documentation, and it works on all browsers. Feel free to use all the aspects of jQuery without fear.
Current data-binding frameworks promote the use of spaghetti on the HTML layer. Suddenly the
onclick attribute is back! (I'm looking at you, Angular). Programming books have told us to keep things separated and in the web this means the following (8):
Riot takes a puristic approach and does not allow you to do mix any logic inside HTML views. This is also the reason why Riot templating is fast – the templating logic is so simple.
This is a Riot!
Current client-side frameworks base their existence on false assumptions:
- There's a big mass of common problems
- MVC (or MVP) requires a framework
- jQuery leads to spaghetti
These are not true.
Current applications can be faster, simpler and smaller. They can be maintained with less knowledge and less code, less knowledge, and less worries.
No "Backbone way", "Angular way" or "Ember way". Frameworks come and go but classic programming skills are forever.