ReasonML Marvel Tutorial — part 0

Wojciech Bilicki
9 min readDec 10, 2017

Introduction

So a few months ago while I was listening to the React Native Radio podcast, I’ve heard this catchword Reason. At the very beginning, I didn’t know what it was all about and I decided to ignore it. Yet, after some time it drilled into my mind and I decided to check it out.

What is ReasonML? It’s basically set of tools that lets you write your good old React apps using JS developer friendly OCaml syntax. Let me elaborate on that.

You see recently JS exploded. It’s no more this funny little language you can use to display a digital clock on your website. Now we use to run our backend, validate our forms, fetch our data asynchronously. Hell, you can even run it on your microcontrollers, if you want. I’d say JS grew rather powerful, with the latest ES6 version. Arrow functions are great and they encourage curried functions, we’ve got new data structures like Map (not immutable, though). Pretty much everyone is using ES6/7 features building their apps now.

Unfortunately for some time now, I had this feeling that this isn’t enough. I have grown tired a little bit of the famous JS fatigue, the one and only undefined or null cases. There’s proposition to handle it using Optionals. Also while maintaning large codebase I got frustrated with the lack of types. Yeah, folks from my company have been using TypeScript and I have been experimenting with FlowType, but it simply didn’t feel right. We have to add ESLint to check for common stupid mistakes and then add some kind of static type analysis just to make sure that we’re writing our code properly. Also if I wanted immutable data structures I had to add ImmutableJS. Soon I felt like I was drowning in layers of stuff I need to add to my project to make it reasonable to work with.

http://i.quoteaddicts.com/media/quotes/92/4570345-drowning-in-work-meme-funny.jpg

Not to mention that I use React and Redux as my frontend stack, so there are two another things on top of that. Soon I started to question my own sanity. Like… is this really how it is supposed to be? Is there a better way. Well, of course there is. You can always go back to writing good old plain VanillaJS. I saw people do it, but the thing is I really like React and the sensation of order that library brought to my development.

Thankfully I stumbled upon this talk:

https://www.youtube.com/watch?v=_0T5OSSzxms

If in your week full of work and activities, you have the time to watch only one video about programming that’s the one. I was gathering info about the ReasonML for some time now. The community is small but very focused on delivering a better experience for developers. Let’s look on the components building the ReasonML technology:

  • Language — OCaml has been chosen as the language backing Reason. It’s battle-tested, functional with immutable data structures and very solid and sound type system. Of course there are few problems with learning it if you’re coming from JS background. It’s different (duh..). The syntax can be overwhelming in the beginning and to be honest there’s not so many materials (courses, tutorials) to help you master it. One book I could find was published in 2013. In our industry it means it’s prehistoric.
  • BuckleScript — in the end our browsers don’t run the OCaml itself. We still need to compile to JS. Is compilation of our code for browser senseless and unnatural? Well, for some time now we have been using Babel to transpile our code from ES6/7 to ES5, why not go one step further? Elm does that already. BuckleScript is opensourced, but it was introduced, by smart guys from Bloomberg. What does BuckleScript give us? Well, it gives us interop between OCaml and JS code, (very) fast compilation and possibility to write bindings to popular (npm) packages written in JS for OCaml use. It’s a little hard to catch it but will get there step by step.
  • How to solve problem with cumbersome syntax? How about making it a little bit more JSish? ReasonML gives you the ability to transfer easily into the world of all goods provided by OCaml, while giving you a syntax that won’t make your eyes pop out. Makes perfect sense for me.
  • “Yeah, but I still wanna use React”. Worry not, clever people at Facebook already took care of that and made React first citizen of ReasonML and introduced ReasonReact.

That’s pretty much a short description of the toolchain of Reason. My goal will be to recreate the Marvel Hero App I presented previously with React in ReasonML. Why? Well, I have the API in place that I can share and I already know how it should look and work.

Getting started

I am assuming some prior knowledge of JS and its nowadays ecosystem. I’ll be using Yarn instead of NPM. If you don’t have that installed you can do this by typing:

npm install -g yarn

in your terminal. Since I’d like to skip the configuration, I’ll be using reason-scripts to kick off our app. Let’s start by adding bs-platform to our tools:

npm install -g bs-platform

