-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy path2021-03-05_Deploy-React-App-To-Heroku-Using-Postgres---Express-70b7ea807986.html
More file actions
270 lines (267 loc) · 25.3 KB
/
2021-03-05_Deploy-React-App-To-Heroku-Using-Postgres---Express-70b7ea807986.html
File metadata and controls
270 lines (267 loc) · 25.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Deploy React App To Heroku Using Postgres & Express</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<article class="h-entry">
<header>
<h1 class="p-name">Deploy React App To Heroku Using Postgres & Express</h1>
</header>
<section data-field="subtitle" class="p-summary">
Heroku is an web application that makes deploying applications easy for a beginner.
</section>
<section data-field="body" class="e-content">
<section name="a7bd" class="section section--body section--first section--last">
<div class="section-divider">
<hr class="section-divider">
</div>
<div class="section-content">
<div class="section-inner sectionLayout--insetColumn">
<h3 name="9805" id="9805" class="graf graf--h3 graf--leading graf--title">Deploy React App To Heroku Using
Postgres & Express</h3>
<p name="9ce5" id="9ce5" class="graf graf--p graf-after--h3">Heroku is an web application that makes
deploying applications easy for a beginner.</p>
<figure name="9fca" id="9fca" class="graf graf--figure graf--iframe graf-after--p">
<script src="https://gist.github.com/bgoonz/7bf839da876126324957e1f0f0feb578.js"></script>
</figure>
<p name="7a95" id="7a95" class="graf graf--p graf-after--figure">Before you begin deploying, make sure to
remove any <code class="markup--code markup--p-code">console.log</code>'s or <code
class="markup--code markup--p-code">debugger</code>'s in any production code. You can search your
entire project folder if you are using them anywhere.</p>
<p name="0120" id="0120" class="graf graf--p graf-after--p">You will set up Heroku to run on a production,
not development, version of your application. When a Node.js application like yours is pushed up to
Heroku, it is identified as a Node.js application because of the <code
class="markup--code markup--p-code">package.json</code> file. It runs <code
class="markup--code markup--p-code">npm install</code> automatically. Then, if there is a <code
class="markup--code markup--p-code">heroku-postbuild</code> script in the <code
class="markup--code markup--p-code">package.json</code> file, it will run that script. Afterwards, it
will automatically run <code class="markup--code markup--p-code">npm start</code>.</p>
<p name="4bd8" id="4bd8" class="graf graf--p graf-after--p">In the following phases, you will configure
your application to work in production, not just in development, and configure the <code
class="markup--code markup--p-code">package.json</code> scripts for <code
class="markup--code markup--p-code">install</code>, <code
class="markup--code markup--p-code">heroku-postbuild</code> and <code
class="markup--code markup--p-code">start</code> scripts to install, build your React application, and
start the Express production server.</p>
<h3 name="6c67" id="6c67" class="graf graf--h3 graf-after--p">Phase 1: Heroku Connection</h3>
<p name="983d" id="983d" class="graf graf--p graf-after--h3">If you haven’t created a Heroku account yet,
create one <a href="https://signup.heroku.com/" data-href="https://signup.heroku.com/"
class="markup--anchor markup--p-anchor" rel="nofollow noopener" target="_blank">here</a>.</p>
<p name="fd5c" id="fd5c" class="graf graf--p graf-after--p">Add a new application in your <a
href="https://dashboard.heroku.com/" data-href="https://dashboard.heroku.com/"
class="markup--anchor markup--p-anchor" rel="nofollow noopener" target="_blank">Heroku dashboard</a>
named whatever you want. Under the “Resources” tab in your new application, click “Find more add-ons”
and add the “Heroku Postgres” add-on with the free Hobby Dev setting.</p>
<p name="7c07" id="7c07" class="graf graf--p graf-after--p">In your terminal, install the <a
href="https://devcenter.heroku.com/articles/heroku-command-line"
data-href="https://devcenter.heroku.com/articles/heroku-command-line"
class="markup--anchor markup--p-anchor" rel="nofollow noopener" target="_blank">Heroku CLI</a>.
Afterwards, login to Heroku in your terminal by running the following:</p>
<pre name="bcfa" id="bcfa"
class="graf graf--pre graf-after--p"><code class="markup--code markup--pre-code">heroku login</code></pre>
<p name="eb37" id="eb37" class="graf graf--p graf-after--pre">Add Heroku as a remote to your project’s git
repository in the following command and replace <code
class="markup--code markup--p-code"><name-of-Heroku-app></code> with the name of the application
you created in the <a href="https://dashboard.heroku.com/" data-href="https://dashboard.heroku.com/"
class="markup--anchor markup--p-anchor" rel="nofollow noopener" target="_blank">Heroku dashboard</a>.
</p>
<pre name="69d1" id="69d1"
class="graf graf--pre graf-after--p"><code class="markup--code markup--pre-code">heroku git:remote -a <name-of-Heroku-app></code></pre>
<p name="8947" id="8947" class="graf graf--p graf-after--pre">Next, you will set up your Express + React
application to be deployable to Heroku.</p>
<h3 name="6d41" id="6d41" class="graf graf--h3 graf-after--p">Phase 2: Setting up your Express + React
application</h3>
<p name="6a49" id="6a49" class="graf graf--p graf-after--h3">Right now, your React application is on a
different localhost port than your Express application. However, since your React application only
consists of static files that don’t need to bundled continuously with changes in production, your
Express application can serve the React assets in production too. These static files live in the <code
class="markup--code markup--p-code">frontend/build</code> folder after running <code
class="markup--code markup--p-code">npm run build</code> in the <code
class="markup--code markup--p-code">frontend</code> folder.</p>
<p name="ed99" id="ed99" class="graf graf--p graf-after--p">Add the following changes into your <code
class="markup--code markup--p-code">backend/routes.index.js</code> file.</p>
<p name="0d3e" id="0d3e" class="graf graf--p graf-after--p">At the root route, serve the React
application’s static <code class="markup--code markup--p-code">index.html</code> file along with <code
class="markup--code markup--p-code">XSRF-TOKEN</code> cookie. Then serve up all the React
application's static files using the <code class="markup--code markup--p-code">express.static</code>
middleware. Serve the <code class="markup--code markup--p-code">index.html</code> and set the <code
class="markup--code markup--p-code">XSRF-TOKEN</code> cookie again on all routes that don't start
in <code class="markup--code markup--p-code">/api</code>. You should already have this set up in <code
class="markup--code markup--p-code">backend/routes/index.js</code> which should now look like this:
</p>
<pre name="50a6" id="50a6"
class="graf graf--pre graf-after--p"><code class="markup--code markup--pre-code">// backend/routes/index.js<br>const express = require('express');<br>const router = express.Router();<br>const apiRouter = require('./api');</code></pre>
<pre name="08dd" id="08dd"
class="graf graf--pre graf-after--pre"><code class="markup--code markup--pre-code">router.use('/api', apiRouter);</code></pre>
<pre name="1f34" id="1f34"
class="graf graf--pre graf-after--pre"><code class="markup--code markup--pre-code">// Static routes<br>// Serve React build files in production<br>if (process.env.NODE_ENV === 'production') {<br> const path = require('path');<br> // Serve the frontend's index.html file at the root route<br> router.get('/', (req, res) => {<br> res.cookie('XSRF-TOKEN', req.csrfToken());<br> res.sendFile(<br> path.resolve(__dirname, '../../frontend', 'build', 'index.html')<br> );<br> });</code></pre>
<pre name="5f4c" id="5f4c"
class="graf graf--pre graf-after--pre"><code class="markup--code markup--pre-code"> // Serve the static assets in the frontend's build folder<br> router.use(express.static(path.resolve("../frontend/build")));</code></pre>
<pre name="b4c2" id="b4c2"
class="graf graf--pre graf-after--pre"><code class="markup--code markup--pre-code"> // Serve the frontend's index.html file at all other routes NOT starting with /api<br> router.get(/^(?!\/?api).*/, (req, res) => {<br> res.cookie('XSRF-TOKEN', req.csrfToken());<br> res.sendFile(<br> path.resolve(__dirname, '../../frontend', 'build', 'index.html')<br> );<br> });<br>}</code></pre>
<pre name="e2ce" id="e2ce"
class="graf graf--pre graf-after--pre"><code class="markup--code markup--pre-code">// Add a XSRF-TOKEN cookie in development<br>if (process.env.NODE_ENV !== 'production') {<br> router.get('/api/csrf/restore', (req, res) => {<br> res.cookie('XSRF-TOKEN', req.csrfToken());<br> res.status(201).json({});<br> });<br>}</code></pre>
<pre name="dd71" id="dd71"
class="graf graf--pre graf-after--pre"><code class="markup--code markup--pre-code">module.exports = router;</code></pre>
<p name="532c" id="532c" class="graf graf--p graf-after--pre">Your Express backend’s <code
class="markup--code markup--p-code">package.json</code> should include scripts to run the <code
class="markup--code markup--p-code">sequelize</code> CLI commands.</p>
<p name="6174" id="6174" class="graf graf--p graf-after--p">The <code
class="markup--code markup--p-code">backend/package.json</code>'s scripts should now look like
this:</p>
<pre name="1e1f" id="1e1f"
class="graf graf--pre graf-after--p"><code class="markup--code markup--pre-code">"scripts": {<br> "sequelize": "sequelize",<br> "sequelize-cli": "sequelize-cli",<br> "start": "per-env",<br> "start:development": "nodemon -r dotenv/config ./bin/www",<br> "start:production": "node ./bin/www"<br> },</code></pre>
<p name="adf5" id="adf5" class="graf graf--p graf-after--pre">Initialize a <code
class="markup--code markup--p-code">package.json</code> file at the very root of your project
directory (outside of both the <code class="markup--code markup--p-code">backend</code> and <code
class="markup--code markup--p-code">frontend</code> folders). The scripts defined in this <code
class="markup--code markup--p-code">package.json</code> file will be run by Heroku, not the scripts
defined in the <code class="markup--code markup--p-code">backend/package.json</code> or the <code
class="markup--code markup--p-code">frontend/package.json</code>.</p>
<p name="94a6" id="94a6" class="graf graf--p graf-after--p">When Heroku runs <code
class="markup--code markup--p-code">npm install</code>, it should install packages for both the <code
class="markup--code markup--p-code">backend</code> and the <code
class="markup--code markup--p-code">frontend</code>. Overwrite the <code
class="markup--code markup--p-code">install</code> script in the root <code
class="markup--code markup--p-code">package.json</code> with:</p>
<pre name="fff0" id="fff0"
class="graf graf--pre graf-after--p"><code class="markup--code markup--pre-code">npm --prefix backend install backend && npm --prefix frontend install frontend</code></pre>
<p name="b632" id="b632" class="graf graf--p graf-after--pre">This will run <code
class="markup--code markup--p-code">npm install</code> in the <code
class="markup--code markup--p-code">backend</code> folder then run <code
class="markup--code markup--p-code">npm install</code> in the <code
class="markup--code markup--p-code">frontend</code> folder.</p>
<p name="ee4d" id="ee4d" class="graf graf--p graf-after--p">Next, define a <code
class="markup--code markup--p-code">heroku-postbuild</code> script that will run the <code
class="markup--code markup--p-code">npm run build</code> command in the <code
class="markup--code markup--p-code">frontend</code> folder. Remember, Heroku will automatically run
this script after running <code class="markup--code markup--p-code">npm install</code>.</p>
<p name="7ea1" id="7ea1" class="graf graf--p graf-after--p">Define a <code
class="markup--code markup--p-code">sequelize</code> script that will run <code
class="markup--code markup--p-code">npm run sequelize</code> in the <code
class="markup--code markup--p-code">backend</code> folder.</p>
<p name="74af" id="74af" class="graf graf--p graf-after--p">Finally, define a <code
class="markup--code markup--p-code">start</code> that will run <code
class="markup--code markup--p-code">npm start</code> in the `backend folder.</p>
<p name="f146" id="f146" class="graf graf--p graf-after--p">The root <code
class="markup--code markup--p-code">package.json</code>'s scripts should look like this:</p>
<pre name="71cf" id="71cf"
class="graf graf--pre graf-after--p"><code class="markup--code markup--pre-code">"scripts": {<br> "heroku-postbuild": "npm run build --prefix frontend",<br> "install": "npm --prefix backend install backend && npm --prefix frontend install frontend",<br> "dev:backend": "npm install --prefix backend start",<br> "dev:frontend": "npm install --prefix frontend start",<br> "sequelize": "npm run --prefix backend sequelize",<br> "sequelize-cli": "npm run --prefix backend sequelize-cli",<br> "start": "npm start --prefix backend"<br> },</code></pre>
<p name="0a93" id="0a93" class="graf graf--p graf-after--pre">The <code
class="markup--code markup--p-code">dev:backend</code> and <code
class="markup--code markup--p-code">dev:frontend</code> scripts are optional and will not be used for
Heroku.</p>
<p name="5899" id="5899" class="graf graf--p graf-after--p">Finally, commit your changes.</p>
<h3 name="827c" id="827c" class="graf graf--h3 graf-after--p">Phase 3: Deploy to Heroku</h3>
<p name="8f37" id="8f37" class="graf graf--p graf-after--h3">Once you’re finished setting this up,
navigate to your application’s Heroku dashboard. Under “Settings” there is a section for “Config Vars”.
Click the <code class="markup--code markup--p-code">Reveal Config Vars</code> button to see all your
production environment variables. You should have a <code
class="markup--code markup--p-code">DATABASE_URL</code> environment variable already from the Heroku
Postgres add-on.</p>
<p name="3b85" id="3b85" class="graf graf--p graf-after--p">Add environment variables for <code
class="markup--code markup--p-code">JWT_EXPIRES_IN</code> and <code
class="markup--code markup--p-code">JWT_SECRET</code> and any other environment variables you need for
production.</p>
<p name="9535" id="9535" class="graf graf--p graf-after--p">You can also set environment variables through
the Heroku CLI you installed earlier in your terminal. See the docs for <a
href="https://devcenter.heroku.com/articles/config-vars"
data-href="https://devcenter.heroku.com/articles/config-vars" class="markup--anchor markup--p-anchor"
rel="nofollow noopener" target="_blank">Setting Heroku Config Variables</a>.</p>
<p name="fc5b" id="fc5b" class="graf graf--p graf-after--p">Push your project to Heroku. Heroku only
allows the <code class="markup--code markup--p-code">master</code> branch to be pushed. But, you can
alias your branch to be named <code class="markup--code markup--p-code">master</code> when pushing to
Heroku. For example, to push a branch called <code
class="markup--code markup--p-code">login-branch</code> to <code
class="markup--code markup--p-code">master</code> run:</p>
<pre name="a60d" id="a60d"
class="graf graf--pre graf-after--p"><code class="markup--code markup--pre-code">git push heroku login-branch:master</code></pre>
<p name="89b7" id="89b7" class="graf graf--p graf-after--pre">If you do want to push the <code
class="markup--code markup--p-code">master</code> branch, just run:</p>
<pre name="efb9" id="efb9"
class="graf graf--pre graf-after--p"><code class="markup--code markup--pre-code">git push heroku master</code></pre>
<p name="ffb6" id="ffb6" class="graf graf--p graf-after--pre">You may want to make two applications on
Heroku, the <code class="markup--code markup--p-code">master</code> branch site that should have working
code only. And your <code class="markup--code markup--p-code">staging</code> site that you can use to
test your work in progress code.</p>
<p name="c91f" id="c91f" class="graf graf--p graf-after--p">Now you need to migrate and seed your
production database.</p>
<p name="3ff5" id="3ff5" class="graf graf--p graf-after--p">Using the Heroku CLI, you can run commands
inside of your production application just like in development using the <code
class="markup--code markup--p-code">heroku run</code> command.</p>
<p name="76a6" id="76a6" class="graf graf--p graf-after--p">For example to migrate the production
database, run:</p>
<pre name="d296" id="d296"
class="graf graf--pre graf-after--p"><code class="markup--code markup--pre-code">heroku run npm run sequelize db:migrate</code></pre>
<p name="5a41" id="5a41" class="graf graf--p graf-after--pre">To seed the production database, run:</p>
<pre name="26b8" id="26b8"
class="graf graf--pre graf-after--p"><code class="markup--code markup--pre-code">heroku run npm run sequelize db:seed:all</code></pre>
<p name="c703" id="c703" class="graf graf--p graf-after--pre">Note: You can interact with your database
this way as you’d like, but beware that <code class="markup--code markup--p-code">db:drop</code> cannot
be run in the Heroku environment. If you want to drop and create the database, you need to remove and
add back the "Heroku Postgres" add-on.</p>
<p name="97ba" id="97ba" class="graf graf--p graf-after--p">Another way to interact with the production
application is by opening a bash shell through your terminal by running:</p>
<pre name="4ede" id="4ede"
class="graf graf--pre graf-after--p"><code class="markup--code markup--pre-code">heroku bash</code></pre>
<p name="6e54" id="6e54" class="graf graf--p graf-after--pre">In the opened shell, you can run things like
<code class="markup--code markup--p-code">npm run sequelize db:migrate</code>.</p>
<p name="f98e" id="f98e" class="graf graf--p graf-after--p">Open your deployed site and check to see if
you successfully deployed your Express + React application to Heroku!</p>
<p name="8041" id="8041" class="graf graf--p graf-after--p">If you see an <code
class="markup--code markup--p-code">Application Error</code> or are experiencing different behavior
than what you see in your local environment, check the logs by running:</p>
<pre name="3605" id="3605"
class="graf graf--pre graf-after--p"><code class="markup--code markup--pre-code">heroku logs</code></pre>
<p name="3e1d" id="3e1d" class="graf graf--p graf-after--pre">If you want to open a connection to the logs
to continuously output to your terminal, then run:</p>
<pre name="18f4" id="18f4"
class="graf graf--pre graf-after--p"><code class="markup--code markup--pre-code">heroku logs --tail</code></pre>
<p name="3611" id="3611" class="graf graf--p graf-after--pre">The logs may clue you into why you are
experiencing errors or different behavior.</p>
<h4 name="4553" id="4553" class="graf graf--h4 graf-after--p">If you found this guide helpful feel free to
checkout my github/gists where I host similar content:</h4>
<p name="1c2f" id="1c2f" class="graf graf--p graf-after--h4"><a href="https://gist.github.com/bgoonz"
data-href="https://gist.github.com/bgoonz" class="markup--anchor markup--p-anchor" rel="noopener"
target="_blank">bgoonz’s gists · GitHub</a></p>
<div name="3585" id="3585" class="graf graf--mixtapeEmbed graf-after--p"><a
href="https://github.com/bgoonz" data-href="https://github.com/bgoonz"
class="markup--anchor markup--mixtapeEmbed-anchor" title="https://github.com/bgoonz"><strong
class="markup--strong markup--mixtapeEmbed-strong">bgoonz — Overview</strong><br><em
class="markup--em markup--mixtapeEmbed-em">Web Developer, Electrical Engineer JavaScript | CSS |
Bootstrap | Python | React | Node.js | Express | Sequelize…</em>github.com</a><a
href="https://github.com/bgoonz" class="js-mixtapeImage mixtapeImage u-ignoreBlock"
data-media-id="6ee74d5200d495ddc7ddad0c92bd6dce" data-thumbnail-img-id="0*Udg3rbeFyslZ9dyl"
style="background-image: url(https://cdn-images-1.medium.com/fit/c/160/160/0*Udg3rbeFyslZ9dyl);"></a>
</div>
<p name="cb1a" id="cb1a" class="graf graf--p graf-after--mixtapeEmbed">Or Checkout my personal Resource
Site:</p>
<div name="4bce" id="4bce" class="graf graf--mixtapeEmbed graf-after--p graf--trailing"><a
href="https://goofy-euclid-1cd736.netlify.app/" data-href="https://goofy-euclid-1cd736.netlify.app/"
class="markup--anchor markup--mixtapeEmbed-anchor"
title="https://goofy-euclid-1cd736.netlify.app/"><strong
class="markup--strong markup--mixtapeEmbed-strong">a/A-Student-Resources</strong><br><em
class="markup--em markup--mixtapeEmbed-em">Edit
description</em>goofy-euclid-1cd736.netlify.app</a><a
href="https://goofy-euclid-1cd736.netlify.app/" class="js-mixtapeImage mixtapeImage u-ignoreBlock"
data-media-id="260adefce95974b3b8f27566d0434b9c" data-thumbnail-img-id="0*kHvsYWw7LFYl0PB_"
style="background-image: url(https://cdn-images-1.medium.com/fit/c/160/160/0*kHvsYWw7LFYl0PB_);"></a>
</div>
</div>
</div>
</section>
</section>
<footer>
<p>By <a href="https://medium.com/@bryanguner" class="p-author h-card">Bryan Guner</a> on <a
href="https://medium.com/p/70b7ea807986"><time class="dt-published"
datetime="2021-03-05T14:59:13.421Z">March 5, 2021</time></a>.</p>
<p><a href="https://medium.com/@bryanguner/deploy-react-app-to-heroku-using-postgres-express-70b7ea807986"
class="p-canonical">Canonical link</a></p>
<p>Exported from <a href="https://medium.com">Medium</a> on April 3, 2021.</p>
</footer>
</article>
</body>
</html>