Mint: a breath of fresh air for the web 🍃
Tags: mint, javascript, crystal, tutorial
Published: 2020-02-05 18:27:28

_One of the languages/technologies I want to learn this year is Mint. Here is a first approach to the language._


# Introduction

We are starting a new journey upon the lands of Single-Page Applications development. And as adventurers say: 
> _Better start a new journey with a breath of fresh air!_

_wait ... what?_ 🤔

ok, well, I don't know if that's what they say 🤣 but bear with me: we are starting an awesome web application development _journey_ with the programming language [Mint](https://www.mint-lang.com/)!

### The map

An awesome journey needs an awesome map, just like [J.R.R. Tolkien's Middle-earth map](http://lotrproject.com/map). In our case, these are going to be our next steps:

* What is Mint
  * Installing Mint
* Building our first application:
  * `init`
  * `start`
  * An initial `component`
  * The `store`
  * The full `component`
     * Events
     * CSS

Our 10-step journey begins ... now!🍃

# What is Mint?

As said in Mint's [guide](https://www.mint-lang.com/guide):
>Mint is a language specifically created for writing single-page applications. It is a compiler and a framework combined to provide great developer experience while allowing to write safe, readable and maintainable code. 

Moreover, Mint will provide us with React abstractions (components and stores) and all this _protected_ by a type system, making writing  single-page applications a fun task! Mint's output will be our application in [JavaScript](https://tc39.es/ecma262/), ready to run in the browser.

Also, Mint itself is written in [Crystal](https://crystal-lang.org/) and it's [open source](https://github.com/mint-lang/mint)! Yeah! 🤓🎉

## Installing Mint

We are going to create an application, so let's start [installing the Mint language](https://www.mint-lang.com/install)

_a few minutes later_ 

Ok, are we all done? Let's try the `mint-lang` command:

```terminal-session
$ mint-lang --help
Usage:
  mint-lang [flags...] [arg...]

Mint

Flags:
  --env, -e (default: "")  # Loads the given .env file
  --help                   # Displays help for the current command.

Subcommands:
  build                    # Builds the project for production
  compile                  # Compiles the project into a single JavaScript
  docs                     # Starts the documentation server
  format                   # Formats source files
  init                     # Initializes a new project
  install                  # Installs dependencies
  loc                      # Counts Lines of Code
  start                    # Starts the development server
  test                     # Runs the tests
  version                  # Shows version
```

`--help` working great! And the `version` command:

```terminal-session
$ mint-lang version
Mint - Showing version
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Mint 0.7.1
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
All done in 3.362ms!
```

# Building our first Mint application

This first application is the great-awesome-as-always **Counter App**

## The magic word: `init`

Let's create the project with:

```terminal-session
$ mint-lang init counter
Mint - Initializing a new project
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚙ Creating directory structure...
⚙ Writing initial files...

There are no dependencies!

There is nothing to do!
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
All done in 3.428ms!
```

Here's the resulting project's structure:

```
counter
├── source
│   └── Main.mint
├── tests
│   └── Main.mint
├── .gitignore
└── mint.json
```

**Note:** We may continue reading about [using the cli](https://www.mint-lang.com/guide/getting-started/using-the-cli), with more examples and commands.

## The launching word: `start` 

Yeah! Mint as a framework has a built-in development server:

```terminal-session
$ mint-lang start
Mint - Running the development server
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚙ Ensuring dependencies... 5.621ms
⚙ Parsing files... 4.709ms
⚙ Development server started on http://127.0.0.1:3000/
```

Visiting `localhost:3000` will present a `Hello Mint!` page.

## Let's count 1 2 3

So, our application it's going to show a counter with two buttons (for incrementing and decrementing the counter)

First let's create the `Counter` component (we are creating the file `/source/Counter.mint`):

```crystal
/* Counter.mint */

component Counter {
  fun render : Html {
    <div>
      <{"Here be a counter!"}>
    </div>
  }
}
```

Next we are going to change the (autogenerated) `Main` component so that we render the `Counter` component:

```crystal
/* Main.mint */

component Main {
  fun render : Html {
    <Counter/>
  }
}
```

**Note:** Don't worry refreshing your browser, Mint takes care of that:

```terminal-session
...
⚙ Files changed recompiling... 8.832ms
```

Let's continue with the `store` and then we will finish the component.

## The Store 📦

We will define the counter [store](https://www.mint-lang.com/guide/reference/stores) like this:

```crystal
/* CounterStore.mint */

store Counter.Store {
  state count : Number = 0

  fun increment : Promise(Never, Void) {
    next { count = count + 1 }
  }

  fun decrement : Promise(Never, Void) {
    next { count = count - 1 }
  }
}
```

**Note:** The store is defined in the file `/source/CounterStore.mint`

Some references for the above code:
- [State](https://www.mint-lang.com/guide/reference/components/internal-state)
- [Promise type](https://www.mint-lang.com/guide/reference/built-in-types)

Now, let's **connect** the `Counter.store` to the component.

## The Component

We started writing an initial implementation of the Counter's `component`. Then we implement the `store`. Now we need to **connect** the `component` to that `store`:

```crystal
/* Counter.mint */

component Counter {
  connect Counter.Store exposing { count }

  fun render : Html {
    <div>
      <{"Here's the count: #{count}"}>
    </div>
  }
}
```

Great! That was intuitive and easy! 🤓

### Buttons and Events

It's time to add the buttons to increment/decrement the counter. Taking into account that when clicking a button we need to **handle the event**, and then use the proper function defined in the `store` so that the action reflects on the counter (i.e. the store is updated)

```crystal
/* Counter.mint */

component Counter {
  connect Counter.Store exposing {
    count,
    increment as incrementCounter,
    decrement as decrementCounter
  }

  fun handleClickOnDecrement (event : Html.Event) : Promise(Never, Void) {
    decrementCounter()
  }

  fun handleClickOnIncrement (event : Html.Event) : Promise(Never, Void) {
    incrementCounter()
  }

  fun render : Html {
    <div>
      <button onClick={handleClickOnDecrement}>
        "-"
      </button>

      <div>
        <{"Here's the count: #{count}"}>
      </div>

      <button onClick={handleClickOnIncrement}>
        "+"
      </button>
    </div>
  }
}

```

Let's try it! 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/81ohkyjfpz989c6lus51.gif)

Yeah! It's alive!

### CSS to my eyes!

To be honest we can't say it's a work of art, visually it lacks of some sort of ... well ... you know ... my eyes hurt!

So let's create a better layout 📐 and put some colors 🎨, nothing too fancy. For this we are going to [use simple CSS](https://www.mint-lang.com/guide/getting-started/styling-with-css).

We are modifying `/source/Main.mint`:

```crystal
component Main {
  style base {
    font-family: sans;
    font-size: 18px;
  }

  fun render : Html {
    <div::base>
      <Counter />
    </div>
  }
}
```

and `/source/Counter.mint`:

```crystal
/* Counter.mint */

component Counter {
  connect Counter.Store exposing {
    count,
    increment as incrementCounter,
    decrement as decrementCounter
  }

  style base {
    display: flex;
  }

  style baseButton {
    color: white;
    border: 0;
    margin: 0 7px 0;
    font-size: 12px;
    font-weight: bold;
  }

  style decrementButton {
    background: red;
  }

  style incrementButton {
    background: #009c00;
  }

  style count {
    margin: 0 7px 0;
  }

  fun handleClickOnDecrement (event : Html.Event) : Promise(Never, Void) {
    decrementCounter()
  }

  fun handleClickOnIncrement (event : Html.Event) : Promise(Never, Void) {
    incrementCounter()
  }

  fun render : Html {
    <div::base>
      <button::baseButton::decrementButton
        onClick={handleClickOnDecrement}>
        "-"
      </button>

      <div::count>
        <{"Here's the count: #{count}"}>
      </div>

      <button::baseButton::incrementButton
        onClick={handleClickOnIncrement}>
        "+"
      </button>
    </div>
  }
}
```

And the final result 🥁

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/oc4tqkntfzbivonbilvo.png)

# Farewell and see you later

We've reached the end of this amazing journey with Mint! And as the adventurers say: 

_It's time to rest my friend,
 in this mint fresh air night.
 Remember this is not an end,
 in the morning new adventures shall arrive!_

Well, I don't know if they say that ... but they should 😉

Hope you enjoyed it! Until the next Mint journey!

As always, thanks, thanks, thanks to:
@bcardiff, @diegoliberman and [@petti](https://www.linkedin.com/in/mpettinati/) for reviewing this post and improving the code and text!! 👏👏👏

_Photo by Jonas Weckschmied on Unsplash_