and then we can initialize our app with:

yarn create react-app marvel-reason -- --scripts-version reason-scripts

Reason scripts come with development server and hotloading built in, so we can start right of the bat. As stated in terminal output we can:

cd marvel-reason
yarn start

To run our app. There are few things that are entirely different with Reason. Let’s discuss those. For start there’s bsconfig.json file. This is the point of configuration for our Reason project. Here we can specify stuff like the folders that are containing the files that should be compiled ( sources ), dependencies similar to those in package.json ( bs-dependencies ), object representing the specific configuration of Reason ( reason ), flags passed to the bucklescript binary ( bsc-flags ) and the version of the formatter to use ( refmt ).

Then there’s .merlin which is autocompletion service file for OCaml and ReasonML. Since our files and definitions are spread across few places .merlin file groups them together to provide autocompletion feature in our IDE. You can read more about it here:

I’ll be using VSCode and I highly recommend you to install package that will provide Reason support in our IDE:

Let’s quickly go through the folders. Our main focus will be of course the src folder where we will write and store our Reason files. public and node_modules are no different than standard React project folders of the same name. What is the most interesting is the lib folder, which will consist the files compiled from Reason to JS by BuckleScript? What’s interesting is that if you checkout the files in lib folder, they’re pretty darn readable. They may not be as easy to read as ones written by a human, but for the code produced by the process of compilation, I must say I was rather impressed.

Let’s actually try and add first of our components to the mix. This will be the TopBar.re used to search through our set of Marvel Heroes. Be aware that the name of the file is important. In Reason files are modules meaning that we do not need any require or import statements that you know from CommonJS or ES6 modules. Since I am defining a file with React component called TopBar.re I will use it as children in another component with </TopBar /> jsx tag.

Let’s fill this file with code and explain it step by step:

First, we don’t need import React to use jsx and build our components which is fine by me. Then we declare and initialize our component with ReasonReact.statelessComponent function. The name that you provide for this components isn’t the name of the module and this isn’t the name of the jsx tag you’ll be using to render this component in other files. It’s the name of the component that will be visible in React Dev Tools, though. What do I mean by that?

Remember that file is mapped to module automatically and we can use it without using import, while Name provided to ReasonReact.statelessComponent is more for information/debugging purpose.

Ok, I’d like my TopBar to consist of link, title, input and button. Let’s add these to our markup:

There are two things we need to add to make it functional:

  • CSS
  • Link components from ReactRouter library

We could use standard CSS as they’re used in app.re . Simply create .css file and use something like:

[%bs.raw {|require('./app.css')|}];

to add them to our app and start adding proper classNames to your component. But the thing is I always felt that lack of strong types in CSS is also holding me back. We know that flex property align-items can only take very well defined values, why not utilize this to make sure we are passing the right thing? We can do this be using bs-css package that provides this exact functionality. Add bs-css:

yarn add bs-css

after that open your bsconfig.json file and update bs-dependencies:

"bs-dependencies": ["reason-react", "bs-jest", "bs-css"],

Ok, now we should be ready to start adding typed styles to our files. The syntax might seem a little cumbersome at the start, but I assure you it’s worth your while. Also the documentation of this package isn’t very thorough, so looking through the interface file, might be helpful from time to time:

Ok let’s check our styling syntax and then discuss it:

At the very top, we include our logo image as a module to use it in jsx markup. In line 6 we define our style object using the bs-css syntax. It’s built from pairs of keys (string) and values (css). Values are lists of rules same as normal CSS, but the great thing is that they’re typed. What do I mean by that? If I change the value of alignItems in line 14 to from Center to NopeNotAValidValue I’ll get an error:

It would be a little bit more readable if I could get the possible values in error message, but I can go to the interface file and see that admissible values are:

How cool is that? Also please be noted that the numeric values like pixels are now passed through as a result of calling a function that takes an int as an argument and returns type called cssunit.

How to use our styles? style object is something called a record in OCaml and to access any of its field that we have defined we use ## operator when we specify the className in jsx.

That’s it for part one. In the next part we’ll see how to write bindings for js libraries that we need.

Cheers!

--

--

Wojciech Bilicki

Mobile & FrontEnd Developer at OKE Software Poland. Marvel fan. Can't live without music and books.