Skip to content

Commit

Permalink
Updates to allow for deployment to Heroku
Browse files Browse the repository at this point in the history
* Separate production and deploy boot processes
* Add `client/build` to source control
* Unify ports around environment variable `PORT`
  • Loading branch information
acco committed Oct 25, 2016
1 parent 9a5dba9 commit 0008038
Show file tree
Hide file tree
Showing 20 changed files with 678 additions and 13 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
cra-server-ex.graffle
node_modules
npm-debug.log
client/build
3 changes: 1 addition & 2 deletions Procfile
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
web: cd client && npm start
api: npm run server
web: npm run server
2 changes: 2 additions & 0 deletions Procfile.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
web: cd client && npm start
api: PORT=3001 npm run server
82 changes: 78 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ We have a [detailed blog post](https://www.fullstackreact.com/articles/using-cre

Check out the [Rails version](https://github.com/fullstackreact/food-lookup-demo-rails) if that's your preferred API server platform.

## Running
## Running locally

```
git clone [email protected]:fullstackreact/food-lookup-demo.git
Expand All @@ -23,9 +23,11 @@ cd client
npm i
cd ..
npm start
npm run dev
```

**Important**: **`npm start`** is intended for production only. Use `npm run dev`.

## Overview

`create-react-app` configures a Webpack development server to run on `localhost:3000`. This development server will bundle all static assets located under `client/src/`. All requests to `localhost:3000` will serve `client/index.html` which will include Webpack's `bundle.js`.
Expand All @@ -41,7 +43,7 @@ return fetch(`/api/food?q=${query}`, {
})
```

This request is made to `localhost:3000`, the Webpack dev server. Because the route has the special prefix `/api/`, the Webpack server knows that this request is actually intended for our API server. We specify in `package.json` that we would like Webpack to proxy API requests to `localhost:3001`:
This request is made to `localhost:3000`, the Webpack dev server. Webpack will infer that this request is actually intended for our API server. We specify in `package.json` that we would like Webpack to proxy API requests to `localhost:3001`:

```js
// Inside client/package.json
Expand All @@ -57,11 +59,83 @@ Therefore, the user's browser makes a request to Webpack at `localhost:3000` whi
This setup provides two advantages:

1. If the user's browser tried to request `localhost:3001` directly, we'd run into issues with CORS.
2. In many setups, this means that references to the API URL in development matches that in production. You don't have to do something like this:
2. The API URL in development matches that in production. You don't have to do something like this:

```js
// Example API base URL determination in Client.js
const apiBaseUrl = process.env.NODE_ENV === 'development' ? 'localhost:3001' : '/'
```

This setup uses [node-foreman](https://github.com/strongloop/node-foreman) for process management. Executing `npm start` instructs Foreman to boot both the Webpack dev server and the API server.

## Deploying

### Background

The app is ready to be deployed to Heroku. In `package.json`, we specify separate boot commands for development and production:

```
"start": "nf start -p $PORT",
"dev": "nf start -p 3000 --procfile Procfile.dev",
```

In development, we use `Procfile.dev` which boots both the API server and the Webpack server:

```
web: cd client && npm start
api: PORT=3001 npm run server
```

In production, Heroku will use `Procfile` which boots just the server:

```
web: npm run server
```

Inside `server.js`, we tell Node/Express we'd like it to serve static assets in production:

```
if (process.env.NODE_ENV === 'production') {
app.use(express.static('client/build'));
}
```

### Steps

We assume basic knowledge of Heroku.

**0. Setup your Heroku account and Heroku CLI**

For installing the CLI tool, see [this article](https://devcenter.heroku.com/articles/heroku-command-line).

**1. Build the React app**

Running `npm run build` creates the static bundle which we can then use any HTTP server to serve:

```
cd client/
npm run build
```

**2. Commit the `client/build` folder to source control**

From the root of the project:

```
git add client/build
git commit -m 'Adding `build` to source control'
```

**3. Create the Heroku app**

```
heroku apps:create food-lookup-demo
```

**4. Push to Heroku**

```
git push heroku master
```

Heroku will give you a link at which to view your live app.
3 changes: 0 additions & 3 deletions client/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ node_modules
# testing
coverage

# production
build

# misc
.DS_Store
.env
Expand Down
12 changes: 12 additions & 0 deletions client/build/asset-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"main.css": "static/css/main.03b6e96f.css",
"main.css.map": "static/css/main.03b6e96f.css.map",
"main.js": "static/js/main.e5a5c899.js",
"main.js.map": "static/js/main.e5a5c899.js.map",
"static/media/flags.png": "static/media/flags.9c74e172.png",
"static/media/icons.eot": "static/media/icons.f7c2b4b7.eot",
"static/media/icons.svg": "static/media/icons.29800836.svg",
"static/media/icons.ttf": "static/media/icons.706450d7.ttf",
"static/media/icons.woff": "static/media/icons.d9ee23d5.woff",
"static/media/icons.woff2": "static/media/icons.97493d3f.woff2"
}
Binary file added client/build/favicon.ico
Binary file not shown.
1 change: 1 addition & 0 deletions client/build/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="shortcut icon" href="/favicon.ico"><title>Food Lookup Demo</title><link href="/static/css/main.03b6e96f.css" rel="stylesheet"></head><body><div id="root"></div><script type="text/javascript" src="/static/js/main.e5a5c899.js"></script></body></html>
2 changes: 2 additions & 0 deletions client/build/static/css/main.03b6e96f.css

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions client/build/static/css/main.03b6e96f.css.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions client/build/static/js/main.e5a5c899.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions client/build/static/js/main.e5a5c899.js.map

Large diffs are not rendered by default.

Binary file added client/build/static/media/flags.9c74e172.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

2 comments on commit 0008038

@fresh5447
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Am I going to need a different process if I have ejected the app?
I am getting 'missing script: build'

@acco
Copy link
Member Author

@acco acco commented on 0008038 Dec 3, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @fresh5447,

Indeed, an ejected app might behave differently. It looks like by default ejected apps should have that script though?

"scripts": {
    "start": "node scripts/start.js",
    "build": "node scripts/build.js",
    "test": "jest --watch --env=jsdom"
  },

Please sign in to comment.