There is no shortage of front-end frameworks and libraries to choose from, but Riot.js offers something unique. It’s incredibly simple, lightweight, and a flexible framework, making it a nice choice for rapid prototyping and scaffolding web applications.

A way to look at Riot in the realm of JavaScript frameworks is as a happy medium between both React and Vue. It’s as lightweight as React, but doesn’t impose JSX, and as encapsulated as Vue, but doesn’t enforce strict development semantics. These two factors alone make it appealing, but it also invites bad practice and can lead to a disastrous stack with lack of better understanding for the Riot ecosystem.

Let’s take a look at the dos and don’ts of Riot, as well as realistic expectations to have for building both websites and web applications.

Prior to building a new website or web application with Riot or incorporating it into your existing stack, you should ask yourself the following questions:

How UI intensive is my website or web application going to be?

2. How much data are my tags going to be consuming, and how frequently am I going to be hydrating my components?

3. What is the expected life time of my given website or web application?

Understanding these constraints can make or break your website or application.

When to Use Riot

This micro framework can easily be adopted into most existing websites because of its minimalistic nature; it is just a computed view layer. Regular websites without many data pipelines running on web software like Wordpress, Joomla, or Drupal are perfect candidates because you can leverage their mature REST APIs to build rich reusable components. Take for example the following tag:

Tag For Wordpress — Fetching Posts



<wp-posts>

<div if={ error }>

<h1>Could not retrieve posts</h1>

</h2>{ error }</h2>

</div>

<div if={ !posts }>

<h1>No posts found</h1>

</div>

<div>

<div each={ post in posts }>

<div>

<h1>Title: { post.title }</h1>

<div>

{ post.content }

</div>

<span>Link: <a href={ post.link }>{ post.title }</a></span>

</div>

</div>

<button click={ getPosts }>

</div>

<div if={ updated }>

<h1>Last Updated: { updated }</h1>

</div>

<script>

var self = this

self.posts = []

