Structuring Angular/React + Node.js Application for Heroku Hosting

So the primary intention for writing this article is to give a little head start for the beginners to structure out their application for a good hosting environment like Heroku. Heroku allows you to both Pipeline your application using a remote VCS tool like GitHub, which makes it so much easier, and to configure your application using Heroku CLI locally and push it remotely. Here we’ll discuss how to structure your content to connect your GitHub repository branch to deploy your application in Heroku.

Structuring your application is a very critical task which you have to reconcile at the very beginning. If you ever made the incorrect file structure then you might know what I am talking about.

The main concept

Well, it doesn’t matter what your client side framework is going to be. Eventually, you will build all of those files (This is prominent for a large framework like Angular) and get a dist folder which contains an index.html file and some JavaScript files. What the framework does is to provide a platform to create these files.

So by referring to our main concept, it might be apparent to you that our root should not be the client side framework. Our root should be the server side. This is because whatever the client side framework you’re gonna use, it will get eventually built up and put into the server’s static content directory so that it is served up at the / route.

Note: In large scale applications, the client is usually hosted in a web server such as NGINX and the server is hosted somewhere else (In a container, a physical server, etc.). In this case, the double-origin system still exists, but the proxying still needs to happen.

So it is wise if you keep your file structure as displayed in the image below.

Image for post
Image for post
File Structure of a Full-Stack

Notice that this use MV* Pattern and the client is where your Angular application lives.

Configure the client

What you gotta understand is, we are about to make the double-origin application a single origin application. That is, we’re gonna make the application run in one port. Thus you need to build your client side and move that into the static content directory as the primary way which a browser renders an application — with a index.html and a bunch of Javascript files. This is why you build the application. Building is done by running a CLI command which you can find in each of the client side framework documentation. More on this later.

Proxying to the backend.

Let us get this concept straight. To do that, we must consider both the production environment and the development environment. In the production environment, since Heroku will serve your application from their own origin (i.e. their own server space) when you make calls to your backend from the Angular application, you need to make calls to the same origin. For example, in a development environment where you spin up two ports one for Angular and one for Node, you make Angular service calls from port 4200 to the Node port 8080. But in production environments, like Heroku, you make requests to the same origin.

Let us go to that particular instance where you have two ports. Here’s a typical Angular HTTP call (via a service) which you make to the backend.

Image for post
Image for post

But soon after we change into the production environment, there is only one origin. There are no two ports but one. So we need to do the HTTP call like this.

Image for post
Image for post

To resolve this conflict between the source code in the services in two environments, we use a proxy.conf.json file. Here is a sample config file.

Image for post
Image for post

What this will do is it will proxy all your HTTP requests which starts with /, to http://localhost:8080 origin, thus we're able to keep the same service code throughout the two environments. But be sure to alter your start script in package.json to serve up with a proxy. And make sure you serve your application using npm start not ng serve because we have configured a different start script.

Image for post
Image for post
Be sure to add this to your start script

Refer more to proxying to the backend from Angular official documentation.

This is an example for consuming from the back-end through an Angular service,

Image for post
Image for post
Use this instead of http://localhost:8080/getforks

This is the endpoint of the back-end where the above service is hitting. Note that the picture below is a code snippet of a Java backend and I hope it is trivial to compare it with node.

Image for post
Image for post
Backend endpoint

Note that proxying the backend is a concept we configure in the development environment prior to doing any HTTP requests. If you configure it after implementing the services you would have to go through each service and replace http://localhost:8080 with /. Therefore, implement all the services using proxies.

Building your client side

No matter how extensive the file structure of your client application (e.g. Angular, React or Vue) is going to be, it eventually is going to be built up to a index.html file and some JavaScript files. This is because the browser itself only understands HTML and JavaScript. If you ever wondered about the structure of a Web-browser, you might know what I am talking about. A web browser usually consists of two major components — one being able to interpret JavaScript (Called the JavaScript Engine) and the other is able to render HTML. So if you’re using React — your JSX syntax needs to be bundled up into ES5 standards (We confine our talk to ES5 because it is well supported in all the browsers). If you’re using Angular, your TypeScript files are eventually compiled into the same standard. So all these files are rendered through the rendering engine which each of the browser processes. If you’re using Chrome, it is rendered through its own JavaScript engine called V8 which is a great base for Electron (A great tool by GitHub to create desktop applications using web technologies). If it is IE, JavaScript is rendered using Chakra. If it is Firefox, JavaScript is rendered through SpiderMonkey which they redid for a better performance (And they succeeded with the release of Firefox Quantum).

So, in Angular, you build the client side using ng build — prod and in React you build using npm run build . These build scripts are specified in package.json . Building the application usually builds up a dist folder where all the static content (index.html and the JS files we’ve talked about) lives in. What should be done after building is to copy these files into the static files directory which you configure in the server side — which is our next topic - Configure the server.

Configure the server

So how exactly are we going to configure the server-side so that it serves up our client? That is where public folder comes in.

In Express API, which is used as a Node Framework, you have the capability to specify the location of the static files. We us static middleware to do this.

app.use(express.static('public'))

This eventually tells that the server needs to serve up the static content from public folder, where the content of your build i.e. content of your dist folder, lives in. Make sure that your server serves up index.html which lives in the dist folder is served up at /.

In development environments we used to serve up two applications, one being the Angular/React app and the server side app. But now, after configuring this, you can serve up your application using one origin that is, the port where your server is served up. Simply open http://localhost:3000 (Your backend port) in your browser and you will get served up with the index.html you’ve just built.

Heroku

So that’s it. All you have got to do is to link your application in Heroku.

Create a new Heroku app in Heroku dashboard (In official site) and link your GitHub profile and the repository there.

Image for post
Image for post

Make sure you add the correct branch.

Image for post
Image for post

If you have some CI tools you can enable automatic deployments but I have not configured it so I didn’t enable it.

When it comes to the database you can configure a remote database using mLab and use that database in your server.js. If you have got a MySQL database or a GraphDB like Neo4j, you need to host the database somewhere and configure the credentials including host, username, password, database name, port (The database hosting service will provide you all these) etc. in your server-side database configurations. Doing this will point the server to the remote database where you host the database.

Note: In this article I went through how to structure your application so that you can deploy your application using the same remote repository which you use to do development work. However, you can take a different approach and use Heroku CLI to host your server folder, which is the other approach that Heroku themselves suggests.

A little bit about Continuous Integration

However, I find it easier to use CI tools (Continuous Integration Tools) with Heroku being deployed with the remote repository, thus I can attach a pipeline to the production. Adding a pipeline to the production will reflect the commits we push to the remote repository in the production. CI tools are recommended by default since we are directly pushing to the production, (because of the pipeline) even a minor change could cause an adverse effect to the overall production. Thus, the CI tools provide an efficient platform to write scripts of tests which are to be run prior to the push towards the remote repository. In case of a failure of the tests (You can adjust how critical these tests can be for the production) you can adjust the CI tool to reject the push and prompt the errors or exceptions.

Have fun deploying!

Software Engineer @ CodeGen International, CSE Graduate @ University of Moratuwa

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store