Mint vs JavaScript (stack)
Tags: mintlang, javascript, webdev
Published: 2018-09-17 13:00:59

---
title: Mint vs JavaScript (stack)
published: true
description: Comparing Mint with JavaScript
tags: mintlang, javascript, webdev
---

In this post we are going to compare Mint with JavaScript, more specifically we are going to compare it with the equivalent JavaScript stack because Mint is also a framework.

This comparison will cover the following layers:

* Language
* Type checking
* Development Server
* View
* State
* Routing
* Networking
* Testing
* Error Messages
* Formatting
* Production Build

Each layer has the following sections:

* The JavaScript implementation with an example
* The Mint implementation with an example
* Comparison of the implementations
* Statistics (if applicable)

_Beware: it covers a lot of features so this is a lengthy article._

# Language

Comparing the two languages is tricky because they are very different, so I'll just try to give a small definition for both.

There are examples through out the post which gives you a general idea on the syntax an semantics. 

### JavaScript

Wikipedia defines it as:

> JavaScript (/ˈdʒɑːvəˌskrɪpt/),[7] often abbreviated as JS, is a high-level, interpreted programming language. It is a language which is also characterized as dynamic, weakly typed, prototype-based and multi-paradigm.

### Mint

Mint doesn't have an official definition yet, so I'll try to do my best to summarize it in a short paragraph:

> Mint is a programming language which compiles to JavaScript. Created specifically for writing client side web applications. It is fundamentally strongly typed, functional with some object-oriented parts sprinkled in.
>

# Type checking

The languages should support some sort of type checking which is important because it makes our code safer and less buggy.

### JavaScript

