- Notifications
You must be signed in to change notification settings - Fork0
⚛️ Heroku Buildpack for create-react-app: static hosting for React.js web apps
License
Enzo-21/create-react-app-buildpack
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
Deploy React.js web apps generated withcreate-react-app. Automates deployment with the built-in bundler and serves it up viaNginx. See theintroductory blog post and entry inHeroku elements.
- 🚦Purpose
⚠️ Requirements- 🚀Quick Start
- 🛠Usage
- 👓Customization
- 🕵️ Troubleshooting
- 📍Version compatibility
- 🏙Architecture
This buildpack deploys a React UI as a static web site. TheNginx web server provides optimum performance and security for the runtime. SeeArchitecture for details.
If your goal is to make a single app that combines React UI with a server-side backend (Node, Ruby, Python…), then this buildpack is not the answer.
Check out these alternatives to use React with a server-side app:
- create-react-app + Node.js server ⭐️ simplest solution
- create-react-app + Ruby on Rails server
Ensurerequirements are met, then execute the following in a terminal.
✏️Replace$APP_NAME with the name for your unique app.
npx create-react-app@2.x$APP_NAMEcd$APP_NAMEgit initheroku create$APP_NAME --buildpack mars/create-react-appgit add.git commit -m"Start with create-react-app"git push heroku masterheroku open
Once deployed,continue development 🌱
For explanation about these steps, continue reading thenext section.
✏️Replace$APP_NAME with the name for your unique app.
npx create-react-app@2.x$APP_NAMEcd$APP_NAME
- npx comes with npm 5.2+ and higher, seeinstructions for older npm versions
- ifyarn is installed locally, the new app will use it instead ofnpm
git init
At this point, this new repo is local, only on your computer. Eventually, you may want topush to Github.
✏️Replace$APP_NAME with the name for your unique app.
heroku create$APP_NAME --buildpack mars/create-react-appThis command:
- sets theapp name & its default URL
https://$APP_NAME.herokuapp.com - sets the app to use thisbuildpack
- configures the
herokugit remote in the local repo, sogit push heroku masterwill push to this new Heroku app.
git add.git commit -m"Start with create-react-app"git push heroku master
…or if you are ever working on a branch other thanmaster:
✏️Replace$BRANCH_NAME with the name for the current branch.
git push heroku$BRANCH_NAME:masterheroku open
Find the app onyour dashboard.
Work with your app locally usingnpm start. See:create-react-app docs
Then, commit & deploy ♻️
Eventually, to share, collaborate, or simply back-up your code,create an empty repo at Github, and then follow the instructions shown on the repo topush an existing repository from the command line.
Usecreate-react-app's built-in Jest testing or whatever testing library you prefer.
Heroku CI is supported with minimal configuration. The CI integration is compatible with npm & yarn (seebin/test).
Heroku CI usesapp.json to provision test apps. To support Heroku CI, commit this minimal exampleapp.json:
{"buildpacks": [ {"url":"mars/create-react-app" } ]}Heroku apps may declare what processes are launched for a successful deployment by way of theProcfile. This buildpack's default process comes fromheroku/static buildpack. (See: 🏙Architecture). The implicitProcfile to start the static web server is:
web: bin/bootTo customize an app's processes, commit aProcfile and deploy. Includeweb: bin/boot to launch the default web process, or you may replace the default web process. Additionalprocess 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'sPurpose to avoid misusing this buildpack (such as running a Node server) which can lead to confusing deployment issues.
The web server may beconfigured via the static buildpack.
The config filestatic.json should be committed at the root of the repo. It will not be recognized, if this file in a sub-directory
The defaultstatic.json, if it does not exist in the repo, is:
{"root":"build/","routes": {"/**":"index.html" }}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 beset to enable runtime environment variables.
🚥Client-side routing is supported by default. Any server request that would result in 404 Not Found returns the React app.
👓 Seecustom routing w/ the static buildpack.
Enforce secure connections by automatically redirecting insecure requests tohttps://, instatic.json:
{"root":"build/","routes": {"/**":"index.html" },"https_only":true}Prevent downgrade attacks withHTTP strict transport security. Add HSTS"headers" tostatic.json.
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-ageis the number of seconds to enforce HTTPS since the last connection; the example is one-year
Proxy XHR requests from the React UI in the browser to API backends. Use to prevent same-origin errors whenCORS is not supported on the backend.
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/meYou may choose any prefix and may have multiple proxies with different prefixes.
Theheroku/static buildpack (see: 🏙Architecture) providesProxy Backends configuration to utilize Nginx for high-performance proxies in production.
Add"proxies" tostatic.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"create-react-app itself provides a built-inproxy for development. This may be configured to match the behavior ofproxy for deployment.
Add"proxy" topackage.json:
{"proxy": {"/api": {"target":"http://localhost:8000","pathRewrite": {"^/api":"/" } } }}Replacehttp://localhost:8000 with the URL to your local or remote backend service.
REACT_APP_* environment variables are fully supported with this buildpack.
🚫🤐Not for secrets. These values may be accessed by anyone who can see the React app.
heroku config:set REACT_APP_HELLO='I love sushi!'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.comREACT_APP_CLIENT_ID=XyzxYzxyZ
Two versions of variables are supported. In addition to compile-time variables applied duringbuild the app supports variables set at runtime, applied as each web dyno starts-up.
| Requirement | Compile-time | Runtime |
|---|---|---|
| never changes for a build | ✓ | |
| support forcontinuous delivery | ✓ | |
| updates immediately when setting newconfig vars | ✓ | |
| different values for staging & production (in apipeline) | ✓ | |
ex:REACT_APP_BUILD_VERSION (static fact about the bundle) | ✓ | |
ex:REACT_APP_DEBUG_ASSERTIONS (prune code from bundle) | ✓ | |
ex:REACT_APP_API_URL (transient, external reference) | ✓ | |
ex:REACT_APP_FILEPICKER_API_KEY (Add-on config vars) | ✓ |
Supports all config vars, includingREACT_APP_,NODE_,NPM_, &HEROKU_ prefixed variables.
☝️🤐Use secrets carefully. If these values are embedded in the JavaScript bundle, like withREACT_APP_ vars, then they may be accessed by anyone who can see the React app.
Use Node'sprocess.env object.
importReact,{Component}from'react';classAppextendsComponent{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
OnlyREACT_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 inpackage.json, like this:
REACT_APP_HEROKU_SLUG_COMMIT=$HEROKU_SLUG_COMMIT react-scripts buildSupports onlyREACT_APP_ prefixed variables.
🚫🤐Not for secrets. These values may be accessed by anyone who can see the React app.
Install theruntime env npm package:
npm install @mars/heroku-js-runtime-env --save
Then, require/import it to use the vars within components:
importReact,{Component}from'react';importruntimeEnvfrom'@mars/heroku-js-runtime-env';classAppextendsComponent{render(){// Load the env object.constenv=runtimeEnv();// …then use values just like `process.env`return(<code>Runtime env var example:{env.REACT_APP_HELLO}</code>);}}
\n, into Runtime config vars. Use literal UTF-8 values only; they will be automatically escaped.
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 thebundle is split.
To unset this config and use the default path forcreate-react-app's bundle,/app/build/static/js/*.js:
heroku config:unset JS_RUNTIME_TARGET_BUNDLE
🚫🤐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 to make variables set by other components available to the React app by prefixing them withREACT_APP_.
create
.profile.d/000-react-app-exports.shmake it executable
chmod +x .profile.d/000-react-app-exports.shadd an
exportline for each variable:export REACT_APP_ADDON_CONFIG=${ADDON_CONFIG:-}
set-up & useRuntime configuration to access the variables
For example, to use the API key for theFilestack JS image uploader:
export REACT_APP_FILEPICKER_API_KEY=${FILEPICKER_API_KEY:-}
Private modules are supported during build.
Setup your app with a
.npmrcfile followingnpm's guide for CI/deployment.Set your secret in the
NPM_TOKENconfig var:heroku config:set NPM_TOKEN=xxxxx
Confirm that your app is using this buildpack:
heroku buildpacks
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 masterIf the error still occurs, then at least we know it's really using this buildpack! Proceed with troubleshooting.
Check this README to see if it already mentions the issue.
Search ourissues to see if someone else has experienced the same problem.
Search the internet for mentions of the error message and its subject module, e.g.
ENOENT "node-sass"File a newissue. Please include:
- build log output
- link to GitHub repo with the source code (if private, grant read access to @mars)
This buildpack will never intentionally cause previously deployed apps to become undeployable. Using masteras directed in the main instructions will always deploy an app with the most recent version of this buildpack.
Releases are tagged, 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
✏️Replacev6.0.0 with the desiredrelease tag.
♻️ Then, commit & deploy to rebuild on the new buildpack version.
This buildpack combines several buildpacks, specified in.buildpacks, to supportzero-configuration deployment on Heroku:
heroku/nodejsbuildpack- installs
node, puts on the$PATH - version specified in
package.json,engines.node node_modules/cached between deployments- production build for create-react-app
- executes the npm package's build script; create-react-app default is
react-scripts build - exposes all env vars to the build script
- generates a production bundle regardless of
NODE_ENVsetting - customize further withNode.js build configuration
- executes the npm package's build script; create-react-app default is
- installs
mars/create-react-app-inner-buildpack- sets defaultweb server config unless
static.jsonalready exists - enablesruntime environment variables
- sets defaultweb server config unless
heroku/staticbuildpack- Nginx web server
- configure with
static.json(see alsoall static web server config)
🚀 The runtimeweb process is thelast buildpack's default processes. heroku-buildpack-static usesbin/boot to launch its Nginx web server. Processes may be customized by committing aProcfile to the app.
Some kind feedback pointed out that this buildpack is not necessarily specific tocreate-react-app.
This buildpack can deploy any SPA [single-page app] as long as it meets the following requirements:
npm run buildperforms the transpile/bundling- the file
build/index.htmlorthe root specified instatic.jsonexists at runtime.
About
⚛️ Heroku Buildpack for create-react-app: static hosting for React.js web apps
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Languages
- Shell100.0%