getPosts() {

return fetch(‘//wp-json/posts’)

.then(res => {

res.json()

.then(data => {

delete self.error

self.posts = data

self.update()

})

.catch(error => {

self.error = error

self.update()

})

})

}

self.on(‘mount’, self.getPosts)

</script>

</wp-posts>

The tag in the example above is a reusable plug and play tag that we can actually place into any Wordpress template. What makes Riot so appealing is that even in limited environments where bundling with Webpack, Browserify, Gulp, or Grunt isn’t viable, the client side compiler is hasty enough that with smaller websites the compilation time is so fast it’s hardly, if at all, noticeable. In the event you do want to bundle your tags, Riot’s CLI, which is automatically installed with the node module via NPM, can also be used to create bundles without having to set up any of the build tools mentioned previously.

Riot can be a pleasure to work with for both experienced, and inexperienced JavaScript developers, because of how easy it is to pickup. The level of productivity greatly exceeds the time investment to learn the framework. At the end of the day, Riot at its core is just vanilla JavaScript and HTML. It’s perfect for building minimal web components without any accessory overhead, and can be useful if you’re looking to modularize and modernize older, monolithic websites exercising frameworks like jQuery. Not only can you decouple your view from the user experience, you can develop rich self-contained components to be reused throughout your entire website.

jQuery Counter

<h1>Count: <span id="counter">0</span></h1>

<h2>Updated: <span id="updated">-</span></h2>

<button id="count">Click Me</button>

<script>

var count = 0

$('#count').click(function() {

count++

$('#counter').text(count)

$('#updated').text(new Date().toLocaleString())

})

</script>

The code sample above is a very basic, rudimentary counter using jQuery to listen on our provided button’s click event and update our view accordingly. Using vanilla JavaScript and Riot component semantics, we can write up the same functionality in an encapsulated component to reuse how we see fit. Riot has the ability to convert just about any major JavaScript framework into a component with minimal effort.

Riot Counter

<counter>

<h1>Count: { counter }</h1>

<h2>Updated: { updated || '-' }</h2>

<button click={ increment }>Click Me</button>

<script>

this.counter = 0

count() {

this.counter++

}

this.on('update', function() {

this.updated = new Date().toLocaleString()

})

</script>

</counter>

Because of this, Riot is a perfect solution for developers new to web components, and seasoned developers wanting to rapidly prototype and build their websites or web applications. It’s a straightforward implementation of web components with a minimal footprint that strives for simplicity above all else, providing enjoyable syntax and a favorable learning curve. As explained by the Riot team themselves, Riot is a small framework, but it is a complete solution for your front-end needs. There is no proprietary state management system, there’s no need for any polyfills, or additional libraries, and it can be compiled both in the browser and bundled with your favorite build tools.

Riot vs Competitors

The three frameworks most commonly compared to Riot are React, Vue, and Polymer. The most prevalent similarity between the three is their shared implementation of web components. React and Vue use a virtual DOM at their core, where Polymer uses a shadow DOM. To simplify, the HTML DOM is a tree structured map of nodes, making it very easy to traverse and execute simple operations.

Although the HTML DOM was designed with simplicity in mind, the push for more complex web applications makes the traditional HTML DOM too bloated. The virtual DOM is an abstraction layer of the HTML DOM allowing React and Vue to bind components, directives, and other features of their own to Nodes and execute different computations and operations without having to run a myriad of operations against your given web page to try and find the attributed node.

You can think of the virtual DOM as a copy of tagged references to each Node your component or framework specific feature exercises. The virtual DOM was a brilliant solution to a pressing concern in the field of front-end web development, and though React and Vue weren’t the first to inherit the methodology, they’ve definitely helped mature and progress it’s implementation into modern web development. The shadow DOM, on the other hand, isn’t necessarily about performance, but encapsulation. The shadow DOM was created to encapsulate the DOM tree, meaning you can encapsulate a given set of style rules and JavaScript to target your specific web component, rather than applying these rules to the entire DOM tree. In a way, this can also drastically improve website and web application performance if leveraged correctly. Polymer is essentially a wrapper for the official Web components API driven by the shadow DOM to provide the experience of a modern JavaScript framework.

So, where does Riot fall?

Well, it’s sort of a gray area. By definition, Riot would technically classify as a virtual DOM implementation; but it still technically traverses through the DOM tree. Riot 3 uses expression binding, so it extracts the dynamic aspects of your given component’s template and re-evaluates them when an update occurs; this is similar to the dirty checking done by Angular.js. This unfortunately means that Riot can, and will suffer from the same performance issues that plague Angular.js, but these concerns can be expelled by using good practices and properly using the Riot observable (though misuse of the observable can lead to disastrous architectural anti-patterns).

Riot’s implementation isn’t all bad though, in fact it will perform just about as well as both Angular and Vue for smaller to medium size applications. Underneath the hood, the non dynamic parts of a given component are cached for re-use, and when an update is triggered by the observable-only the dynamic parts get re-rendered. This is again similar to Angular.js, but more resource performant because the observable works as a push-like mechanism, where Angular.js watchers work in a brute force pull based fashion. Riot observable methods are either triggered by bound user events, or triggered manually.

Riot’s Adoption Rate

Adoption for Riot.js has overall been moderate, and the reason it hasn’t been widely adopted yet is due to many underlying factors. The greatest reason for this of course being the momentum for React because of its backer, Facebook, and high profile adopters like Netflix and Microsoft. On the other end of the scale we have both Angular.js and Angular 2, which are backed by Google. Vue gained some overwhelming traction in 2016 and 2017 in part because of its great PR and its adoption by Alibaba and high profile developers like Sarah Drasner.

We also have Ember.js, which is currently also being used by Netflix, Microsoft, Travis CI, Linkedin, and Ted. Riot most certainly arrived on the scene a tad too late, but it’s still gaining some momentum as the framework continues to mature. Unfortunately, at the time of writing, there aren’t many enterprise level adopters aside from Muut, the creators of Riot and Honda. Riot 4, however, does promise an even smaller core library and is going to merge with the Simulacra project for it’s primary rendering engine that does yield benchmarks remarkably faster than React (React 15.4.2 vs Simultra 1.5.5).

Riot saw a growth of 55% on NPM between 2017 and 2018 with 240,605 downloads, compared to the 155,372 downloads between 2016 and 2017. Following this trend, and with Riot 4 setting forth some pretty interesting expectations, we can expect growth to continue consistently throughout 2018. Riot is definitely a framework worth learning even if you’re not immediately implementing it into your stack.

Where Riot is Lacking

Let’s take a look at a Riot/Redux example.

Riot + Redux Example

import riot from 'riot'

import { combineReducers, applyMiddleware, createStore, compose } from 'redux'

import thunk from 'redux-thunk' const reducers = combineReducers({

function(state={name:'Before Redux'}, action) {

switch(action.type) {

case 'ACTION_PENDING':

return {

...state,

name: 'Loading...'

}

case 'ACTION_FULFILLED':

return {

...state,

name: 'After Redux'

}

default:

return state

}

}

}) const store = createStore(

reducers

) store.subscribe(() => {

riot.update()

}) export default {

store: store

}

State Management

As fascinating as Riot is for its minimalistic approach, it’s that very factor that can quickly become a burden for less experienced developers. As we covered previously in this chapter, Riot does not ship with a proprietary state management system. The observable exists, and it is a very flexible and powerful tool, but it’s not a full fledged solution for state management. You can of course default to a universal state manager like Redux, but there really isn’t a preferred or suggested architectural pattern for implementation. For large scale applications this can be an immediate turn off because state management is a crucial aspect of modern web development.

Tag Routing (similar to React)

<app>

<router>

<route path="search..">

<Search />

</route>

</router>

</app>

Routing

Another lacking component of Riot’s ecosystem is routing. The official router is objectively worse than its competitors like React, Vue, and Angular 2. There are many instances, and edge cases that just aren’t covered, such as fragment identification. Server side rendering can be a hassle to set up, specifically because there are simply so many possible approaches. This can also be said for server sided routing. All in all, the official router is very feature full and even includes interception and middleware. It’s extraordinarily easy to set up and applications can very easily be built on top of it; but being mindful of it’s weaknesses prior to constructing an application is crucial because the router is tightly coupled with Riot and can determine the flow of your development process and component data pipeline design or convention. The Riot router is at its core designed to be a simple aid to your website or web application, it is not designed to manage your state or history.

Processing Query Parameters

<search>

<input ref="searchField" type="text" value={ searchQuery } autofocus />

<button ref="searchButton" click={ search }>Search</button>

<ul><li each={ result in searchResults }>...</li></ul>

<script>

const self = this self.searchQuery = ''

self.searchResults = [] search() {

// disable our search button

self.refs.searchButton.disabled = true

// some theoretical endpoint that consumes our search query via a query string

fetch(`...?query=${ self.refs.searchField.value || self.searchQuery }`, {

method: 'get',

headers: {

'Accept': 'application/json, text/plain, */*'

}

})

.then(res => {

res.json().then((data) => {

self.searchResults = data

// enable our search button

self.refs.searchButton.disabled = false

// process changes to search results

self.update()

})

})

} // this sample would process query string arguments against the route attributed to this component

// query string processing is done in separate context than tag route mounting

// this snippet would automatically perform a search when query parameter provided

subroute = route.create() // create another routing context

subroute('/search..', function() {

const args = route.query()

// .../search?query=riot+example+search

if (args.query) {

// note: because we have the search field value bound to an expression

// it will be automatically updated on our ntext updated

self.searchQuery = args.query

// process our search

self.search()

}

})

</script>

</search>

A major pain point with routing is managing route variables and query parameters. By design the router doesn’t actually pass any information onto your tags, rather it’s recommended to use routing middleware for each attributed tag to consume and digest any and all information. This can become very redundant and feels rather unintuitive coming from a more mature framework like Vue, React, or Angular with a well established router. It’s not difficult, but can take some getting used to.

Testing

Testing Riot applications can also be tricky because of the plethora of build tools available and the lack of a universally established project structure-constructing tests for individual components can be a chore. If you’re coming to Riot unfamiliar with industry standards or unaware of discrepancies between popular testing tools, you’re also unfortunately going to have a rough time. This doesn’t mean TDD with Riot is impossible, but you’re going to have to be resourceful to set up a proper testing environment due to the lack of official documentation on unit testing Riot components.

Test Example — taken from dashboard example

it('should properly draw a chart on mount', function(done) {

setInterval(function() {

if (document.querySelector('.chartjs-size-monitor'))

done()

}, 250)

})

Writing tests are fairly straightforward once you have your tag mounted. Because Riot's ecosystem is so small, TDD should be much more seemless than with Angular or Vue, where stubbing plugins and services may be necessary just to render given components.

The Dos and Don’ts

For a relatively small framework, Riot has a number of gotcha’s that can heavily impact the performance of your website or web application. There are a number of anti patterns that can plague highly reactive pages or components, and the prime culprit for these are the observable. As discussed throughout this book, the observable can a pretty nifty and powerful tool, but it has its weak points. What the observable allows us to accomplish is approach our web application with a loosely coupled architecture so we can focus on true modularity and make the most out of our web components. The most common mistake developers make is misunderstanding how observable events are triggered.

User Service Mixin

class UserService {

* Theoretical service for user resources.

*

*

*/

constructor(instance, userHref) {

// note: any object can be transformed into a riot observable

instance.observable(this)

this.userHref = userHref

this.profile = { }

this.update()

} /*** Theoretical service for user resources. @param {Riot} riot - Riot instance to target. @param {string} userHref - Href for user resource.*/constructor(instance, userHref) {// note: any object can be transformed into a riot observableinstance.observable(this)this.userHref = userHrefthis.profile = { }this.update() update() {

const self = this self.trigger('update')

fetch(self.user_href, { ... })

.then(res => {

res.json().then(data => {

self.profile = data

self.profile.updated = new Date().getTime()

self.trigger('updated')

})

})

.catch(error => {

self.error = error

self.trigger('error')

})

} }

The example above is a simple user service for fetching user profile information. The following is an example of a few bad practices exercising the observable that can lead to severe performance issues.

Component Exercising The User Service

<Profile>

<loading if={ !profile.updated } />

<div if={ profile.updated }>

<h1>{ profile.username }</h1>

<button click={ updateProfile }>Update Profile</button>

<button click={ updateProfileNoUpdate }>

Update Profile Without Update

</button>

</div>

<script>

const self = this // assume user service has been installed as a global mixin

self.profile = self.user.profile self.on('update', function() {

self.profile = self.user.profile

})



self.user.on('updated', function() {

// if a user were to invoke a user profile update

// and the corresponding method does not prevent updates

// the component would actually be updated twice

self.update()

}) updateProfile(e) {

// a user invoked event will automatically cause the component to update itself

self.user.update()

// this update call will cause the component to update twice

self.update()

} updateProfileNoUpdate(e) {

// the preventUpdate event property will stop the next component update from being dispatched in this context

e.preventUpdate = true

self.user.update()

// any additional invokations that trigger an update will be ignored

self.update()

}

</script>

</Profile>

In the example above there are a couple of important don’ts to note. Notice the component method updateProfile that gets invoked by a user event. Riot by design will automatically trigger an update when a user invokes a member of the component, therefore triggering an update yourself is not necessary. Also notice the updateProfileWithoutUpdate method that consumes the user event as an argument. Riot allows us to prevent the following update by toggling the event property preventUpdate , but this property will only prevent the following update. Any other updates that are triggered will be run.

Another pattern you want to steer clear from is reinventing the wheel. If multiple components share the same functionality, it’s a sign you should be creating a mixin. You can think of mixins as objects or collections, sets of functionality, or data to inject into your components. The following sample is an example of what you want to avoid.

Bad Practice

<Home>

<h1>Time: { time() }</h1>

<script>

time() {

return new Date().toLocaleString()

}

</script>

</Home> <Dashboard>

<h1>Time: { time() }</h1>

<script>

time() {

return new Date().toLocaleString()

}

</script>

</Dashboard>

Instead you can create a shared utility mixin to reference between your components.

Mixin

riot.mixin('time', {

getTime() {

return new Date().toLocaleString()

}

})

Use

<Home>

<h1>Time: { getTime() }</h1>

<script>

this.mixin('time')

</script>

</Home>

A powerful feature of Riot is one way data flow, which is crucial to master for building maintainable and scalable components. It’s important to emphasize how much of a difference properly using opts can make. Above all else, data flow provides a good architectural structure for your components and website or web application as a whole.

Riot Opts

<Home>

<ul each={ user in users }>

<li>

<UserCard user={ user } />

</li>

</ul>

</Home>

When using opts for one way data flow, unless you know what you’re doing, opts should never be mutated by the consuming component (like React). This allows us to better architect our components without the fear of our data losing its integrity. So how do we approach modifying our data? Mixins. One approach is using the subscribe and publish philosophy. The following code samples are a more advanced real world example portraying a blog.

Global User Mixin

class User {

* User service for local user.

*

*

*/

constructor(instance, apiroot) {

instance.observable(this)

this.apiroot = apiroot

this.posts = []

this.trigger('ready')

} /*** User service for local user. @param {Riot} instance - Riot instance to target. @param {string} apiroot - Href to service description for application.*/constructor(instance, apiroot) {instance.observable(this)this.apiroot = apirootthis.posts = []this.trigger('ready')

* Fetch user links from service description.

*

*/

href() {

const self = this

/*

Assume payload in form: /*** Fetch user links from service description. @returns {Promise}*/href() {const self = this/*Assume payload in form:

rel: 'user',

links: [{

rel: 'posts',

href: '

}]

}]

*/

return fetch(self.apiroot)

.then(res => {

return res.json().then(links => {

return links.find(link => link.rel == 'user')

})

})

} [{rel: 'user',links: [{rel: 'posts',href: ' http://posts:8080/posts' }]}]*/return fetch(self.apiroot).then(res => {return res.json().then(links => {return links.find(link => link.rel == 'user')})})

* Fetch all user posts.

*

*/

getPosts() {

const self = this /*** Fetch all user posts. @returns {void}*/getPosts() {const self = this

.then(links => {

fetch(links.find(link => link.rel == 'posts'))

.then(response => {

response.json.then(data => {

/*

[

{

href: String, // post resource link

links: [{

rel: 'post-view',

href: '

}, ...], // post links

author: String,

title: String,

content: String,

created: Int,

modified: Int

}, ...

]

*/

self.posts = posts

self.trigger('publish', self.posts)

})

})

})

} self.href().then(links => {fetch(links.find(link => link.rel == 'posts')).then(response => {response.json.then(data => {/*href: String, // post resource linklinks: [{rel: 'post-view',href: ' http://posts:8080/posts/1/view' }, ...], // post linksauthor: String,title: String,content: String,created: Int,modified: Int}, ...*/self.posts = postsself.trigger('publish', self.posts)})})})

* Edit given user post.

*

*

*

*/

editPost(href, edits) {

const self = this

fetch(post.href, { method: 'PUT', body: edits })

.then(response => {

response.json().then(data => {

// grab reference to target post

let target = self.posts.find(p => p.href == post.href)

// update post in local store

Object.assign(target, data)

// emit event that changes have been published

self.trigger('publish', self.posts)

})

})

} /*** Edit given user post. @param {string} href - Href for target post resource. @param {object} edits - Fields of provided post to edit. @returns {void}*/editPost(href, edits) {const self = thisfetch(post.href, { method: 'PUT', body: edits }).then(response => {response.json().then(data => {// grab reference to target postlet target = self.posts.find(p => p.href == post.href)// update post in local storeObject.assign(target, data)// emit event that changes have been publishedself.trigger('publish', self.posts)})}) }

We define a mixin as a User . Whenever an update is made to our mixin's data, or a change to a resource is explicitly made, we emit an event publish so our subscribed components can handle these changes however necessary. We don't force an update to allow us complete control for dealing with the event in any context. We can also pass along our updated data through the emitted event.

Entry

riot.mixin({ user: new User() })

Subscriber

<Home>

<ul each={post in this.posts}>

<UserPost post={ post }>

</ul>

<script>

const self = this // necessary for closure within user context self.posts = []

self.user.getPosts()

// this functionality will be triggered whenever the user mixin emits the publish event

self.user.on('publish', function(posts) {

// update component's posts

self.posts = posts

self.update()

})

</script>

</Home>

Post Extension Mixin

class Post {

* General use mixin for handling post resources.

*

*/

constructor(post) {

this.resource = post

} /*** General use mixin for handling post resources. @param {object} post - Post data transfer object as provided by global mixin.*/constructor(post) {this.resource = post postSeen() {

const link = this.resource.links.find(l => l.rel == 'post-view')

fetch(link.href, { method: 'PUT' })

} ... }

Using this methodology, our subscribed component(s) will always be updated whenever a major change is committed to the user service.

Modifying Data

<UserPost>

<input type="text" ref="postTitle" value={ opts.post.title }></a>

<button click={ edit }></button>

<script>

import Post from './mixins/post'

const self = this // install local mixin

self.mixin(new Post(self.opts.post))

// when this component is mounted, invoke postSeen from locally installed mixin

self.on('mount', self.postSeen) edit(e) {

// invoking editPost from global user mixin

self.user.editPost(self.opts.post.href, {

title: self.refs.postTitle.value

})

}

</script>

</UserPost>

Also note the Post mixin we implemented for higher level operations on a provided resource. We can leverage this Post mixin in any given component, regardless of the source of the data consumed or decoupled from our global service.

Riot Dos and Don’ts

Do:

Be reactive. The observable is an incredible feature, so use it.

Minimize the number of updates necessary for your components.

Leverage Riot mixins wherever possible, they’re meant to compliment your components.

If you have shared methods that you would like to implement into multiple components, consider using a mixin to patch them in.

Use global mixins for functionality you would like shared globally across your entire Riot application, whether it be general utilities or services for resources.

Exercise one way data flow. The example provided is a much more advanced representation of how to approach this architectural pattern, but Riot is flexible enough that you can mold it in your preferred style.

Don’t:

Over engineer. Riot is meant to be simple.

Over update components. Understanding the Riot component lifecycle can make or completely destroy an application.

Reinvent the wheel. If you have multiple components sharing the same functionality, use a mixin.

Riot at Scale

Riot is promoted as an open stack framework, enabling you to to build your given applications however you see fit in any environment. Because of this, your application is to a high degree only as scalable as your given architecture. Due to the lack of enterprise scale adopters, there aren’t many resources to suggest Riot’s threshold in a real world situation, but given Stefan Krause’s benchmarks, we can see that on a technical perspective Riot 3 will perform about as well as Polymer 2 when it comes to high volume rendering. Riot even actually out performs both Angular.js (1.6) and Ember.

To put things into prospective, Youtube, Google Earth, McDonald’s, SalesForce, Bloomberg, and Domino’s Pizza actually use Polymer 2 at the core of their view layer. Given the size of Riot and its miniature ecosystem — it’s certainly feasible to say Riot 3 certainly has the potential to be used in an enterprise environment. The framework also doesn’t require any polyfills, nor does it depend on future browser specifications.

jQuery with Riot

<SearchBar>

<input ref="searchField" placeholder="Search for..."></input>

<script>

$(this.refs.searchField).click(function() {

...

})

</script>

</SearchBar>

Another major bonus to adopting Riot is that it plays very well with other frameworks. As expressed, its ecosystem is lightweight and incredibly encapsulated.

Riot with React and JSX

class App extends React.Component {

componentDidMount() {

// mount riot tag after react component rendered

riot.mount('searchbar')

}

render() {

return (

<app>

<div>

<Header />

<!-- theoretical use of search bar component portrayed in jQuery example -->

<SearchBar />

<section>

<TaskList />

</section>

</div>

<Footer />

</app>

)

}

}

Summary

We’ve covered a lot of important information, ranging from Riot’s use cases, to performance quirks, what it’s lacking, and how it stacks up against other JavaScript frameworks. These points of reference should help paint a clearer picture as to where Riot stands when choosing your stack for your next project. Riot 3 does not offer a platform for bootstrapping applications, nor the foundation of it’s larger competitors; it is however a completely viable solution for curating both websites and web applications of all sizes. Websites or web applications built with jQuery, React, Angular, or Vue can easily be crafted using Riot.

A fair and important point of concern and discussion popular among new adopters of Riot is its longetivity and relevance. Riot was created by Muut and released in 2013 just a few months after React publicly hit the scene. Since then we’ve seen drastic changes to every major update overhauling performance, usability, expressiveness, and simplicity. During each major release, like many other popular frameworks, the maintainers provide updating strategies to make use of and leverage new features so support isn’t an issue.

Riot does though without a doubt have a terribly slow release cycle, but with every major release we’ve seen an increase in maintainers and more public interest in the framework. A perfect example of this being the merger with Simultra in Riot 4. As for adoption, according to NPM statistics as shown in framework comparison sections the growth of Riot has been similar to that of early Vue. Between the year of 2017 and 2018 alone Riot saw a growth of 55%, therefore there’s no need for any immediate worry.

The job market for Riot developers as of 2018 is incredibly small, in part because of the massive adoption of React. You can, however, expect it to grow as the framework continues to mature, more developers are exposed to it, and most certainly with the release of Riot 4. There isn’t a high demand in developers, but learning the framework can prove to be valuable when prototyping or creating a generic SPA-especially considering the low learning curve.

Riot is a wonderful tool to have at your disposal, and truly easy to learn. It enables you to build both websites and web applications at the speed of technology, and is probably the most easily maintainable framework you’ll ever work with. Development may come with minor hiccups when tackling more complex structures without many points of reference, but as long as you keep your project as granular as possible and follow best practices, as well as more common developer patterns such as Flux, Riot shouldn’t pose any hurdles that a typical web developer can’t resolve.

If you’re still questioning whether or not to give this micro framework a shot, try giving it a whirl. The basics can be learned in a single sitting if you’re familiar with other frameworks.You can also jump in right now, and learn how to build an app step-by-step with our new book, “Building Apps with Riot.”

You can also access the code from our sample application included with this book at: (https://github.com/backstopmedia/riot-book-example). This post was excerpted from this book’s chapter titled, “Realistic Expectations,” by one of the authors, John Nolette.

John Nolette is a fullstack web developer, as well as a web development enthusiast, with over four years of experience. He has authored and coauthored a handful of plugins and utilities for a number of JavaScript frameworks. He was drawn to Riot.js because he found it a minimal but complete solution to modern front-end web development.