DEV Community

Cover image for Mint: a breath of fresh air for the web 🍃
Franciscello
Franciscello

Posted on

Mint: a breath of fresh air for the web 🍃

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!

The map

An awesome journey needs an awesome map, just like J.R.R. Tolkien's Middle-earth 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:

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, ready to run in the browser.

Also, Mint itself is written in Crystal and it's open source! Yeah! 🤓🎉

Installing Mint

We are going to create an application, so let's start installing the Mint language

a few minutes later

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

$ 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
Enter fullscreen mode Exit fullscreen mode

--help working great! And the version command:

$ mint-lang version
Mint - Showing version
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Mint 0.7.1
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
All done in 3.362ms!
Enter fullscreen mode Exit fullscreen mode

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:

$ 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!
Enter fullscreen mode Exit fullscreen mode

Here's the resulting project's structure:

counter
├── source
│   └── Main.mint
├── tests
│   └── Main.mint
├── .gitignore
└── mint.json
Enter fullscreen mode Exit fullscreen mode

Note: We may continue reading about using the cli, with more examples and commands.

The launching word: start

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

$ 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/
Enter fullscreen mode Exit fullscreen mode

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):

/* Counter.mint */

component Counter {
  fun render : Html {
    <div>
      <{"Here be a counter!"}>
    </div>
  }
}
Enter fullscreen mode Exit fullscreen mode

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

/* Main.mint */

component Main {
  fun render : Html {
    <Counter/>
  }
}
Enter fullscreen mode Exit fullscreen mode

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

...
⚙ Files changed recompiling... 8.832ms
Enter fullscreen mode Exit fullscreen mode

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

The Store 📦

We will define the counter store like this:

/* 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 }
  }
}
Enter fullscreen mode Exit fullscreen mode

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

Some references for the above code:

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:

/* Counter.mint */

component Counter {
  connect Counter.Store exposing { count }

  fun render : Html {
    <div>
      <{"Here's the count: #{count}"}>
    </div>
  }
}
Enter fullscreen mode Exit fullscreen mode

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)

/* 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>
  }
}

Enter fullscreen mode Exit fullscreen mode

Let's try it!

Alt Text

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.

We are modifying /source/Main.mint:

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

  fun render : Html {
    <div::base>
      <Counter />
    </div>
  }
}
Enter fullscreen mode Exit fullscreen mode

and /source/Counter.mint:

/* 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>
  }
}
Enter fullscreen mode Exit fullscreen mode

And the final result 🥁

Alt Text

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 for reviewing this post and improving the code and text!! 👏👏👏

Photo by Jonas Weckschmied on Unsplash

Top comments (0)