Riot compiler explained

Riot compiler explained

The compilation

All Riot custom tags must compiled before use. The compilation step converts tag definition (HTML + JavaScript) to JavaScript code.

<clock>
	<div class="clock" onclick="test">
		<div class="hour"></div>
		<div class="minute"></div>
	</div>

	test() {
		console.log("click");
	}
</clock>

If we look at the example above the custom tag definition is almost valid HTML + JS. The way it combines all together (code inside custom tag without script block) and use of shorthand syntax (such as event handlers) makes it invalid to use without compilation.

This necessary step can be done both in client- and server-side. For testing and smaller projects client compilation is a valid option, but the server compilation has many benefits such as:

  • bundling the compiled tags with rest of the JavaScript code
  • pre-processor support
  • no need to download the compiler in the client-side

Compiler output

By comparing the original tag definition and output we can understand what the compiler is doing. I made a small Node application that has only one purpose: use Riot compiler on a single tag and print the output.

The example has a dummy onclick and event handler attach to it, so that we can see how bindings are handled.

Source:

<clock>
    <div class="clock" onclick="test">
        <div class="hour"></div>
        <div class="minute"></div>
    </div>

    test() {
        console.log("click");
    }

    function clock() { 
        var t = moment(),
            a = t.minutes() * 6,
            o = t.hours() % 12 / 12 * 360 + (a / 12);
        $(".hour").css("transform", "rotate(" + o + "deg)");
        $(".minute").css("transform", "rotate(" + a + "deg)");
    }

    function refreshClock() {
        clock(), setTimeout(refreshClock, 1000)
    }
    refreshClock();

</clock>

After compilation:

riot.tag('clock', '<div class="clock" onclick="test"> 
    	<div class="hour"></div> 
    	<div class="minute"></div> 
    </div>', function(opts) {

    this.test = function() {
       console.log("click");
    }.bind(this);

    function clock() {
        var t = moment(),
            a = t.minutes() * 6,
            o = t.hours() % 12 / 12 * 360 + (a / 12);
        $(".hour").css("transform", "rotate(" + o + "deg)");
    	$(".minute").css("transform", "rotate(" + a + "deg)");
    }

    function refreshClock() {
        clock(), setTimeout(refreshClock, 1000)
    }
	refreshClock();
});

Okay, so what just happened.. first thing we notice is that the custom tag in the original file is placed as a first argument in a function call.

riot.tag('clock', .... )

The second argument is the HTML content. The onclick event binding has stayed the same.

Third argument is the modified JavaScript code. At the beginning there is a function definition which explains why we need to use opts to provide external data to the custom tag.

function(opts) { ...

Shorthand event handler definition (test() {.. }) is automatically set to be part of this context and function's context is the same.

this.test = function() {
    console.log("click");
}.bind(this);

Whole source code can be found from this repository.

What to do with the compiled tag?

The end result is pure JavaScript and therefore we can do commonly used optimizations such minification, concatenation etc.

Here is an example how to use compiler together with Gulp and Browserify.

In the Gulpfile we can use tiny npm package called Riotify to wrap compiler and use it together with Browserify.

This example is part of larger Gulpfile, but following lines will help you to take compiler part of the build stack.

var riotify = require('riotify');
var browserify = require('browserify');

In your Browserify / JS task:

var bundler = browserify('./js/your_entrypoint', watchify.args);
// this will make your Browserify understand Riot tags
bundler.transform(riotify);
bundler.bundle()

I hope that this blog post helped you to understand what the compiler does and how to take it part of your build process.