We at Orpheus Digital made a decision to try out a NodeJS stack. After much research, we decided to go for the most famous stack – ExpressJS. Currently, PHP over a CodeIgniter framework drives almost all our server-side systems. This stack performs well. However, the decline in popularity of CodeIgniter pressured us to adopt a more modern tech stack.
Despite this, we do not see ourselves deprecating the CodeIgniter stack anytime soon. It is quite fast, reliable and incredibly easy to setup. NodeJS will serve as another choice when developing a server-side application – it will exist beside our tried and tested solution that is CodeIgniter.
Although this is the first in-depth dive into NodeJS, we have several tutorials using NodeJS stacks like using GCE to run a NodeJS app.
Easier ExpressJS development
By default, updating application files will not update the server during ExpressJS development. Therefore, we need to manually start and stop the server. To prevent this, we can use a tool called nodemon. Servers started with nodemon will automatically reload files as they are being saved.
Next, we will look at how we can install nodemon. It is quite easy:
npm install -g nodemon
Adding nodemon is not compulsory. However, it is an incredible time saver!
ExpressJS file structure
ExpressJS does not enforce a strict directory structure. Therefore, we have total freedom over file management. Firstly, we will use the express-generator tool to setup an ExpressJS project.
npx express-generator -h npx express-generator --view=hbs --git ej-server
This creates a folder called ej-server which has a directory structure similar to the one shown below
Next, we need to download the dependencies (which will create a node_modules folder).
cd ej-server npm install nodemon bin/www
The advantage of this method is that it sets up some default behaviour out of the box:
- Adds support for a public directory where static resources can be stored. The generated boilerplate already has support for serving these static files!
- Two sample routes (/ route and a /users route) along with route handling
- Handlebars-based templating system
An advantage of our previous CodeIgniter stack was that API calls and the backend UI could be handled on the same repository. We will add similar functionality for the ExpressJS stack as well.
Now that we have created our stack and files, let’s look at a way to deploy the ExpressJS application.
Deploy ExpressJS app on cPanel
Most cPanel-based shared hosting services also let advanced users serve NodeJS apps. We will look into how this can be done.
If your cPanel account supports this feature, you will see an icon like this:
Click on the “Create Application” button to create a new NodeJS application. You will be greeted with a form similar to the one shown below:
This feature does not provide a file uploader. You have to manually upload the NodeJS files using FTP or GIT. This location is the one you have to specify in the ‘Application root’ property.
Serve a public folder
Since this application will also serve HTML pages, the pages need to be able to access static content like CSS and JS. ExpressJS has a built in function to facilitate this:
Serve as a subfolder
When it comes to serving on a production server, you have to serve as a child URL of the top-level domain. For example, if the domain is example.org, the application will have to be served from example.org/app. This is a production-specific problem. The best way to go about this is to have redesign the routing hierarchy – a parent route will take care of handling requests to the subfolder, i.e. /app. All requests to this subfolder will be routed to child routes of the parent. This method is detailed in this article.
What should be remembered is that if you opt to go with this method, the public folder will also be served as a sub-route of /app. Therefore, to access a CSS in the public folder from an HTML file, you will have to load the resource from /app/stylesheets/style.css instead of stylesheets/style.css
cPanel uses an application called Phusion Passenger to serve NodeJS applications. It uses something called reversed port binding to serve the NodeJS app. An in-depth look at this method and its consequences is available on https://www.phusionpassenger.com/library/indepth/nodejs/reverse_port_binding.html
An implication of this architecture is that the NodeJS application can have only one createServer().listen() otherwise Passenger gets confused. NodeJS applications served this way cannot specify their port. Passenger ignores any specified ports. Instead, it listens on a random Unix domain socket.
Another common mistake is specifying app.js as the application startup file. This property should always mention the script that calls the initial createServer().listen()