# Setting up React with Rails-7 using esbuild.

Prerequisites for local setup: 
- rails 7 installed
- yarn installed 

Create a new rails app by the command:
```
rails new esbuildApp -j esbuild
```

Now let us look at the `Package.json` and `Procfile.dev`

#### Package.json
 `package.json` has our js dependencies and scripts
```json
  "dependencies": {
    "@hotwired/stimulus": "^3.1.0",
    "@hotwired/turbo-rails": "^7.1.3",
    "esbuild": "^0.15.7"
  },
  "scripts": {
    "build": "esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds --public-path=assets"
  }
```
The esbuild command here basically just imports the stuff from `app/javascript/* ` & runs a **bundle command**, a **source map command **and then it throws it all inside
of `app/assets/builds` with the public path of assets.

This is important because inside of `app/assets/builds` you have `application.js` and  `application.js.map` basically spits everything out here then the rails asset pipeline uses it.

#### Procfile.dev 
If you only start your application with a `bundle exec rails s` it's not going to run the `yarn build --watch` 
The `yarn build` command inside of our `package.json` is the command which delivers our javascript into the asset pipeline.
The `--watch` flag in the command watches for changes when you update your application code for hot reloading. 

We can run your `Procfile.dev` by the command:
`bin/dev` which uses the `foreman gem` to run both of the below processes in two pids.
Firstly it runs the yarn command to throw everything into the source map. Then it starts the rails server.

![Screenshot 2022-09-18 at 12.28.36.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1663491758436/W2_kRiG4l.png align="left")


![Screenshot 2022-09-18 at 12.29.17.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1663492167791/AUitenJV_.png align="left")

Now let us stop the server with control+c.


#### Let's set up a home page and add some javascript to it

To set up a home page using the rails generator run the command: 
```
rails g controller pages home
``` 

Now let's update the `routes.rb` file, to point the `localhost:3000/` request to `pages/home`
```rb
Rails.application.routes.draw do
  root 'pages#home'
end
```


To make javascript appear on the screen, let's add a `javascript controller`  using [stimulus generator](https://github.com/hotwired/stimulus-rails#usage-with-javascript-bundler) and run the command: 
```
rails g stimulus react
```
so this creates our `app/javascript_controllers/react_controller.js`

Now let's update the `react_controller.js` by adding a `console.log` to test the javascript changes reflect on our app's root page.
```js
import { Controller } from "@hotwired/stimulus";

// Connects to data-controller="react"
export default class extends Controller {
  connect() {
    console.log("React controller connected");
  }
}
```

Now update the home view to inject the react controller javascript code. Go to `app/views/pages/home.html.erb` and make the below changes:

```
<h1>Pages#home</h1>
<p>Find me in app/views/pages/home.html.erb</p>
<%= content_tag(:div, "", id:"app", data: {
    controller: "react"
}) %>
```
We are using a `content_tag`. In the content tag we have to tell it what type of content by providing the below info:
 - *type*: `:div`, 
 - *id*: `app` 
 - Which stimulus controller to use. In our case: `app/javascript/controllers/react_controller.js`. We don't need the `_controller` part so we just type `controller: "react"`

Restart the server and run the command: `bin/dev` you should now be able to see the log: `"React controller connected"`  in the browser console.


![Screenshot 2022-09-18 at 12.32.03.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1663492043793/U3-Zk4w9W.png align="left")


![Screenshot 2022-09-18 at 12.35.51.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1663492054921/JKUa1d5-R.png align="left")

Now let us stop the server with `control+c`.


#### Now to add some actual react components.

Firstly let's add `react & react-dom` packages with the command:

`yarn add react react-dom`

Now check the changes in `Package.json`
```json
  "dependencies": {
    "@hotwired/stimulus": "^3.1.0",
    "@hotwired/turbo-rails": "^7.1.3",
    "esbuild": "^0.15.7",
    "react": "^18.2.0", // this is new
    "react-dom": "^18.2.0" // this is new
  },
```

Create `App.jsx` inside `app/javascript/components/` folder by running the commands:
```bash
mkdir app/javascript/components/
touch app/javascript/components/App.jsx
```

Let us create a basic counter in the `App.jsx` with a button to increment the count state and a `<p>`tag displaying it:

```jsx
import React, { useState } from "react";

function App() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>You clicked {count} times!</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

export default App;
```

Now let us import the `App.jsx` into the `react_controller.js` and render it onto the `app` element using the `createRoot` from `react-dom/client`
<!-- // app/javascript/controllers/react_controller.js -->
```js

import { Controller } from "@hotwired/stimulus";
import React from "react";
import { createRoot } from "react-dom/client";
import App from "../components/App";

// Connects to data-controller="react"
export default class extends Controller {
  connect() {
    console.log("React controller connected");
    const app = document.getElementById("app");
    createRoot(app).render(<App />);
  }
}
```
In the console we are getting an error:

![Screenshot 2022-09-18 at 12.38.50.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1663492342234/3TqzRjncx.png align="left")

Now to fix the esbuild loader error by updating the `package.json` build script to: 
```json
  "scripts": {
    "build": "esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds --public-path=assets --loader:.js=jsx"
  }
```
