MERN Heroku Deployment Pt. 2

Daily Standup

Today I picked up where I left off a couple weeks ago and got our app deployed WOO!!!!

NPM Run Build

Last time I was hung up on how to build the React files instead of using npm start which set up a development server. Although that was perfect for building and running the React app locally, this isn’t how it should be done in production.

We did have a build script in the app (it just ran webpack). Eventually I went with a few posts’ suggestions to add Webpack as a normal dependency (it had been a dev dependency) to the app. This wasn’t necessary to run the app locally, but when I pushed it to Heroku, it was a necessity.

Ultimately the Heroku build and deployment started working when I split it in two steps: first initiate the Express server using the npm start script (Heroku default) in the root folder:

"start": "cd Server && npm install && node app.js"

Second step was to add a post-build script to make sure Heroku builds the React app:

"heroku-postbuild": "cd Client && npm install && npm run build"

This successfully got all of our packages installed and running. Yeah!

But…Another Problem

Even though everything built as it should, still nothing was being rendered when visiting the deployed app’s URL (or the localhost root for that matter).

Thanks to some helpful guidance at a meetup, I noticed that I had removed an important line of code from the Express server, the one that directs the app to a specific folder to serve static files. Important, because this is exactly what was causing the problem! So I added it:

// Point Node to React build files
app.use(express.static(path.join(__dirname, "../Client/build")));

And from here it worked!!!! The page would load from the Heroku URL as well as a local server. The only thing that didn’t seem to be working was serving the other static files, like CSS and JavaScript.

Serving Static CSS Files

Once again, my limited React knowledge proved to be another obstacle, and more specifically Webpack (I think). Here’s what I could see:

1. React was creating our `index.html` file using a package called `html-webpack-plugin` to create the file in `Client/public/index.html`.
2. This `index.html` file included direct paths to static files, such as `<link href="../src/style.css" type="text/css" rel="stylesheet" >` and `<script type="text/javascript" src="../src/utils/search_box.js"></script>`. But I don't know if these were linked by my teammate or automatically by `create-react-app`.
3. All of the static files in this `src` directory were not being carried over to the `build` folder when Webpack carried out each build.

So my goal was to get these files brought over by Webpack.

Interestingly, some of the other files in this src folder seem to be needed only by React to render components, etc.

Root
|-- Client
| |-- src
| | |-- components
| | | |-- APIBottom.js
| | | |-- APITop.js
| | |-- utils
| | | |-- registerServiceWorker.js
| | | |-- searchBox.js
| | | |-- seed_gen.js
| | |-- index.js
| | |-- style.css
|-- Server
|-- etc...

Only style.css and searchBox.js need to be accessible from the build folder.

I found this great article which explained how to make Webpack bundle the CSS in with the final output file. Although by default create-react-app does it slightly differently (it’s configured to create a css file in /build), this would work too.

So in our Client/src/index.js file I added an import to pull in the CSS:

import "./style.css";

Then I added two packages to help Webpack handle the CSS file (note not saving it as a dev dependency so that the file is still handled by Webpack in Heroku’s production environment):

npm install css-loader style-loader --save

And finally added the Webpack rule in Client/webpack.config.js to put these packages to use:

module.exports = {
entry: __dirname + "/src/index.js",
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader"
},
{
test:/\.css$/,
use:['style-loader','css-loader']
}
]
}
};

After this, voila! The CSS worked in the front end both on my local machine and live on our Heroku site. PROGRESS!

Serving Static JS Files

Next was getting the static JavaScript to work. Notice in the Webpack config above that there is already a rule to handle .js files. This is necessary in order to render the React components and build the app. But I don’t want my front-end JS file compiled with the rest of the app.

FAST FORWARD: Posting this a few days later…in the end my teammate moved the event handlers into each React component rather than putting the JS in a separate file. Problem solved!

Webpack Config

The final thing that got in the way was that our Webpacg config file was set up for the webpack-dev-sever to run locally on our machines. Great for development, but it caused all kinds of problems with Heroku. In the end, I created a separate production config file which entirely removes the development environment settings, and set the build command to use this file instead by editing the build script to:

"build": "webpack --config webpack.config.prod.js"

Other Stuff

There was another great article about create-react-app that was helpful, but not mentioned above.