For JavaScript there are third party tools for type checking, like [Flow](https://flow.org) which we will use, but before we can do actual type checking we need to compile our typed JavaScript  (with type annotations) to regular JavaScript (removing type annotations) which the browser can use.

For that we will use [Babel](https://babeljs.io) so we need to install some packages to make it work: `babel-core`  `babel-preset-react` (which includes the Flow preset for some reason) also we install `babel-preset-es2015` and `babel-preset-stage-0` to make advanced JavaScript features available.

To configure babel we need to create a `.babelrc` file:

```
{
  "presets": ["es2015", "react", "stage-0"]
}
```

Also we need to install `flow-bin` to do the actual type checking and `flow-typed` to install type definitions for the packages we use.

### Mint

Mint comes with it's own type checker, so you don't need to do anything, it's automatically working under the hood.

### Comparison

To get type checking in JavaScript you need a third party tool, in Mint it's built in.

### Statistics

| Statistics           | JavaScript                                                   | Mint  |
| -------------------- | ------------------------------------------------------------ | ----- |
| Lines of code        | **4**                                                        | **0** |
| Third party packages | **6** <br />`babel-core` <br />`babel-preset-react`<br />`babel-preset-es2015`<br />`babel-preset-stage-0`<br />`flow-bin`<br />`flow-typed` | **0** |

# Development Server

Our development environment should be able to to the following things:

* compile our code into a single file
* recompile the code when the source files change, and refresh the browser
* serve static files from the directory
* provide error messages if there is a syntax or type error
* fall back to the `index.html` file if the route does not match a static file

### JavaScript

To compile our code we can use [Webpack](https://webpack.js.org) with the `webpack` `webpack-cli` and `webpack-dev-server` packages and for using Babel we need the `babel-loader` package. 

After installing them we configure them using the `webpack.config.js` file:

```javascript
const path = require("path");

module.exports = {
  context: path.resolve(__dirname, "src"),
  mode: 'development',
  // The main.jsx will be compiled
  entry: {
    main: ["main.jsx"]
  },
  // This tells webpack how to resolve things
  resolve: {
    modules: [path.resolve("./src"), "node_modules"],
    extensions: [".jsx"]
  },
  module: {
    // This tells webpack to use babel
    rules: [
      {
        test: /\.jsx$/,
        use: {
          loader: 'babel-loader',
        }
      }
    ]
  },
  // Configuration for the development server
  devServer: {
    // Serve static files from the public folder
    contentBase: './public',
    // Fallback to the index.html
    historyApiFallback: {
      rewrites: [
        {
          from: '/./',
          to: '/'
        }
      ]
    }
  }
}
```

In the configuration:

* we are transforming our code using the Babel with the `babel-loader` package
* setting up the fall back to `index.html` for the server
* specify which files to compile and in which directories
* specify the static file directory
* specify the main file

After that we need to create the actual `public/index.html` file which will be served:

```
<!DOCTYPE html>
<html>
<head>
  <title></title>
</head>
<body>
  <div id="root"></div>
  <script type="text/javascript" src="/main.js"></script>
</body>
</html>
```

After that the development server can be started with: `webpack-dev-server`

### Mint

In Mint the development server is built into the binary. After initializing our project with `mint init` the only thing we need to do is to start it with: `mint start` 

### Comparison

In Mint it's a built in feature, while in JavaScript you need to use a third party package to achieve the same setup.

### Statistics

| Statistics           | JavaScript                                                   | Mint  |
| -------------------- | ------------------------------------------------------------ | ----- |
| Lines of code        | **44**                                                       | **0** |
| Third party packages | **4** `webpack` `webpack-dev-server` `webpack-cli` `babel-loader` | **0** |

# View

For the view layer the following needs to be met:

* the styling should be scoped to the current component and it should be written in CSS, in the same file
* the properties of component should be type checked (preferably at compile time but runtime is OK), also default value for them should be provided

For the sake of the example, we are going to implement a simple counter component:

* it should display a counter
* it should have two buttons, one for decrementing the counter and one for incrementing it
* the background color should be reddish (`orangered`) if it's below zero, and greenish (`limegreen`) if it's above ten

### JavaScript
Flow automatically checks prop types we just need to create a type for them and use it, for the default properties we can use a static class property, and for styling we can use [styled-components](https://github.com/styled-components/styled-components).

```jsx
// @flow

import React, { Component } from "react";
import styled from "styled-components";

/* This is the styling for the base div. */
const BaseDiv = styled.div`
  background: ${props => props.background};
  border-radius: 5px;
  transition: 320ms;
  display: flex;
  padding: 20px;
  margin: 20px;
`

/* This is the styling for the counter span. */
const CounterSpan = styled.span`
  font-family: sans;
  font-size: 20px;
  padding: 0 20px;
`

/* These are the property type definitons. */
type Props = {
  onIncrement: () => void,
  onDecrement: () => void,
  counter: number
};

export default class Counter extends Component<Props> {
  /* These are the default property values. */
  static defaultProps = {
    onIncrement: () => null,
    onDecrement: () => null,
    counter: 0
  }

  /* This is a function to return the background color. */
  background () {
    const { counter } = this.props

    if (counter >= 10) {
      return "lightgreen"
    } else {
      if (counter < 0) {
        return "orangered"
      } else {
        return "#F2F2F2"
      }
    }
  }

  /* Renders the component. */
  render () {
    const { counter, onDecrement, onIncrement} = this.props

    return <BaseDiv background={this.background()}>
      <button onClick={() => onDecrement()}>
        Decrement
      </button>

      <CounterSpan>
        { counter }
      </CounterSpan>

      <button onClick={() => onIncrement()}>
        Increment
      </button>
    </BaseDiv>
  }
}
```

Also to be able to display our counter we need to add it to the DOM.

```javascript
// @flow

/* Default react imports. */
import React, { Component } from "react";
import styled from "styled-components";
import ReactDom from "react-dom";

/* Import the counter component. */
import Counter from './counter.jsx';

/* The base style. */
const StyledDiv = styled.div`
  justify-content: center;
  flex-direction: column;
  align-items: center;
  font-family: sans;
  display: flex;
  height: 100vh;
`

/* This is our main component. */
class Main extends Component {
  render () {
    return <StyledDiv><Counter/></StyledDiv>
  }
}

/* Get the root element. */
const root = document.getElementById('root')

/* If there is a root element render the main component. */
if (root) { 
  ReactDOM.render(<Main/>, root) 
}
```

### Mint

In Mint you can define properties one-by-one with type and default value, styling is done with `style` blocks.

```
component Counter {
  /* Here we are defining the properties of the counter. */
  property onIncrement : Function(a) = () : Void => { void }
  property onDecrement : Function(a) = () : Void => { void }
  property counter : Number = 0
 
  /* This is the styling for the base div. */
  style base {
    background: {background};
    border-radius: 5px;
    transition: 320ms;
    display: flex;
    padding: 20px;
    margin: 20px;
  }

  /* This is the styling for the counter span. */
  style counter {
    font-family: sans;
    font-size: 20px;
    padding: 0 20px;
  }

  /* This is a computed property for the background color. */
  get background : String {
    if (counter >= 10) {
      "lightgreen"
    } else if (counter < 0) {
      "orangered"
    } else {
      "#F2F2F2"
    }
  }

  fun render : Html {
    <div::base>
      <button onClick={(event : Html.Event) : Void => { onDecrement() }}>
        <{ "Decrement" }>
      </button>

      <span::counter>
        <{ Number.toString(counter) }>
      </span>

      <button onClick={(event : Html.Event) : Void => { onIncrement() }}>
        <{ "Increment" }>
      </button>
    </div>
  }
}
```

To display something on the screen we need to define the `Main` component:

```
component Main {
  style base {
    justify-content: center;
    flex-direction: column;
    align-items: center;
    font-family: sans;
    display: flex;
    height: 100vh;
  }

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

### Comparison

Both implementations follow pretty much the same semantics and look very similar, there are some differences though:

* In JavaScript there are styled elements (different components), in Mint a `style` can be applied to an element individually
* In JavaScript values for the styles needs to be passed explicitly, in Mint the `style` blocks use the same scope as functions and computed properties of the component
* In JavaScript properties are defined in two blocks, in Mint one-by-one.
* In JavaScript the static CSS is duplicated for each version of the style using different class names (different background color),  in Mint there is only one selector using CSS variables
* In JavaScript the text content is implicit, in Mint it is explicit

### Statistics

| Statistics           | JavaScript                                                | Mint   |
| -------------------- | --------------------------------------------------------- | ------ |
| Lines of code        | **60**                                                    | **52** |
| Third party packages | **3**<br />`react`  `react-dom` `styled-components`<br /> | **0**  |

# State

For the state we need a globally accessible entity, which contains the state of the application (counter) and the functions which lets us mutate it, for lack of a better term let's call it a **store**. 

### JavaScript

For JavaScript there are a lot of frameworks for handling data in an application using the store paradigm: [Redux](https://redux.js.org), [Redux Saga](https://redux-saga.js.org), [Mobx](https://github.com/mobxjs/mobx) just to name a few,  we are going to use Redux here.

In a new file we create the **actions**, **action creators**, **reducer** and finally the **store**.

```javascript
// @flow

import { createStore } from "redux";

/* These are the actions we can take. */
const INCREMENT = "INCREMENT";
const DECREMENT = "DECREMENT";

/* The type of the state. */
type State = {|
  counter: number
|};

/* The type of the action. */
type Action = {|
  payload: null,
  type: string
|};

/* This is the initial state. */
const initialState: State = {
  counter: 0
};

/* This is the reducer which steps the state forward. */
const reducer = function(state: State = initialState, action: Action): State {
  switch (action.type) {
    case INCREMENT:
      return { ...state, counter: state.counter + 1 };

    case DECREMENT:
      return { ...state, counter: state.counter - 1 };

    default:
      return state;
  }
};

/* This is an action creater for the increment action. */
export const increment = (): Action => {
  return {
    type: INCREMENT,
    payload: null
  };
};

/* This is an action creater for the decrement action. */
export const decrement = (): Action => {
  return {
    type: DECREMENT,
    payload: null
  };
};

/* This is a function which creates a store. */
export const store = createStore(reducer, initialState);
```

After that we need to connect the store to our component:

```javascript
...

/* We need to import the action creators and the store from the other file. */
import { increment, decrement } from "./store.jsx";

/* The connect comes from the react-redux package. */
import { connect } from "react-redux";

...

/* This is our main component which is connected to the store. */
class Main extends Component {
  render() {
    const { counter, onIncrement, onDecrement } = this.props;

    return (
      <div>
        <Counter
          onIncrement={onIncrement}
          onDecrement={onDecrement}
          counter={counter}
        />
      </div>
    );
  }
}

/* We need to map the state from the store to our components properties. */
const mapStateToProps = state => {
  return {
    counter: state.counter
  };
};

/* We need to map the actions from the store to our components properties. */
const mapDispatchToProps = dispatch => {
  return {
    onIncrement: () => {
      dispatch(increment());
    },
    onDecrement: () => {
      dispatch(decrement());
    }
  };
};

/*
Finally we are creating a new component by connecting the store the original one, using the two functions above.
*/
export const App = connect(
  mapStateToProps,
  mapDispatchToProps
)(Main);
```

### Mint

In Mint there are only two things we need to do to use a `store`:

Declare them:
```
store Store {
  /* The data lives in states. */
  state counter : Number = 0
    
  /* A store can have any number of functions. */
  fun increment : Promise(Never, Void) {
    /* The next statements steps the state forward based on the previous state. */
    next { counter = counter + 1 }
  }

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

And connect them to a component:
```
component Main {
  /* 
  We are connecting to the store and explicitly exposing 
  it's properties and functions to be available for the 
  component.
  */
  connect Store exposing { counter, increment, decrement }
  
  ...

  fun render : Html {
  	<div::base>
      <Counter 
        onIncrement={increment} 
        onDecrement={decrement}
        counter={counter}/>
    </div>
  }
}
```

### Comparison

The basic idea of the two approaches are the same, although the Redux implementation is more complex:

* there are more types of entities (actions, action-creators, store, reducer)
* mapping state and actions to properties
* external functions which needed to be used correctly (`connect`, `createStore`)
* actions have a specific type, usually with a name

In Mint everything is typed checked even the connection between a component and a store, so for example if we happen to expose something that is not available on the store we get a nice error message.

There are notable difference between the implementations:

* Redux uses the components properties to pass the actions and data, while in Mint it's available in the components scope
* In Redux there is a [HOC component](https://reactjs.org/docs/higher-order-components.html) which connects the store to the base component

### Statistics

| Name                 | JavaScript                  | Mint   |
| -------------------- | --------------------------- | ------ |
| Lines of code        | **103**                     | **13** |
| Third party packages | **2** `redux` `react-redux` | **0**  |

# Routing

Our example application for testing purposes should implement three routes:

* `/` to display the counter with the starting value of `0`
* `/10` (or any number) to display the counter with the starting value which comes from the path
* `/about` to display some information about the application (dummy text is enough)

There should be links for all three routes, which the application should handle.

### JavaScript

In this case we are going to use [react-router](https://reacttraining.com/react-router/web/guides/philosophy).

There are a number of steps we need to take in order to make routing work.

First we need to modify our store to be able to set the count directly:

```javascript
...

/* Add a new action. */
const SET = "SET";

...

/* Update the Action type. */
export type Action = {|
  payload: number | null,
  type: string
|};

...
    /* Add a new branch in the reducer for the given action. */
    case SET:
      return { ...state, counter: action.payload || 0 };
...

/* Create an action creator for the new action. */
export const set = (payload : number): Action => {
  return {
    payload: payload,
    type: SET
  };
};

```

Then wen need to create a new component which handles the routing, let's call it `Page`

```javascript
/* Import the necessary entitites. */
import { BrowserRouter as Router, Route, Link } from 'react-router-dom'

/* Import to store creator. */
import { store } from "./store.jsx";

/* 
Create a functional component which parses the count from the route
and passes it to the App component.
*/
const RoutedApp = (props) =>  {
  const parsed = Number.parseInt(props.match.params.count)
  const initialCount = parsed || 0
	
  /* The key is needed because the `componentDidMount` function sets the counter. */
  return <App 
  	key={initialCount.toString()}
  	initialCount={ initialCount} 
  	store={store} />
}

/* Create a functional component which has to rooting. */
const Page = () =>
  <Router>
    <div>
      <ul>
        <li><Link to="/">0</Link></li>
        <li><Link to="/1">1</Link></li>
        <li><Link to="/about">About</Link></li>
      </ul>

      <hr/>

      <Route exact path="/about" component={<div></div>}/>
      <Route exact path="/" render={RoutedApp}/>
      <Route path="/:count" component={RoutedApp}/>
    </div>
  </Router>
```

Then we need to modify our `App` component  to set the `counter` when it loads.

```javascript
/* Expose the set function from the store. */
import { increment, decrement, set } from "./store.jsx";

class Main extends Component {
  /* When mounted set the counter. */
  componentDidMount () {
    this.props.set(this.props.initialCount)
  }
  
  ...
}
  
const mapDispatchToProps = dispatch => {
  ... 
  /* Add a prop to dispatch the set action. */
  set: (payload : number) => {
    dispatch(set(payload));
  }
}
```

### Mint

First we need to add a function to our store to set the `counter` and a `state` to denote which page is the active one and a function to set the `page`:

```
store Store {
  /* Create a new state for the page. */
  state page : String = ""
  
  ...
  
  fun setCounter (counter : Number) : Promise(Never, Void) {
    next { counter = counter }
  }
  
  fun setPage (page : String) : Promise(Never, Void) {
    next { page = page }
  }
}
```

Then we handle paths using the `routes` top-level block:

```
/* In a routes block you can define the routes of the application. */
routes {
  /* 
  This matches the /about path, needs to be first because 
  routes are matched from top to bottom. 
  */
  /about {
    /* We can directly call store functions. */
    Store.setPage("about")
  }
  
  /* This matches the index path. */
  / {
    /* Sequence allows us to do more things in sequence. */
    sequence {
      Store.setCounter(0)
      Store.setPage("counter")
    }
  }
  
  /* This matches the /10 path. */
  /:value (value : String) {
    sequence {
      /* Here we convert a string to a number safely. */
      counter = 
        value
      	|> Number.fromString()
      	|> Maybe.withDefault(0)
      	
    	Store.setCounter(counter)
    	Store.setPage("counter")
    }
  }  
}
```

Then we need to modify our Main component:

```
component Main {
  /* Expose the page property. */
  connect Store exposing { counter, increment, decrement, page }

  ...

  get content : Html {
    /* Decide what to render based on the page. */
    case (page) {
      "counter" =>
        <Counter
          onIncrement={increment}
          onDecrement={decrement}
          counter={counter}/>

      "about" =>
        <div>
          <{ "about" }>
        </div>

      =>
        <div>
          <{ "" }>
        </div>
    }
  }

  fun render : Html {
    <div::base>
      <ul>
        <li>
          <a href="/">
            <{ "/0" }>
          </a>
        </li>

        <li>
          <a href="/10">
            <{ "/10" }>
          </a>
        </li>

        <li>
          <a href="/about">
            <{ "/about" }>
          </a>
        </li>
      </ul>

      <{ content }>
    </div>
  }
}
```

### Comparison

The two implementations of the routing is fundamentally different:

* In JavaScript it is component based (render something when the path changes), while 
  in Mint it is action based (do something when the path changes)
* In JavaScript the routing does not interact with the store, in Mint it does
* In JavaScript the routing is handled by the developer, while in Mint it's handled by the runtime
* In JavaScript a component is needed for the links, in Mint they are plain `a` tags and the runtime handles the navigation

### Statistics

| Name                 | JavaScript           | Mint   |
| -------------------- | -------------------- | ------ |
| Lines of code        | **68**               | **47** |
| Third party packages | **1** `react-router` | **0**  |

# Networking

To demonstrate how to fetch something from the network, a simple text files content should be displayed on the about page which is fetched dynamically.

### JavaScript

In JavaScript this is straight forward to do using the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API). 

We are going to create a stateful component for this:

```javascript
/* Import React and Component. */
import React, { Component } from "react";

/* The component for the about page. */
export default class About extends Component {
  /* In the constructor set the initial state. */
  constructor(props) {
    super(props)

    this.state = {
      /* This field is for tracking the status of the request. */
      status: "INITIAL",
      /* The content which will be displayed once loaded. */
      content: ""
    }
  }

  /* When the component is mounted. */
  componentDidMount() {
    /* Set the status as loading. */
    this.setState({ status: "LOADING" }, () => {
      /* Fetch the data. */
      fetch('/about.txt')
      .then((response) => {
        /* Get the text. */
        response
        .text()
        .then((body) => {
          /* Set the status to loaded and content. */
          this.setState({
            status: "LOADED",
            content: body
          })
        })
      })
      .catch(() => {
        /* On an error set the status. */
        this.setState({
          status: "ERRORED",
          content: ""
        })
      })
    })
  }

  render () {
    /* Based on the status render things. */
    switch (this.state.status) {
      case "LOADING":
        return <div>Loading...</div>
      case "ERRORED":
        return <div>Could not load the content...</div>
      case "LOADED":
        return <div>{this.state.content}</div>
      default:
        return false
    }
  }
}
```

After we have the component we need to update or `Page` component to include it:

```javascript
...
<Route exact path="/about" component={About}/>
...
```

### Mint

In Mint we need to use the `Http` module from the standard library `mint-core` which is installed automatically on project initialization.

```
/* Define an enum for the status. */
enum Status {
  Initial
  Loading
  Loaded
  Errored
}

/* The component for the about page. */
component About {
  /* A state to track the status. */
  state status : Status = Status::Initial

  /* A state for the content. */
  state content : String = ""

  /* When the component is mounted. */
  fun componentDidMount : Promise(Never, Void) {
    /* In a sequence expression statements are executed asynchronously in sequence. */
    sequence {
      /* Set the status to loading. */
      next { status = Status::Loading }

      /*
      Get the response and unpack it from a
      Result(Http.ErrorResponse, Http.Response).
      */
      response =
        "/about.txt"
        |> Http.get()
        |> Http.send()

      /* Set the status to loaded and the content. */
      next
        {
          status = Status::Loaded,
          content = response.body
        }
    } catch Http.ErrorResponse => error {
      /* On an error set the status to errored. */
      next
        {
          status = Status::Errored,
          content = ""
        }
    }
  }

  /* Renders the component. */
  fun render : Html {
    /* Renders things based on status. */
    case (status) {
      Status::Initial => Html.empty()

      Status::Loading =>
        <div>
          <{ "Loading..." }>
        </div>

      Status::Errored =>
        <div>
          <{ "Could not load the content..." }>
        </div>

      Status::Loaded =>
        <div>
          <{ content }>
        </div>
    }
  }
}
```

Here also we need to update the `Main` component to display it:

```
...
"about" => <About/>
...
```

### Comparison

The implementation is basically following the same steps but there are differences:

* In JavaScript we can use promises for asynchronous tasks, in Mint it is a language feature using the `sequence` expressions
* In JavaScript we can leave out error handling, in Mint it is enforced with nice error messages
* In JavaScript we need to use `this.state` and `this.setState  `for state handling, in Mint it is a built in feature using the name of the states and  `next` keywords
* In JavaScript we need to use strings for the `status` in Mint we can use an `enum`

### Statistics

| Statistics           | JavaScript | Mint              |
| -------------------- | ---------- | ----------------- |
| Lines of code        | **60**     | **72**            |
| Third party packages | **0**      | **1** `mint-core` |

# Testing

We will write three simple test for the `Counter` component:

* displays the counter properly
* clicking on the increment button increments the counter
* clicking on the decrement button decrements the counter

### JavaScript

We will use [Jest](https://jestjs.io) and [Enzyme](https://github.com/airbnb/enzyme) for testing the `Counter` component. Also we need to add `enzyme-adapter-react-16` for Enzyme to work with React, also we need set some configuration in `package.json` for Jest to avoid an error:

```
...
 "jest": {
    "testURL": "http://localhost/"
  }
}
```

Now we can create a test file for our component:

```javascript
/* Import things. */
import Adapter from 'enzyme-adapter-react-16';
import React, { Component } from 'react';
import Enzyme, { mount } from 'enzyme';

/* Configure enzyme. */
Enzyme.configure({adapter: new Adapter()});

/* Import our Counter component. */
import Counter from './counter.jsx';

/* A test component which handles the state. */
class TestComponent extends Component {
  constructor(props) {
    super(props)
    this.state = { counter: 0 }
  }

  increment() {
    this.setState({ counter: this.state.counter + 1 })
  }

  decrement() {
    this.setState({ counter: this.state.counter - 1 })
  }

  render() {
    return <Counter
      onIncrement={() => this.increment()}
      onDecrement={() => this.decrement()}
      counter={this.state.counter}
      />
  }
}

it('displays the counter', () => {
  const counter = mount(<TestComponent/>);

  expect(counter.find('span').text()).toEqual('0');
});

it('decrements the counter', () => {
  const counter = mount(<TestComponent/>);

  expect(counter.find('span').text()).toEqual('0');

  // Simulate a click and update the view.
  counter.find('button').first().simulate("click")
  counter.update()

  expect(counter.find('span').text()).toEqual('-1');
});

it('increments the counter', () => {
  const counter = mount(<TestComponent/>);

  expect(counter.find('span').text()).toEqual('0');

  counter.find('button').last().simulate("click")
  counter.update()

  expect(counter.find('span').text()).toEqual('1');
});
```

To run the tests we just run: `jest`

### Mint

In Mint the language has two keywords specifically for testing: `suite` and `test`, with them we can create tests easily:

```
/* Create component for testing the counter which contains the state. */
component TestCounter {
  state counter : Number = 0

  fun render : Html {
    <Counter
      onIncrement={() : Promise(Never, Void) => { next { counter = counter + 1 } }}
      onDecrement={() : Promise(Never, Void) => { next { counter = counter - 1 } }}
      counter={counter}/>
  }
}

/* A suite is a group of tests. */
suite "Counter" {
  test "Displays counter" {
    /*
    We are using the Test.Html module for testing. The with keyword
    allows us to call its functions in the current scope.
    */
    with Test.Html {
      <TestCounter/>
      |> start()
      |> assertTextOf("span", "0")
    }
  }

  test "Clicking on increment increments the counter" {
    with Test.Html {
      <TestCounter/>
      |> start()
      |> assertTextOf("span", "0")
      |> triggerClick("button:last-child")
      |> assertTextOf("span", "1")
    }
  }

  test "Clicking on decrement decrements the counter" {
    with Test.Html {
      <TestCounter/>
      |> start()
      |> assertTextOf("span", "0")
      |> triggerClick("button")
      |> assertTextOf("span", "-1")
    }
  }
}
```

To run the tests just call the binary with the test command: `mint test`

### Comparison

Both implementations are integration tests:

* In JavaScript to run tests we need third party packages, in Mint it's built in
* In JavaScript Jest runs the tests using nodejs while Mint runs the tests in an actual browsers
* In Mint there is a test server which allows for manually testing in the browser

### Statistics

| Name                 | JavaScript                                      | Mint   |
| -------------------- | ----------------------------------------------- | ------ |
| Lines of code        | **62**                                          | **47** |
| Third party packages | **3** `jest` `enzyme` `enzyme-adapter-react-16` | **0**  |

# Error Messages

Our development environment should provide nice easy to understand error messages.

### JavaScript

In JavaScript we need to handle three types or errors, of which only one of can be displayed in the browser:

* Compile time errors from Webpack
* Type errors from Flow
* Runtime errors from the browser

To enable compile time errors we need to add the following line to our `webpack.config.js`:

```
...
devServer: {
  overlay: true
...
```

![Webpack Error](https://thepracticaldev.s3.amazonaws.com/i/cy54bdmr5obhn9peknk9.png)

Flow errors can only be displayed in the console after running the binary:

![Flow Error](https://thepracticaldev.s3.amazonaws.com/i/qahizh3w69wslpsq25er.png)

Runtime errors can be seen in the browsers console.

### Mint

In Mint there are a number of error types (syntax, type, etc...) but all of them are displayed in the same way either in the console (when running console only commands) or in the browser but with exactly the same content:

![Mint Browser Error](https://thepracticaldev.s3.amazonaws.com/i/p8ynymgipizqwbzb40qt.png)

![Mint Console Error](https://thepracticaldev.s3.amazonaws.com/i/19hxd5bir8wi134be0l9.png)

Runtime errors can be seen in the browsers console, although they should not happen because of the type system.

### Comparison

Mint errors tend to be more informative for example when miscalling a function the message shows the where the function is called and it's source. 

# Formatting

It is a standard practice to format our source code to a specific style, our environment should support that.

### JavaScript

To format our JavaScript files we only need to install [Prettier](https://prettier.io) which can handle a number of languages not just JavaScript.

After installing we only need to call `prettier src/* --write` and our code is formatted in place.

### Mint 

Mint has a built in formatter which can be invoked with the `mint format` command, also the development server can be configured to format files when they change with the `--auto-format` argument.

### Comparison

It's equally simple to format our code in both languages the only difference is that in JavaScript it's a third party tool.

### Statistics

| Name                 | JavaScript       | Mint  |
| -------------------- | ---------------- | ----- |
| Lines of code        | **0**            | **0** |
| Third party packages | **1** `prettier` | **0** |

# Building production files

Our application is ready to be deployed to production, but for that we need to produce compressed and minified files. Also it would be nice to generate favicons from a base icon.

### JavaScript

To minify our JavaScript output we will use [UglifyJs](https://github.com/mishoo/UglifyJS2) via the `uglifyjs-webpack-plugin` plugin. To generate favicons we need to install the `html-webpack-plugin` and `favicons-webpack-plugin` plugins.

After installing them it we need to configure them in our `webpack.config.js` file:

```javascript
/* Import them. */
const FaviconsWebpackPlugin = require('favicons-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
...
  plugins: [
    new FaviconsWebpackPlugin('../public/logo.png'),
    new HtmlWebpackPlugin({
      template: '../public/index.html'
    })
  ],
  optimization: {
    minimizer: [
      new UglifyJsPlugin()
    ]
  }
}
```

Also we need to create a new configuration for the build `webpack.prod.config.js`:

```javascript
const common = require('./webpack.config.js');

module.exports = {
  ...common,
  mode: 'production'
}
```

After that can just call `webpack --config webpack.prod.config.js` to build our production files into the `dist` directory.

### Mint

_Currently Mint does not minifies the production files, although it can be minified with any tool out there. It is planned to be implemented soon._

To generate favicons, we only need to specify the icon for the application (this feature requires ImageMagick to be installed):

```
...
  "application": {
    ...
    "icon": "assets/logo.png"
  }
...
```

Then we can generate the production files to the `dist` directory with the `mint build` command.

#### Bonus: Progressive Web Application

Mint by default generates the `manifest.json` and a service worker for all applications, all we need to do is set the corresponding fields in the `mint.json` file:

```
{
  ...
  "application": {
    ...
    "icon": "assets/logo.png",
    "name": "Counter",
    "orientation": "portrait",
    "display": "standalone",
    "theme-color": "#FFF",
    "meta": {
      "viewport": "width=device-width, initial-scale=1, shrink-to-fit=no",
      "description": "A simple counter example",
      "charset": "utf-8"
    }
  }
  ...
}
```

After building it again and deploying it to a secure website (with https) it is installable on mobile phones.

### Comparison

Using JavaScript third party tools are needed for building the production files, in Mint it's a built in feature.

### Statistics

| Name                 | JavaScript                                                   | Mint  |
| -------------------- | ------------------------------------------------------------ | ----- |
| Lines of code        | **14**                                                       | **1** |
| Third party packages | **3** <br />`html-webpack-plugin`<br />`uglifyjs-webpack-plugin`<br />`favicons-webpack-plugin` | **0** |

# Overall Statistics

Here you can find the final statistics of the two implementations (all of them are collected on a single machine during the same conditions):

| Name                           | JavaScript  | Mint                                              |
| ------------------------------ | ----------- | ------------------------------------------------- |
| Lines of code (`wc -l`)        | **408**     | **258**                                           |
| Production build time          | **21.36 s** | **854 ms**                                        |
| Command line utilities used    | **6**       | **1**                                             |
| Third party packages           | **24**      | **1**                                             |
| All installed packages         | **1426**    | **1**                                             |
| Packages size (`node_modules` / `.mint`)  | **296 MB**  | **744 kB**                                        |
| Bundle Size (`dist` directory) | **1.3 MB**  | **315 kB**                                        |
| Bundle Size (`.js`)            | **212 kB** (minified) | **204 kB** (unminifed) <br />**176 kB** (minified) |

As you can see above the main difference is in the third party packages and packages size. In JavaScript it's bigger because it contains the tools as well.

# Ending Thoughts

_This part is probably subjective (since I'm the author of Mint) so take it as is._

In my opinion this really shows how over engineered todays front-end development is (1426 packages for such a simple application??). Also it's not enough that a developer needs to learn basics of web development (HTML, CSS, JavaScript) they need to learn all of these dependencies as well, which come with their own documentation and that can be overwhelming. 

This is basically why I created Mint so it would be easier to write web applications without all the hassle. I hope this article shows what Mint can do and how easy it is to use it.

If I piqued your interest you can find all the information to get started on the [website](https://www.mint-lang.com) or if you like to contribute check out the Github repository:

{% github mint-lang/mint %}

The full code for both applications can be found here (on separate branches):

{% github mint-lang/mint-vs-x %}

Also if you are interested in more applications written in Mint I suggest you check out these repositories:

{% github mint-lang/mint-website %}

{% github mint-lang/mint-realworld %}