Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/eanplatter/introduce-reason-example

An example app made with Create React App which introduces a Reason component
https://github.com/eanplatter/introduce-reason-example

bucklescript ocaml react reason reason-react reasonml

Last synced: about 16 hours ago
JSON representation

An example app made with Create React App which introduces a Reason component

Awesome Lists containing this project

README

        

# Introducing Reason to an existing React Project
One of the hardest things about trying out new tools is that they don't always play well with your
existing code, or if they do it takes a lot of time and effort to make it happen.

[Reason](https://github.com/facebook/reason) happens to be extremely easy to integrate into an existing React app with the help of [reason-react](https://github.com/reasonml/reason-react)

In this README I am going to attempt to convey how I added Reason to an existing app created by [create-react-app](https://github.com/facebookincubator/create-react-app).
The code in this project is an "existing codebase" with Reason implemented.

## Step 1 - BuckleScript Config
[BuckleScript](https://github.com/bloomberg/bucklescript) is "a backend for the OCaml compiler which emits JavaScript". It
is what turns our Reason code into JavaScript we can import into our React code.

We will run BuckleScript in our terminal, it will read our code and turn it into JavaScript. In order to point it in the
right direction we will need to create a `bsconfig.json` file. This is similar to `webpack.config.js` or `.babelrc` files.
It merely configures BuckleScript.

In the root of your project create a file named `bsconfig.json`.

I borrowed most of this `bsconfig.json` file from [Cheng Lou](https://github.com/chenglou)'s [reason-react-example](https://github.com/chenglou/reason-react-example)

[bsconfig.json](bsconfig.json)
```json
{
"name" : "introduce-reason",
"reason" : { "react-jsx" : true },
"bs-dependencies": ["reason-react", "reason-js"],
"sources": [
{
"dir": "src",
}
],
}
```
## Step 2 - Add Dependencies
We need 3 new dependencies in order to make this work: [reason-react](https://www.npmjs.com/package/reason-react), [reason-js](https://www.npmjs.com/package/reason-js), and [bs-platform](https://www.npmjs.com/package/bs-platform).

To install these, run the following in your terminal:
```shell
npm i -S reason-js reason-react && npm i -D bs-platform
```

## Step 3 - Add a BuckleScript NPM Script
We are going to need a way to run BuckleScript over our codebase. Since we've installed the `bs-platform` dependency and have created our `bsconfig.json` file we are set to start running BuckleScript! Add a script to our `package.json` file which runs BuckleScript, it should look something like this:
```json
"scripts": {
"buckle:up": "bsb -make-world -w",
"buckle:clean": "bsb -clean-world",
"start": "react-scripts start",
}
```
The names are arbitrary, I decided to call my scripts buckle:up and buckle:clean. So now in my terminal I can run it:
```shell
npm run buckle:up
```
Once we do this, if everything worked properly we should see a new directory in the root of our app named `lib/`; this is where BuckleScript will put our transpiled Reason components.

If we look in the `lib/` directory right now we will see that there is a `bs/` directoy. This isn't really important for us to look at right now, once we have a Reason component we will also see a `js/` directory. This `js/` directory is where BuckleScript is going to put our component! Let's go ahead and get started on that.

## Step 4 - Writing a Reason Component
In the `/src` directory of our project let's create a new file called `Intro.re`. This is going to be a React Reason component which is going to replace the into paragraph on the default create-react-app main page.

[Intro.re](src/Intro.re)
```OCaml
module Intro = {
include ReactRe.Component.JsProps;
type props = { message: string };
let name = "Intro";
let render { props } =>

(ReactRe.stringToElement props.message)

;
type jsProps = Js.t {. message : string };
let jsPropsToReasonProps =
Some (
fun jsProps => { message: jsProps##message }
);
};

include ReactRe.CreateComponent Intro;

let createElement ::message => wrapProps { message };

```
I don't want to dive too deep into the Reason syntax here, but essentially this is a component which takes in a `message` props and puts it into a `

` tag with the `className` "App-intro".

## Step 5 - Tieing it All Together
In order to do this, I had 2 terminal windows open, one running Webpack, the other running BuckleScript. Make sure both of these are running:

### Running Webpack
```shell
npm start
```

### Running BuckleScript
```shell
npm run buckle:up
```
Once these are running we should be able to see that our component has been transpiled by BuckleScript to [lib/js/src/intro.js](lib/js/src/intro.js) and it should look something like this:
```js
// Generated by BUCKLESCRIPT VERSION 1.6.0+dev, PLEASE EDIT WITH CARE
'use strict';

var Curry = require("bs-platform/lib/js/curry");
var React = require("react");
var ReactRe = require("reason-react/lib/js/src/reactRe");

var include = ReactRe.Component[/* JsProps */9];

var componentDidMount = include[0];

var componentWillUpdate = include[1];

var componentDidUpdate = include[2];

var componentWillReceiveProps = include[3];

var componentWillUnmount = include[4];

var getInstanceVars = include[5];

var getInitialState = include[6];

var name = "Intro";

function render(param) {
return React.createElement("p", {
className: "App-intro"
}, param[/* props */1][/* message */0]);
}

var jsPropsToReasonProps = /* Some */[function (jsProps) {
return /* record */[/* message */jsProps.message];
}];

var Intro = /* module */[
/* componentDidMount */componentDidMount,
/* componentWillUpdate */componentWillUpdate,
/* componentDidUpdate */componentDidUpdate,
/* componentWillReceiveProps */componentWillReceiveProps,
/* componentWillUnmount */componentWillUnmount,
/* getInstanceVars */getInstanceVars,
/* getInitialState */getInitialState,
/* name */name,
/* render */render,
/* jsPropsToReasonProps */jsPropsToReasonProps
];

var include$1 = ReactRe.CreateComponent([
name,
getInstanceVars,
getInitialState,
componentDidMount,
componentWillReceiveProps,
componentWillUpdate,
componentDidUpdate,
componentWillUnmount,
jsPropsToReasonProps,
render
]);

var wrapProps = include$1[1];

var createElement = Curry.__1(wrapProps);

var comp = include$1[0];

exports.Intro = Intro;
exports.comp = comp;
exports.wrapProps = wrapProps;
exports.createElement = createElement;
/* include Not a pure module */

```

If that is all working then we should be able to now import our Reason component into our existing React app. I am going to import it into [App.js](src/App.js) as `Intro`:
[App.js](src/App.js)
```js
import React, { Component } from 'react';
import logo from './logo.svg';
import Intro from '../lib/js/src/intro'
import './App.css';
```
...and replace the paragraph with the `className` "App-intro" with:
```js

```

## All done!
That should be it! If you've made it this far then congratulations you've successfully introduced Reason into a React codebase! If you experienced any issues with this walkthrough please [open an issue](https://github.com/eanplatter/introduce-reason-example/issues/new) or if there are changes you think we should make feel free to [open a PR](https://github.com/eanplatter/introduce-reason-example/compare).

A big thanks to [Cheng Lou](https://github.com/chenglou) and his [reason-react-example](https://github.com/chenglou/reason-react-example) which served as my primary source of information while doing this. Be sure to check out his example project for a more in depth look at using reason-react.