# React app

#### [Fork from](https://github.com/solana-labs/create-react-app-buildpack) <a href="#user-content-heroku-buildpack-for-create-react-app" id="user-content-heroku-buildpack-for-create-react-app"></a>

### [Requires](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-requires" id="user-content-requires"></a>

* [Heroku](https://www.heroku.com/home)
  * [command-line tools (CLI)](https://toolbelt.heroku.com/)
  * [a free account](https://signup.heroku.com/)
* [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
* [Node.js](https://nodejs.org/)

### [Quick Start](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-quick-start" id="user-content-quick-start"></a>

Ensure [requirements](https://solnm.gitbook.io/docs/technology/broken-reference) are met, then execute the following in a terminal.

✏️ *Replace `$APP_NAME` with the name for your unique app.*

```
npx create-react-app@3.x $APP_NAME
cd $APP_NAME
heroku create $APP_NAME --buildpack mars/create-react-app
git push heroku master
heroku open
```

Once deployed, [continue development](https://solnm.gitbook.io/docs/technology/broken-reference) 🌱

For explanation about these steps, continue reading the [next section](https://solnm.gitbook.io/docs/technology/broken-reference).

### [Usage](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-usage" id="user-content-usage"></a>

#### [Generate a React app](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-generate-a-react-app" id="user-content-generate-a-react-app"></a>

✏️ *Replace `$APP_NAME` with the name for your unique app.*

```
npx create-react-app@3.x $APP_NAME
cd $APP_NAME
```

* as of create-react-app v3, it automatically performs `git init` and an initial commit
* [npx](https://medium.com/@maybekatz/introducing-npx-an-npm-package-runner-55f7d4bd282b) comes with npm 5.2+ and higher, see [instructions for older npm versions](https://gist.github.com/gaearon/4064d3c23a77c74a3614c498a8bb1c5f)
* if [yarn](https://yarnpkg.com/) is installed locally, the new app will use it instead of [npm](https://www.npmjs.com/)

#### [Create the Heroku app](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-create-the-heroku-app" id="user-content-create-the-heroku-app"></a>

✏️ *Replace `$APP_NAME` with the name for your unique app.*

```
heroku create $APP_NAME --buildpack mars/create-react-app
```

This command:

* sets the [app name](https://devcenter.heroku.com/articles/creating-apps#creating-a-named-app) & its default URL `https://$APP_NAME.herokuapp.com`
* sets the app to use this [buildpack](https://devcenter.heroku.com/articles/buildpacks)
* configures the [`heroku` git remote](https://devcenter.heroku.com/articles/git#creating-a-heroku-remote) in the local repo, so `git push heroku master` will push to this new Heroku app.

#### [Deploy ♻️](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-deploy" id="user-content-deploy"></a>

…or if you are ever working on a branch other than `master`:

✏️ *Replace `$BRANCH_NAME` with the name for the current branch.*

```
git push heroku $BRANCH_NAME:master
```

#### [Visit the app's public URL in your browser](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-visit-the-apps-public-url-in-your-browser" id="user-content-visit-the-apps-public-url-in-your-browser"></a>

#### [Visit the Heroku Dashboard for the app](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-visit-the-heroku-dashboard-for-the-app" id="user-content-visit-the-heroku-dashboard-for-the-app"></a>

Find the app on [your dashboard](https://dashboard.heroku.com/).

#### [Continue Development](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-continue-development" id="user-content-continue-development"></a>

Work with your app locally using `npm start`. See: [create-react-app docs](https://github.com/facebookincubator/create-react-app#getting-started)

Then, `git commit` your changes & `git push heroku master` ♻️

#### [Push to Github](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-push-to-github" id="user-content-push-to-github"></a>

Eventually, to share, collaborate, or simply back-up your code, [create an empty repo at Github](https://github.com/new), and then follow the instructions shown on the repo to **push an existing repository from the command line**.

#### [Testing](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-testing" id="user-content-testing"></a>

Use [create-react-app's built-in Jest testing](https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md#user-content-running-tests) or whatever testing library you prefer.

[Heroku CI](https://devcenter.heroku.com/articles/heroku-ci) is supported with minimal configuration. The CI integration is compatible with npm & yarn (see [`bin/test`](https://3763343587-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLqHVp1UopzsAVRGjwnpr%2Fuploads%2FS40Wn4xdYakiV3WnHNI7%2Ftest?alt=media)).

[**Minimal `app.json`**](https://solnm.gitbook.io/docs/technology/broken-reference)

Heroku CI uses [`app.json`](https://devcenter.heroku.com/articles/app-json-schema) to provision test apps. To support Heroku CI, commit this minimal example `app.json`:

```
{
  "buildpacks": [
    {
      "url": "mars/create-react-app"
    }
  ]
}
```

### [Customization](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-customization" id="user-content-customization"></a>

#### [Procfile](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-procfile" id="user-content-procfile"></a>

Heroku apps may declare what processes are launched for a successful deployment by way of the [`Procfile`](https://devcenter.heroku.com/articles/procfile). This buildpack's default process comes from [`heroku/static` buildpack](https://github.com/heroku/heroku-buildpack-static). (See: 🏙 [Architecture](https://solnm.gitbook.io/docs/technology/broken-reference)). The implicit `Procfile` to start the static web server is:

To customize an app's processes, commit a `Procfile` and deploy. Include `web: bin/boot` to launch the default web process, or you may replace the default web process. Additional [process types](https://devcenter.heroku.com/articles/procfile#declaring-process-types) may be added to run any number of dynos with whatever arbitrary commands you want, and scale each independently.

🚦 *If replacing the default web process, please check this buildpack's* [*Purpose*](https://solnm.gitbook.io/docs/technology/broken-reference) *to avoid misusing this buildpack (such as running a Node server) which can lead to confusing deployment issues.*

#### [Web server](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-web-server" id="user-content-web-server"></a>

The web server may be [configured via the static buildpack](https://github.com/heroku/heroku-buildpack-static#configuration).

The config file `static.json` should be committed at the root of the repo. It will not be recognized, if this file in a sub-directory

The default `static.json`, if it does not exist in the repo, is:

```
{
  "root": "build/",
  "routes": {
    "/**": "index.html"
  }
}
```

#### [Changing the root](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-changing-the-root" id="user-content-changing-the-root"></a>

If a different web server `"root"` is specified, such as with a highly customized, ejected create-react-app project, then the new bundle location may need to be [set to enable runtime environment variables](https://solnm.gitbook.io/docs/technology/broken-reference).

#### [Routing](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-routing" id="user-content-routing"></a>

🚥 ***Client-side routing is supported by default.** Any server request that would result in 404 Not Found returns the React app.*

👓 See [custom routing w/ the static buildpack](https://github.com/heroku/heroku-buildpack-static/blob/master/README.md#user-content-custom-routes).

#### [HTTPS-only](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-https-only" id="user-content-https-only"></a>

Enforce secure connections by automatically redirecting insecure requests to **https\://**, in `static.json`:

```
{
  "root": "build/",
  "routes": {
    "/**": "index.html"
  },
  "https_only": true
}
```

[**Strict transport security (HSTS)**](https://solnm.gitbook.io/docs/technology/broken-reference)

Prevent downgrade attacks with [HTTP strict transport security](https://developer.mozilla.org/en-US/docs/Web/Security/HTTP_strict_transport_security). Add HSTS `"headers"` to `static.json`.

⚠️ **Do not set HSTS headers if the app's hostname will not permantly support HTTPS/SSL/TLS.** Once HSTS is set, switching back to plain HTTP will cause security errors in browsers that received the headers, until the max-age is reached. Heroku's built-in `herokuapp.com` hostnames are safe to use with HSTS.

```
{
  "root": "build/",
  "routes": {
    "/**": "index.html"
  },
  "https_only": true,
  "headers": {
    "/**": {
      "Strict-Transport-Security": "max-age=31557600"
    }
  }
}
```

* `max-age` is the number of seconds to enforce HTTPS since the last connection; the example is one-year

#### [Proxy](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-proxy" id="user-content-proxy"></a>

Proxy XHR requests from the React UI in the browser to API backends. Use to prevent same-origin errors when [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS) is not supported on the backend.

[**Proxy URL prefix**](https://solnm.gitbook.io/docs/technology/broken-reference)

To make calls through the proxy, use relative URL's in the React app which will be proxied to the configured target URL. For the example URL prefix of `/api/`, here's how the proxy would rewrite the requests:

```
/api/search-items
  → https://backend.example.com/search-items
  
/api/users/me
  → https://backend.example.com/users/me
```

You may choose any prefix and may have multiple proxies with different prefixes.

[**Proxy for deployment**](https://solnm.gitbook.io/docs/technology/broken-reference)

The [`heroku/static` buildpack](https://github.com/heroku/heroku-buildpack-static) (see: 🏙 [Architecture](https://solnm.gitbook.io/docs/technology/broken-reference)) provides [Proxy Backends configuration](https://github.com/heroku/heroku-buildpack-static/blob/master/README.md#proxy-backends) to utilize Nginx for high-performance proxies in production.

Add `"proxies"` to `static.json`:

```
{
  "root": "build/",
  "routes": {
    "/**": "index.html"
  },
  "proxies": {
    "/api/": {
      "origin": "${API_URL}"
    }
  }
}
```

Then, point the React UI app to a specific backend API:

```
heroku config:set API_URL="https://backend.example.com"
```

[**Proxy for local development**](https://solnm.gitbook.io/docs/technology/broken-reference)

create-react-app itself provides a built-in [proxy for development](https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md#user-content-proxying-api-requests-in-development). This may be configured to match the behavior of [proxy for deployment](https://solnm.gitbook.io/docs/technology/broken-reference).

Add `"proxy"` to `package.json`:

```
{
  "proxy": {
    "/api": {
      "target": "http://localhost:8000",
      "pathRewrite": {
        "^/api": "/"
      }
    }
  }
}
```

Replace `http://localhost:8000` with the URL to your local or remote backend service.

#### [Environment variables](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-environment-variables" id="user-content-environment-variables"></a>

[`REACT_APP_*` environment variables](https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables) are fully supported with this buildpack.

🚫🤐 ***Not for secrets.** These values may be accessed by anyone who can see the React app.*

#### [Set vars on Heroku](https://devcenter.heroku.com/articles/config-vars)

```
heroku config:set REACT_APP_HELLO='I love sushi!'
```

#### [Set vars for local dev](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-set-vars-for-local-dev" id="user-content-set-vars-for-local-dev"></a>

*Requires at least create-react-app 0.7. Earlier versions only support Compile-time.*

Create a `.env` file that sets a variable per line:

```
REACT_APP_API_URL=http://api.example.com
REACT_APP_CLIENT_ID=XyzxYzxyZ
```

#### [Compile-time vs Runtime](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-compile-time-vs-runtime" id="user-content-compile-time-vs-runtime"></a>

Two versions of variables are supported. In addition to compile-time variables applied during [build](https://github.com/facebookincubator/create-react-app#npm-run-build) the app supports variables set at runtime, applied as each web dyno starts-up.

| Requirement                                                                                                                   | [Compile-time](https://solnm.gitbook.io/docs/technology/broken-reference) | [Runtime](https://solnm.gitbook.io/docs/technology/broken-reference) |
| ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| never changes for a build                                                                                                     | ✓                                                                         |                                                                      |
| support for [continuous delivery](https://www.heroku.com/continuous-delivery)                                                 |                                                                           | ✓                                                                    |
| updates immediately when setting new [config vars](https://devcenter.heroku.com/articles/config-vars)                         |                                                                           | ✓                                                                    |
| different values for staging & production (in a [pipeline](https://devcenter.heroku.com/articles/pipelines))                  |                                                                           | ✓                                                                    |
| ex: `REACT_APP_BUILD_VERSION` (static fact about the bundle)                                                                  | ✓                                                                         |                                                                      |
| ex: `REACT_APP_DEBUG_ASSERTIONS` ([prune code from bundle](https://webpack.github.io/docs/list-of-plugins.html#defineplugin)) | ✓                                                                         |                                                                      |
| ex: `REACT_APP_API_URL` (transient, external reference)                                                                       |                                                                           | ✓                                                                    |
| ex: `REACT_APP_FILEPICKER_API_KEY` ([Add-on config vars](https://solnm.gitbook.io/docs/technology/broken-reference))          |                                                                           | ✓                                                                    |

#### [Compile-time configuration](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-compile-time-configuration" id="user-content-compile-time-configuration"></a>

Supports all config vars, including [`REACT_APP_`](https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#adding-custom-environment-variables), `NODE_`, `NPM_`, & `HEROKU_` prefixed variables.

☝️🤐 ***Use secrets carefully.** If these values are embedded in the JavaScript bundle, like with `REACT_APP_` vars, then they may be accessed by anyone who can see the React app.*

Use Node's [`process.env` object](https://nodejs.org/dist/latest-v10.x/docs/api/process.html#process_process_env).

```
import React, { Component } from 'react';

class App extends Component {
  render() {
    return (
      <code>Runtime env var example: { process.env.REACT_APP_HELLO }</code>
    );
  }
}
```

♻️ The app must be re-deployed for compiled changes to take effect, because during the build, these references will be replaced with their quoted string value.

```
heroku config:set REACT_APP_HELLO='I love sushi!'

git commit --allow-empty -m "Set REACT_APP_HELLO config var"
git push heroku master
```

Only `REACT_APP_` vars are replaced in create-react-app's build. To make any other variables visible to React, they must be prefixed for the build command in `package.json`, like this:

```
REACT_APP_HEROKU_SLUG_COMMIT=$HEROKU_SLUG_COMMIT react-scripts build
```

#### [Runtime configuration](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-runtime-configuration" id="user-content-runtime-configuration"></a>

Supports only [`REACT_APP_`](https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#adding-custom-environment-variables) prefixed variables.

🚫🤐 ***Not for secrets.** These values may be accessed by anyone who can see the React app.*

Install the [runtime env npm package](https://www.npmjs.com/package/@mars/heroku-js-runtime-env):

```
npm install @mars/heroku-js-runtime-env --save
```

Then, require/import it to use the vars within components:

```
import React, { Component } from 'react';
import runtimeEnv from '@mars/heroku-js-runtime-env';

class App extends Component {
  render() {
    // Load the env object.
    const env = runtimeEnv();

    // …then use values just like `process.env`
    return (
      <code>Runtime env var example: { env.REACT_APP_HELLO }</code>
    );
  }
}
```

⚠️ *Avoid setting backslash escape sequences, such as , into Runtime config vars. Use literal UTF-8 values only; they will be automatically escaped.*

[**Custom bundle location**](https://solnm.gitbook.io/docs/technology/broken-reference)

If the javascript bundle location is customized, such as with an ejected created-react-app project, then the runtime may not be able to locate the bundle to inject runtime variables.

To solve this so the runtime can locate the bundle, set the custom bundle path:

```
heroku config:set JS_RUNTIME_TARGET_BUNDLE=/app/my/custom/path/js/*.js
```

✳️ *Note this path is a `*` glob, selecting multiple files, because as of create-react-app version 2 the* [*bundle is split*](https://reactjs.org/blog/2018/10/01/create-react-app-v2.html)*.*

To unset this config and use the default path for **create-react-app**'s bundle, `/app/build/static/js/*.js`:

```
heroku config:unset JS_RUNTIME_TARGET_BUNDLE
```

#### [Add-on config vars](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-add-on-config-vars" id="user-content-add-on-config-vars"></a>

🚫🤐 ***Be careful not to export secrets.** These values may be accessed by anyone who can see the React app.*

Use a custom [`.profile.d` script](https://devcenter.heroku.com/articles/buildpack-api#profile-d-scripts) to make variables set by other components available to the React app by prefixing them with `REACT_APP_`.

1. create `.profile.d/000-react-app-exports.sh`
2. make it executable `chmod +x .profile.d/000-react-app-exports.sh`
3. add an `export` line for each variable:

   ```
   export REACT_APP_ADDON_CONFIG=${ADDON_CONFIG:-}
   ```
4. set-up & use [Runtime configuration](https://solnm.gitbook.io/docs/technology/broken-reference) to access the variables

For example, to use the API key for the [Filestack](https://elements.heroku.com/addons/filepicker) JS image uploader:

```
export REACT_APP_FILEPICKER_API_KEY=${FILEPICKER_API_KEY:-}
```

### [npm Private Packages](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-npm-private-packages" id="user-content-npm-private-packages"></a>

Private modules are supported during build.

1. Setup your app with a `.npmrc` file following [npm's guide for CI/deployment](https://docs.npmjs.com/private-modules/ci-server-config).
2. Set your secret in the `NPM_TOKEN` config var:

   ```
   heroku config:set NPM_TOKEN=xxxxx
   ```

### [Troubleshooting](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-troubleshooting" id="user-content-troubleshooting"></a>

1. Confirm that your app is using this buildpack:

   If it's not using `create-react-app-buildpack`, then set it:

   ```
   heroku buildpacks:set mars/create-react-app
   ```

   …and deploy with the new buildpack:

   ```
   git commit --allow-empty -m 'Switch to create-react-app-buildpack'
   git push heroku master
   ```

   If the error still occurs, then at least we know it's really using this buildpack! Proceed with troubleshooting.
2. Check this README to see if it already mentions the issue.
3. Search our [issues](https://github.com/mars/create-react-app-buildpack/issues?utf8=%E2%9C%93\&q=is%3Aissue%20) to see if someone else has experienced the same problem.
4. Search the internet for mentions of the error message and its subject module, e.g. `ENOENT "node-sass"`
5. File a new [issue](https://github.com/mars/create-react-app-buildpack/issues/new). Please include:
   * build log output
   * link to GitHub repo with the source code (if private, grant read access to @mars)

### [Version compatibility](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-version-compatibility" id="user-content-version-compatibility"></a>

This buildpack will never intentionally cause previously deployed apps to become undeployable. Using master [as directed in the main instructions](https://solnm.gitbook.io/docs/technology/broken-reference) will always deploy an app with the most recent version of this buildpack.

[Releases are tagged](https://github.com/mars/create-react-app-buildpack/releases), so you can lock an app to a specific version, if that kind of determinism pleases you:

```
heroku buildpacks:set https://github.com/mars/create-react-app-buildpack.git#v6.0.0
```

✏️ *Replace `v6.0.0` with the desired* [*release tag*](https://github.com/mars/create-react-app-buildpack/releases)*.*

♻️ Then, commit & deploy to rebuild on the new buildpack version.

### [Architecture 🏙](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-architecture" id="user-content-architecture"></a>

This buildpack combines several buildpacks, specified in [`.buildpacks`](https://3763343587-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLqHVp1UopzsAVRGjwnpr%2Fuploads%2FsQCbXVPIlpMaMjZdmRg4%2F.buildpacks?alt=media), to support **zero-configuration deployment** on Heroku:

1. [`heroku/nodejs` buildpack](https://github.com/heroku/heroku-buildpack-nodejs)
   * installs `node`, puts on the `$PATH`
   * version specified in [`package.json`, `engines.node`](https://devcenter.heroku.com/articles/nodejs-support#specifying-a-node-js-version)
   * `node_modules/` cached between deployments
   * production build for create-react-app
     * [executes the npm package's build script](https://devcenter.heroku.com/changelog-items/1557); create-react-app default is `react-scripts build`
     * exposes all env vars to the build script
     * generates a production bundle regardless of `NODE_ENV` setting
     * customize further with [Node.js build configuration](https://devcenter.heroku.com/articles/nodejs-support#customizing-the-build-process)
2. [`mars/create-react-app-inner-buildpack`](https://github.com/mars/create-react-app-inner-buildpack)
   * sets default [web server config](https://solnm.gitbook.io/docs/technology/broken-reference) unless `static.json` already exists
   * enables [runtime environment variables](https://solnm.gitbook.io/docs/technology/broken-reference)
3. [`heroku/static` buildpack](https://github.com/heroku/heroku-buildpack-static)
   * [Nginx](http://nginx.org/en/) web server
   * [configure with `static.json`](https://solnm.gitbook.io/docs/technology/broken-reference) (see also [all static web server config](https://github.com/heroku/heroku-buildpack-static#user-content-configuration))

🚀 The runtime `web` process is the [last buildpack](https://github.com/mars/create-react-app-buildpack/blob/master/.buildpacks)'s default processes. heroku-buildpack-static uses [`bin/boot`](https://github.com/heroku/heroku-buildpack-static/blob/master/bin/release) to launch its Nginx web server. Processes may be customized by committing a [Procfile](https://solnm.gitbook.io/docs/technology/broken-reference) to the app.

#### [General-purpose SPA deployment](https://solnm.gitbook.io/docs/technology/broken-reference) <a href="#user-content-general-purpose-spa-deployment" id="user-content-general-purpose-spa-deployment"></a>

[Some kind feedback](https://github.com/mars/create-react-app-buildpack/issues/2) pointed out that this buildpack is not necessarily specific to `create-react-app`.

This buildpack can deploy any SPA \[single-page app] as long as it meets the following requirements:

* `npm run build` performs the transpile/bundling
* the file `build/index.html` or [the root specified in `static.json`](https://solnm.gitbook.io/docs/technology/broken-reference) exists at runtime.
