This tutorial will have you deploying a Single Page App in minutes.
Hang on for a few more minutes to learn how it all works, so you can make the most out of Heroku.
The tutorial assumes that you have:
- a free Heroku account
- Node 4+ installed locally
In this step you will install the Heroku Toolbelt. This provides you access to the Heroku Command Line Interface (CLI), which can be used for managing and scaling your applications and add-ons. A key part of the toolbelt is the heroku local
command, which can help in running your applications locally.
Once installed, you can use the heroku
command from your command shell.
Log in using the email address and password you used when creating your Heroku account:
$ heroku login
Enter your Heroku credentials.
Email: me@example.com
Password:
...
Authenticating is required to allow both the heroku and git commands to operate.
Note that if you’re behind a firewall that requires use of a proxy to connect with external HTTP/HTTPS services, you can set the HTTP_PROXY
or HTTPS_PROXY
environment variables in your local development environment before running the heroku
command.
In order to take advantage of this beta product, we provide a set of commands for the Heroku Toolbelt in the static
namespace. To get this, you'll need to install the heroku-cli-static
plugin.
$ heroku plugins:install heroku-cli-static
In this step, you will prepare a simple application that can be deployed.
Execute the following commands to clone the sample application:
$ git clone https://github.com/heroku/wywh.git
$ cd wywh
You now have a functioning git repository that contains a simple application.
To get the app running, you first need the dependencies for your application. The way this app is setup, the following command will install all the dependencies as well as build the assets into a public/
directory. We'll be using npm which is the node package manager.
$ NODE_ENV=production npm install
> node-sass@3.4.2 install /home/hone/Projects/heroku_work/frontend/apps/wywh/node_modules/node-sass
> node scripts/install.js
...
> heroku-event-signup@1.0.0 postinstall /home/hone/Projects/heroku_work/frontend/apps/wywh
> webpack
Hash: 498f5ec33dc0481ab623
Version: webpack 1.12.13
Time: 21864ms
Asset Size Chunks Chunk Names
f4769f9bdb7466be65088239c12046d1.eot 20.1 kB [emitted]
89889688147bd7575d6327160d64e760.svg 109 kB [emitted]
87faad85511847d6d753bd02ab2e607a.svg 1.69 kB [emitted]
6df9140f6920c8de454cee4a491a0e01.svg 4.41 kB [emitted]
e18bbf611f2a2e43afc071aa2f4e1512.ttf 45.4 kB [emitted]
fa2772327f55d8198301fdb8bcfc8158.woff 23.4 kB [emitted]
448c34a56d699c29117adc64c43affeb.woff2 18 kB [emitted]
heroku-event-signup.1.0.0.js 755 kB 0 [emitted] main
heroku-event-signup.1.0.0.css 16.1 kB 0 [emitted] main
index.html 699 bytes [emitted]
[0] multi main 28 bytes {0} [built]
+ 908 hidden modules
Child extract-text-webpack-plugin:
Asset Size Chunks Chunk Names
f4769f9bdb7466be65088239c12046d1.eot 20.1 kB [emitted]
89889688147bd7575d6327160d64e760.svg 109 kB [emitted]
87faad85511847d6d753bd02ab2e607a.svg 1.69 kB [emitted]
6df9140f6920c8de454cee4a491a0e01.svg 4.41 kB [emitted]
e18bbf611f2a2e43afc071aa2f4e1512.ttf 45.4 kB [emitted]
fa2772327f55d8198301fdb8bcfc8158.woff 23.4 kB [emitted]
448c34a56d699c29117adc64c43affeb.woff2 18 kB [emitted]
+ 10 hidden modules
...
Now start your application locally using the heroku local
command, which was installed as part of the Toolbelt:
$ heroku local web
forego | starting web.1 on port 5000
web.1 | Server running at: http://x220:5000
Just like Heroku, heroku local
examines the Procfile
to determine what to run.
Open http://localhost:5000 with your web browser. You should see your app running locally.
To stop the app from running locally, in the CLI, press Ctrl
+C
to exit.
In this step you will deploy the app to Heroku.
Create an app on Heroku, which prepares Heroku to receive your source code.
$ heroku create
Creating sharp-rain-871... done, stack is cedar-14
http://sharp-rain-871.herokuapp.com/ | https://git.heroku.com/sharp-rain-871.git
Git remote heroku added
When you create an app, a git remote (called heroku
) is also created and associated with your local git repository.
Heroku generates a random name (in this case sharp-rain-871
) for your app, or you can pass a parameter to specify your own app name.
Express is used for serving assets during local development. To deploy this application on Heroku, you'll be using the static buildpack to replace the express server in production. Buildpacks handle the glue code for a specific language or use case. In this case, the static buildpack is used for serving your static assets. To set the buildpack, you need to run:
$ heroku buildpacks:set https://github.com/hone/heroku-buildpack-static
To start, you can use heroku static:init
to bootstrap our static configuration file, static.json
. The application builds its assets in the public/
directory.
$ heroku static:init
? Enter the directory of your app: (public_html) public
? Drop `.html` extensions from urls? No
? Path to custom error page from root directory:
{
"root": "public",
"clean_urls": false
}
With the assets built from before by running npm install
from above and the newly minted static.json
, you're ready to deploy the app. The heroku static:deploy
command, bundles up static.json
along with the asset directory specified in the static.json
.
$ heroku static:deploy
Uploading app
Creating build
-----> Fetching set buildpack https://github.com/hone/heroku-buildpack-static... done
-----> Static HTML app detected
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 838k 100 838k 0 0 9956k 0 --:--:-- --:--:-- --:--:-- 9983k
-----> Installed directory to /app/bin
-----> Discovering process types
Procfile declares types -> (none)
Default types for buildpack -> web
-----> Compressing...
Done: 1.3M
-----> Launching...
Released v19
https://sharp-rain-871.herokuapp.com/ deployed to Heroku
The application is now deployed. Ensure that at least one instance of the app is running:
$ heroku ps:scale web=1
Now visit the app at the URL generated by its app name. As a handy shortcut, you can open the website as follows:
$ heroku open
Push State is used to manipulate the browser history, allowing rich JavaScript applications to ensure URLs continue to be useful. If you try to go to a page that isn't the index, but actually exists:
$ curl -I https://sharp-rain-871.herokuapp.com/conferences/
HTTP/1.1 404 Not Found
Connection: keep-alive
Server: nginx
Date: Wed, 10 Feb 2016 06:56:17 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 162
Via: 1.1 vegur
This can be fixed, but using a custom route. In your static.json
, you can add a custom route that redirects all routes to the index.html
.
{
"root": "public",
"clean_urls": false,
"routes": {
"/**": "index.html"
}
}
With these changes, you can deploy them onto Heroku to have them take effect.
$ curl -I https://sharp-rain-871.herokuapp.com/conferences/
HTTP/1.1 200 OK
Connection: keep-alive
Server: nginx
Date: Wed, 10 Feb 2016 07:08:59 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 699
Last-Modified: Wed, 10 Feb 2016 06:41:29 GMT
Vary: Accept-Encoding
Etag: "56badb99-2bb"
Accept-Ranges: bytes
Via: 1.1 vegur
As can be seen, this is the exact same as the index route:
$ curl -I https://sharp-rain-871.herokuapp.com/
HTTP/1.1 200 OK
Connection: keep-alive
Server: nginx
Date: Wed, 10 Feb 2016 07:09:38 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 699
Last-Modified: Wed, 10 Feb 2016 06:41:29 GMT
Vary: Accept-Encoding
Etag: "56badb99-2bb"
Accept-Ranges: bytes
Via: 1.1 vegur
Not only can you build locally, but you can also build your assets on Heroku during the deploy process. By doing this, you can advantage of some Heroku Flow features such as Review Apps or GitHub Sync.
You'll be using git to deploy this time instead of the heroku static:deploy
command, which is built for local asset building. This means, you'll need to add the static.json
file from above to git.
$ git add static.json
$ git commit -m "add static configuration"
You'll also need to remove the Procfile
that has an entry for starting the Express server. Instead, the static buildpack will handle creating a web entry.
$ git rm Procfile
$ git commit -m "remove Procfile"
In order to build the assets on Heroku, you'll need to take advantage of multiple buildpacks. This will let you use the Node.js buildpack to build the assets on Heroku and then serve them with the static buildpack.
$ heroku buildpacks:clear
$ heroku buildpacks:add heroku/nodejs
$ heroku buildpacks:add https://github.com/hone/heroku-buildpack-static
With all that, you can now deploy:
$ git push heroku master
Counting objects: 8, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (7/7), done.
Writing objects: 100% (8/8), 773 bytes | 0 bytes/s, done.
Total 8 (delta 3), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Using set buildpack heroku/nodejs
remote: -----> Node.js app detected
remote:
remote: -----> Creating runtime environment
remote:
remote: NPM_CONFIG_LOGLEVEL=error
remote: NPM_CONFIG_PRODUCTION=true
remote: NODE_ENV=production
remote: NODE_MODULES_CACHE=true
remote:
remote: -----> Installing binaries
remote: engines.node (package.json): ^4.0.0
remote: engines.npm (package.json): ^3.0.0
remote:
remote: Resolving node version ^4.0.0 via semver.io...
remote: Downloading and installing node 4.3.0...
...
remote: -----> Fetching set buildpack https://github.com/hone/heroku-buildpack-static... done
remote: -----> Static HTML app detected
remote: % Total % Received % Xferd Average Speed Time Time Time Current
remote: Dload Upload Total Spent Left Speed
remote: 100 838k 100 838k 0 0 11.1M 0 --:--:-- --:--:-- --:--:-- 11.2M
remote: -----> Installed directory to /app/bin
remote:
remote: -----> Discovering process types
remote: Procfile declares types -> (none)
remote: Default types for buildpack -> web
remote:
remote: -----> Compressing...
remote: Done: 32M
remote: -----> Launching...
remote: Released v3
remote: https://sharp-rain-871.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy.... done.
To https://git.heroku.com/sharp-rain-871.git
* [new branch] master -> master
You can use heroku open
to view the newly deployed app.
You now know how to deploy an app.
Here's some recommended reading.
- Read the static buildpack Readme which lists all the features that can be used.
- Read How Heroku Works for a technical overview of the concepts you’ll encounter while writing, configuring, deploying and running applications.
Thank you for this detailed explanation. We have a similar but a bit different set up:
We have a node app that serves a react app website, and it's all in the same repo.
Right now what we do is using the node buildpack, and in the build phase we building the client assets:
The problem with this approach is that we don't leverage the cache features for the client node modules. Maybe if we'll build a dedicated CRA buildpack and use it before the node buildpack, it will solve the problem, what do you say?