RiotJS + ViteJS tutorial
Tags: javascript, beginners, frontend, riotjs
Published: 2023-11-15 15:00:04

## Introduction

RiotJS is getting popular but still lacking visibility compared to mastodons projects like Vue, React, and Angular. 

However, [Riot](https://riot.js.org/) is my first choice when creating a front-end, here is why:
- Minimal learning curve, Small API, Close to HTML/JS standards, no magic tricks, it's accessible to everyone
- Performant and predictable
- "Everything you wished native the web components API looked like" mentioned on their website, and I do approve!
- Tiny build when gzipped (compared to other front-ends)
- Good documentation

The development tooling is quite broad, and one of my favourites is [Vite](https://vitejs.dev/). However, **I can't find any documentation or tutorial to run Riot with Vite!** Let's fix that together.

This tutorial will go through all the steps to create a counter; the final result:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/brh5hi44rm1v4171i7bb.png)

> If you want to look at the final code, the GitHub repository: https://github.com/steevepay/riotjs-vite-setup

## Build and run Riot with Vite

### Init and install packages

Create a new directory
```
mkdir riot-vite-setup && cd riot-vite-setup
```

Init the node project
```
npm init
```

Now you have to install the following npm packages:
```bash
npm install --save-dev riot vite rollup-plugin-riot
```
`Rollup-plugin-riot` is a plugin that compiles Riot files within rollup processes. ViteJS uses Rollup under the hood as its default bundler for JavaScript modules. Without it, Riot can't be compiled and used by Vite.

Finally, create a Vite configuration file, `vite.conf.mjs`:
```js
import { defineConfig } from 'vite'
import riot from 'rollup-plugin-riot'

export default defineConfig({
  root       : process.cwd() + '/client',
  plugins    : [riot()],
  build: { 
    minify       : 'esbuild', /** https://vitejs.dev/config/build-options.html#build-minify */
    target       : 'esnext' /** https://vitejs.dev/config/build-options.html#build-target */
  }
})
```
Option details:
- `root`: defines the project root directory (where index.html is located). In our case, it is located in `client`.
- `target`: Browser compatibility target for the final bundle.
- `minify`: Minify the final bundle, `Esbuild` is 20 ~ 40x faster than Terser and only 1 ~ 2% worse compression.
- Lean more about Vite configuration: https://vitejs.dev/config/

### Base project

All the front-end code will be located in the `client` directory. Let's create three files:
- `client/index.html`: entry point of your front-end, it will mount the Riot application
- `client/index.riot`: Riot application
- `client/c-button.riot`: Custom button component used by the application.

At this stage, the root directory should look like:
```
package.json
package-lock.json
vite.config.mjs
client/index.html
client/index.riot
client/c-button.riot
```

The `client/index.html` is pretty basic. It imports and mounts the Riot application:
```html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>RiotJS + ViteJS</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module">
      /** Load riot.js **/
      import * as riot from 'riot'
      import App from './index.riot'

      const mountApp = riot.component(App)
      mountApp(document.getElementById('root'))
    </script>
  </body>
</html>
```

The `client/index.riot` imports the custom button `c-button` and defines three instances: 
- one to increase the counter 
- one to decrease the counter
- one to print the counter

```html
<app>
    <div>
        <h1> Riotjs + ViteJS </h1>
        <c-button> { state.total } </c-button>
        <c-button primary="true" onclick={ () => update({ total: state.total + 1 }) }> Add </c-button>
        <c-button danger="true" onclick={ () => update({ total: state.total - 1 }) }> Delete </c-button>
    </div>
    <script>
        /** Load the custom button **/
        import cButton from './c-button.riot';

        export default {
            /** Define the custom button **/
            components : {
                cButton
            },
            /** State of the counter **/
            state : {
                total: 0
            }
        }
    </script>
</app>
```
The `client/c-button.riot` contains a slot to change the text and props to change the style of the button (default/grey, primary/purple, or danger/orange):
```html
<c-button >
    <button class="btn{ props.primary ? ' btn-primary' : '' }{ props.danger ? ' btn-danger' : '' }">
        <slot></slot>
    </button>
</c-button>
```

Now we have everything to start a development server to get a preview of the app!

### Run live preview

Start the development server, then access the live preview on http://localhost:5173/ :
```bash
npm run dev
```
Et voilà, you should be able to increase/decrease the counter 🎉 You can make code changes, and the preview will be refreshed automatically.

> 🛟 If you need any help, leave a comment.

### Build for production

Build the front for production:
```bash
npm run build
```
Built files are located in the dist directory.

## Conclusion

Using Vite makes the development of Riot application super easy:
- No-brain configuration
- efficient development server with HMR (Hot Module Replacement), allowing you to see changes in your code instantly without a full page reload
- efficient build system with tree-shaking 

Thanks for reading! Cheers 🍻

## Resources
- Link to the Github Repository [Riot+Vite setup] (https://github.com/steevepay/riotjs-vite-setup)
- [Good comparison between Riot and Vue](https://github.com/damusix/riot-vs-vue)
- [Why Vite?](https://vitejs.dev/guide/why.html)