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 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 so we need to install some packages to make it work: babel-corebabel-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.
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 with the webpackwebpack-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:
constpath=require("path");module.exports={context:path.resolve(__dirname,"src"),mode:'development',// The main.jsx will be compiledentry:{main:["main.jsx"]},// This tells webpack how to resolve thingsresolve:{modules:[path.resolve("./src"),"node_modules"],extensions:[".jsx"]},module:{// This tells webpack to use babelrules:[{test:/\.jsx$/,use:{loader:'babel-loader',}}]},// Configuration for the development serverdevServer:{// Serve static files from the public foldercontentBase:'./public',// Fallback to the index.htmlhistoryApiFallback:{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:
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
4webpackwebpack-dev-serverwebpack-clibabel-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.
// @flowimportReact,{Component}from"react";importstyledfrom"styled-components";/* This is the styling for the base div. */constBaseDiv=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. */constCounterSpan=styled.span`
font-family: sans;
font-size: 20px;
padding: 0 20px;
`/* These are the property type definitons. */typeProps={onIncrement:()=>void,onDecrement:()=>void,counter:number};exportdefaultclassCounterextendsComponent<Props>{/* These are the default property values. */staticdefaultProps={onIncrement:()=>null,onDecrement:()=>null,counter:0}/* This is a function to return the background color. */background (){const{counter}=this.propsif (counter>=10){return"lightgreen"}else{if (counter<0){return"orangered"}else{return"#F2F2F2"}}}/* Renders the component. */render (){const{counter,onDecrement,onIncrement}=this.propsreturn<BaseDivbackground={this.background()}><buttononClick={()=>onDecrement()}>
Decrement
</button><CounterSpan>{counter}</CounterSpan><buttononClick={()=>onIncrement()}>
Increment
</button></BaseDiv>}}
Also to be able to display our counter we need to add it to the DOM.
// @flow/* Default react imports. */importReact,{Component}from"react";importstyledfrom"styled-components";importReactDomfrom"react-dom";/* Import the counter component. */importCounterfrom'./counter.jsx';/* The base style. */constStyledDiv=styled.div`
justify-content: center;
flex-direction: column;
align-items: center;
font-family: sans;
display: flex;
height: 100vh;
`/* This is our main component. */classMainextendsComponent{render (){return<StyledDiv><Counter/></StyledDiv>
}}/* Get the root element. */constroot=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 reactreact-domstyled-components
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, Redux Saga, 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.
// @flowimport{createStore}from"redux";/* These are the actions we can take. */constINCREMENT="INCREMENT";constDECREMENT="DECREMENT";/* The type of the state. */typeState={|counter:number|};/* The type of the action. */typeAction={|payload:null,type:string|};/* This is the initial state. */constinitialState:State={counter:0};/* This is the reducer which steps the state forward. */constreducer=function(state:State=initialState,action:Action):State{switch (action.type){caseINCREMENT:return{...state,counter:state.counter+1};caseDECREMENT:return{...state,counter:state.counter-1};default:returnstate;}};/* This is an action creater for the increment action. */exportconstincrement=():Action=>{return{type:INCREMENT,payload:null};};/* This is an action creater for the decrement action. */exportconstdecrement=():Action=>{return{type:DECREMENT,payload:null};};/* This is a function which creates a store. */exportconststore=createStore(reducer,initialState);
After that we need to connect the store to our component:
.../* 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. */classMainextendsComponent{render(){const{counter,onIncrement,onDecrement}=this.props;return (<div><CounteronIncrement={onIncrement}onDecrement={onDecrement}counter={counter}/>
</div>
);}}/* We need to map the state from the store to our components properties. */constmapStateToProps=state=>{return{counter:state.counter};};/* We need to map the actions from the store to our components properties. */constmapDispatchToProps=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.
*/exportconstApp=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 which connects the store to the base component
Statistics
Name
JavaScript
Mint
Lines of code
103
13
Third party packages
2reduxreact-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.
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:
.../* Add a new action. */constSET="SET";.../* Update the Action type. */exporttypeAction={|payload:number|null,type:string|};.../* Add a new branch in the reducer for the given action. */caseSET:return{...state,counter:action.payload||0};.../* Create an action creator for the new action. */exportconstset=(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
/* Import the necessary entitites. */import{BrowserRouterasRouter,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.
*/constRoutedApp=(props)=>{constparsed=Number.parseInt(props.match.params.count)constinitialCount=parsed||0/* The key is needed because the `componentDidMount` function sets the counter. */return<Appkey={initialCount.toString()}initialCount={initialCount}store={store}/>
}/* Create a functional component which has to rooting. */constPage=()=><Router><div><ul><li><Linkto="/">0</Link></li><li><Linkto="/1">1</Link></li><li><Linkto="/about">About</Link></li></ul>
<hr/><Routeexactpath="/about"component={<div></div>}/><Routeexactpath="/"render={RoutedApp}/>
<Routepath="/:count"component={RoutedApp}/>
</div>
</Router>
Then we need to modify our App component to set the counter when it loads.
/* Expose the set function from the store. */import{increment,decrement,set}from"./store.jsx";classMainextendsComponent{/* When mounted set the counter. */componentDidMount (){this.props.set(this.props.initialCount)}...}constmapDispatchToProps=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
1react-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.
We are going to create a stateful component for this:
/* Import React and Component. */importReact,{Component}from"react";/* The component for the about page. */exportdefaultclassAboutextendsComponent{/* 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>Couldnotloadthecontent...</div>
case"LOADED":return<div>{this.state.content}</div>
default:returnfalse}}}
After we have the component we need to update or Page component to include it:
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.setStatefor 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
1mint-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 and 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:
/* Import things. */importAdapterfrom'enzyme-adapter-react-16';importReact,{Component}from'react';importEnzyme,{mount}from'enzyme';/* Configure enzyme. */Enzyme.configure({adapter:newAdapter()});/* Import our Counter component. */importCounterfrom'./counter.jsx';/* A test component which handles the state. */classTestComponentextendsComponent{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<CounteronIncrement={()=>this.increment()}onDecrement={()=>this.decrement()}counter={this.state.counter}/>
}}it('displays the counter',()=>{constcounter=mount(<TestComponent/>);expect(counter.find('span').text()).toEqual('0');});it('decrements the counter',()=>{constcounter=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',()=>{constcounter=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
3jestenzymeenzyme-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
...
Flow errors can only be displayed in the console after running the binary:
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:
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 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
1prettier
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 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:
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:
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) 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 or if you like to contribute check out the Github repository:
🍃 A refreshing programming language for the front-end web
A refreshing programming language for the front-end web, aiming to solve the most common issues of Single Page Applications (SPAs) at a language level:
Reusable components
Styling
Routing
Global and local state handling
Synchronous and asynchronous computations that might fail
While focusing on:
Developer happiness
Fast compilation
Readability
Project Status
The project is in development, we are still tweaking the language and standard library.
There are some bigger applications which can be used as examples / learning material:
This repository contains the implementation of a sample application which is used
in "Mint vs X" blog posts of comparing Mint with popular frontend frameworks /
languages
Implementations
All of the implementation lives in separate branches:
This codebase was created to demonstrate a fully fledged fullstack application built with Mint including CRUD operations, authentication, routing, pagination, and more.
We've gone to great lengths to adhere to the Mint community styleguides & best practices.
For more information on how to this works with other frontends/backends, head over to the RealWorld repo.
How it works
This implemenation only uses the Mint language and it's standard library without any third party dependencies.
There are a few difference to other implementations:
since Mint has a built in way of styling HTML elements we wanted to showcase that, so the design of the
application greatly differs from the original one