# Uploading a Laravel and React Project to Heroku

I've been gone for a while, but I'm back!

During my 'break' I gave Inertia with Laravel another chance and ended up liking it. I'm still not a fan of how Laravel devs still have to go to multiple places for docs, but it's what we have so far until the Laravel team or someone brave puts everything in one place. When I was getting reacquainted, I needed to upload my project to production. I'm a frequent user of Heroku because of their free plan, but getting PHP and Node to work together took a bit of work. Here's how I did it.


**Pre-requisites:**
- Make a Heroku account. [It's totally free](https://signup.heroku.com/php).
- Download and [install the Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli).
    * Carefully follow the instructions and ensure that you have your login credentials set. You don't have to create a repository yet.
    * You must have git installed. If you don't, [do it](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git).
- Make a new Laravel project in your projects folder by running `$ laravel new laravel-inertia-project` in your terminal.

**First Steps:** In this tutorial, we'll be using Laravel Breeze, which is the simplest way to implement a Vue or React frontend in our Laravel project.
- Install Laravel Breeze by running `$ composer require laravel/breeze --dev`. Then we'll install Breeze and its Inertia stack by running these two commands:

```
$ php artisan breeze:install --inertia
$ npm install
```
- Once that's done, we'll need to set up React. Laravel Breeze and Inertia will automatically install Vue, so we'll need to do a bit of work here. 
    * Run:
```
$ npm install react react-dom
$ npm install @inertiajs/inertia @inertiajs/inertia-react
```

    * Go to ***resources/js/app.js*** and make some changes so that we can build our own frontend instead of using Vue.

```
import {InertiaApp} from ‘@inertiajs/inertia-react’
import React from ‘react’
import {render} from ‘react-dom’

const app = document.getElementById(‘app’)

render (
    <InertiaApp
        initialPage={JSON.parse(app.dataset.page)}
        resolveComponent={name => import(`./Pages/${name}`).then(
  module => module.default
        )}
    />,
    app
)
```
- To ensure that Babel can understand the little JSX code that we’ll be writing, we’ll need to install a Babel preset by running `$ npm install --save-dev @babel/preset-react`. We can then use this preset by creating a ***.babelrc*** file in the root with this code:

```bash
{
    "presets": ["@babel/preset-react"]
}
```

- We'll need to go to ***resources/js*** and delete the ***Pages*** and ***Components*** folders you see there, and just replace it with a ***Pages*** folder with a file called ***HelloWorld.js*** in it.
- In ***HelloWorld.js***, we'll make a simple Hello World app:

```
import React from 'react'

const HelloWorld = () => (
   <p>Hello world!</p>
)

export default HelloWorld
```

- Next, go to ***routes/web.php***, and delete the routes that you see there. Then, we'll use Inertia to render our Hello World page without sending any data.

```
Route::get('/', function(){
    return Inertia::render('HelloWorld', []);
}
```

- Finally, go to ***webpack.mix.js*** and ensure that you see `mix.js('resources/js/app.js', 'public/js'`. If you see `.vue()` attached to `mix`, delete it or you'll get errors. Now compile your assets by running `$ npm run dev`.


**The Work Begins:**
- Run `$ git init` to set git up in your project.  Then add your files to git by running `$ git add .`.
- Create a new Heroku app by running `$ heroku create`. 
- Before we commit and push, we need to create a ***Procfile***. This file will tell Heroku what commands to run when the application starts up. For PHP, the file will only have one line: `web: vendor/bin/heroku-php-apache2 public/`. Create ***Procfile***  in your root folder and copy-paste the line in the file, or run `$ echo "web: vendor/bin/heroku-php-apache2 public/" > Procfile` in your terminal.
**NOTE:** It's best to create the file first before writing to it. You'll see less errors this way.


**The Work Continues:**
- Before we can push our work up to Heroku, we'll need to create two buildpacks. Buildpacks are scripts that make the right environment to run a programming language. Because we have React and Inertia, we'll need a buildpack for Node as well as PHP.
    * For PHP, run `$ heroku buildpacks:set heroku/php`.
    * For Node, run `$ heroku buildpacks:add --index 1 heroku/nodejs`.
    * **NOTE:** The `--index 1` basically states that this buildpack will run first. The buildpack for the primary language [must always be run last](https://devcenter.heroku.com/articles/using-multiple-buildpacks-for-an-app).  
* We'll need to ensure Heroku does not ignore our `devDependencies` in ***package.json***, which it [does by default](https://devcenter.heroku.com/changelog-items/1376). Run `$ heroku config:set NPM_CONFIG_PRODUCTION=false`. 


**The Work Ends:**
- Now we can commit and push our project up to Heroku:

```
$ git commit -m "First commit to Heroku"
$ git push heroku main
```
- **NOTE:** If for some reason the `heroku` remote wasn't added, run `$ heroku git:remote -a {APP_NAME}`. Go to your Heroku dashboard to see the name if you lost it.

- For Laravel to work, we'll need an `APP_KEY`. One is already set locally, but we need one for Heroku. Run `$ heroku config:set APP_KEY={key}`.
- Run `$ heroku open` to open and run the app. It should open to `https://{APP_NAME}.netlify.app` and you should see "Hello World" on your screen.


**Conclusion:**
- If you need to debug, [Heroku provides logs](https://devcenter.heroku.com/articles/logging) for your app. Run `$ heroku config:set LOG_CHANNEL=errorlog` so your stack trace errors are logged there.
- I love Heroku because it's one of the best ways to host PHP apps for free. 
- If you're on the free plan of Heroku, your app will 'sleep' at different intervals. If you don't like this behavior, especially as you're building out your app, you can just subscribe to their 'Hobby' plan which costs a dollar less than a Disney Plus subscription.
