Compiler
In-browser compilation
Custom tags need to be transformed to JavaScript before the browser can execute them. You can do this by setting a type="riot/tag"
attribute for your script tags. For example:
<!-- mount point -->
<my-tag></my-tag>
<!-- inlined tag definition -->
<script type="riot/tag">
<my-tag>
<h3>Tag layout</h3>
<inner-tag />
</my-tag>
</script>
<!-- <inner-tag/> is specified on external file -->
<script src="path/to/javascript/with-tags.tag" type="riot/tag"></script>
<!-- include riot.js and the compiler -->
<script src="https://cdn.jsdelivr.net/npm/riot@3.13/riot+compiler.min.js"></script>
<!-- mount normally -->
<script>
riot.mount('*')
</script>
The script tag and the external file can contain multiple tags definitions combined with regular javascript.
Riot automatically takes inlined and external tags and compiles them before the tags are rendered with the riot.mount()
call.
You might prefer using data-src
instead of src
on your <script>
tags stop your browser prefetching automatically any riot script tag in order to avoid to load the same resources twice. Riot will automatically fetch and compile your tags via ajax.
Access tag instances
If you are loading tags with script src
and want to get access to the mounted tags you need to wrap the call with riot.compile
as follows:
<script>
riot.compile(function() {
// here tags are compiled and riot.mount works synchronously
var tags = riot.mount('*')
})
</script>
Compiler performance
Compilation phase is basically free and takes no time at all. Compiling a timer tag 30 times takes 2 milliseconds on a regular laptop. If you have a crazy page with 1000 different timer-sized tags, the compilation takes around 35ms.
The compiler weights only 3.2KB (1.7K gzipped) so you can safely perform client side compilation on production without download or performance or issues.
Read the compiler API for more details.
Demos
- In-browser compiled
- Pre-compiled
- Source code
- Download the demo as a zip file
Pre-compilation
Pre- compilation on the server gives you following benefits:
- Ability to compile tags with your favorite pre-processor.
- Small performance benefit. No need to load and execute the compiler on browser.
- Universal (isomorphic) apps and the ability to pre- render tags on the server.
Pre-compilation happens with a riot
executable, which can be installed with NPM as follows:
npm install riot -g
Type riot --help
and make sure it works. node.js is required on your machine.
With pre-compilation your HTML is something like this:
<!-- mount point -->
<my-tag></my-tag>
<!-- include riot.js only -->
<script src="https://cdn.jsdelivr.net/npm/riot@3.13/riot.min.js"></script>
<!-- include pre-compiled tags (normal javascript) -->
<script src="path/to/javascript/with-tags.js"></script>
<!-- mount the same way -->
<script>
riot.mount('*')
</script>
Using
Here is how riot
command works:
# compile a file to current folder
riot some.tag
# compile file to target folder
riot some.tag some_folder
# compile file to target path
riot some.tag some_folder/some.js
# compile all files from source folder to target folder
riot some/folder path/to/dist
# compile all files from source folder to a single concatenated file
riot some/folder all-my-tags.js
The source file can contain one or more custom tags and there can be regular JavaScript mixed together with custom tags. The compiler will only transform the custom tags and does not touch other parts of the source file.
For more information, type: riot --help
Watch mode
You can watch directories and automatically transform files when they are changed.
# watch for
riot -w src dist
Custom extension
You’re free to use any file extension for your tags (instead of default .tag
):
riot --ext html
ES6 Config file
You can use a config file to store and configure easily all your riot-cli options and create your custom parsers
riot --config riot.config
The riot riot.config.js
file:
export default {
from: 'tags/src',
to: 'tags/dist',
// files extension
ext: 'foo',
// html parser
template: 'foo',
// js parser
type: 'baz',
// css parser
style: 'bar',
parsers: {
html: {
foo: (html, opts, url) => require('foo').compile(html),
},
css: {
bar: (tagName, css, opts, url) => require('bar').compile(css),
},
js: {
baz: (js, opts, url) => require('baz').compile(js),
},
},
// special options that may be used to extend
// the default riot parsers options
parserOptions: {
js: {},
template: {},
style: {}
}
};
Node module
var riot = require('riot')
var js = riot.compile(source_string, options, url)
The compile function takes a string and returns a string.
Plug into your workflow
Pre-processors
This is the main fruit of pre- compilation. You can use your favourite pre- processor to create custom tags. Both HTML and JavaScript processor can be customized.
The source language is specified with --type
or -t
argument on the command line or you can define the language on the script tag as follows:
<my-tag>
<h3>My layout</h3>
<script type="coffee">
@hello = 'world'
</script>
</my-tag>
CoffeeScript
# use coffeescript pre-processor
riot --type coffee --expr source.tag
The --expr
argument specifies that all the expressions are also processed as well. You can also use “cs” as an alias to “coffee”. Here is a sample tag written in CoffeeScript:
<kids>
<h3 each={ kids[1 .. 2] }>{ name }</h3>
# Here are the kids
this.kids = [
{ name: "Max" }
{ name: "Ida" }
{ name: "Joe" }
]
</kids>
Note that each
attribute is CoffeeScript as well. CoffeeScript must be present on your machine:
npm install coffee-script -g
EcmaScript 6
ECMAScript 6 (babeljs) is enabled with a type “es6”:
A sample tag written in ES6:
<test>
<h3>{ test }</h3>
const type = 'JavaScript'
this.test = `This is ${type}`
</test>
Before using the es6 compiler you should properly configure your project following the steps below:
- install our babel-preset-es2015-riot
npm install babel-preset-es2015-riot --save-dev
- install
babel-core
as well
npm install babel-core -g
- create a
.babelrc
file containing the preset id
{ "presets": ["es2015-riot"] }
Once you have configured your environment you can compile your tags:
# use ES6 pre-processor
riot --type es6 source.tag
note Babel generates a lot of extra code in your output so you may consider compiling your tags in 2 separate steps using the babel-plugin-external-helpers-2
as well for example:
# compile your tags using pure es6 code
riot tags/folder dist/es6.tags.js
# convert your es6 to valid es5 code
babel es6.tags.js --out-file tags.js
Here is a simple example on using Babel 6 with Riot.
TypeScript
TypeScript adds optional static typing to JavaScript. Use --type typescript
to enable it:
# use TypeScript pre-processor
riot --type typescript source.tag
A sample tag written in TypeScript:
<test>
<h3>{ test }</h3>
const test: string = 'JavaScript';
this.test = test;
</test>
typescript-simple is used for the transformation:
npm install typescript-simple
LiveScript
Check out LiveScript for language features and documentation.
The source language is specified with --type
or -t
argument:
# use livescript pre-processor
riot --type livescript --expr source.tag
The --expr
argument specifies that all the expressions are also processed as well. You can also use “ls” as an alias to “livescript”. Here is a sample tag written in LiveScript:
<kids>
<h3 each={ kids[1 .. 2] }>{ name }</h3>
# Here are the kids
this.kids =
* name: \Max
* name: \Ida
* name: \Joe
</kids>
Note that each
attribute is LiveScript as well. LiveScript must be present on your machine:
npm install LiveScript -g
Pug (Jade)
HTML layout can be processed with template
configuration option. Here’s an example with pug – a “clean, whitespace sensitive syntax for writing html”
# use Pug HTML pre-processor
riot --template pug source.tag
A Pug sample:
todo
h3 Todo
ul
li(each="{ items }")
label(class="{ completed:done }")
input(type="checkbox", checked="{ done }", onclick="{ parent.toggle }")
= "{ title }"
form(onsubmit="{add}")
input(name="input", onkeyup="{edit}")
button(disabled="{!text}")= "Add { items.length + 1 }"
script.
var self = this
self.items = []
self.disabled = true
edit(e) {
self.text = e.target.value
}
add(e) {
if (this.text) {
self.items.push({ title: this.text })
this.text = this.input.value = ''
}
}
toggle(e) {
var item = e.item
item.done = !item.done
return true
}
As you notice, you can define the script type on the template as well. pug is used for the transformation:
npm install pug -g
Any language
You can configure your favourite language by making a custom parser function. For example:
function myParser(js, options) {
return doYourThing(js, options)
}
This parser is then passed for the compiler with parser
option:
var riot = require('riot')
var js = riot.compile(source_string, { parser: myParser, expr: true })
Set expr: true
if you want the expressions to be parsed as well.
riot.parsers on the browser and the server
You can also create your custom riot parsers adding them to the riot.parsers
property and share them across the browsers and server. For example
riot.parsers.js.myJsParser = function(js, options) {
return doYourThing(js, options)
}
riot.parsers.css.myCssParser = function(tagName, css) {
return doYourThing(tagName, css)
}
Once you have created your own riot.parsers
you will be able to compile your tags using them in the following way
<custom-parsers>
<p>hi</p>
<style type="text/myCssParser">
@tag {color: red;}
</style>
<script type="text/myJsParser">
this.version = "@version"
</script>
</custom-parsers>
No transformation
By default Riot uses a build-in transpiler that simply enables shorter ES6- stylish method signatures. You can disable all transformation with --type none
:
# no pre-processor
riot --type none --expr source.tag
AMD and CommonJS
Riot tags can be compiled with AMD
(Asynchronous Module Definition) and CommonJS
support. This configuration option is necessary if Riot is used with an AMD loader such as RequireJS or a CommonJS loader such as Browserify.
The Riot library must be defined / required as riot
in both cases.
# enable AMD and CommonJS
riot -m
Example AMD:
define(['riot', 'tags'], function (riot) {
riot.mount('*')
})
Example CommonJS:
var riot = require('riot')
var tags = require('tags')
riot.mount('*')
If you make something great, please share it !