Like any kind of apps, JavaScript apps also have to be written well.
Otherwise, we run into all kinds of issues later on.
In this article, we’ll look at some best practices we should follow when writing Node apps.
Use npm Scripts
We can use NPM scripts to put our scripts for builds, tests, and starting the app.
This way, we can type less to do all those tasks as we put them all in one command.
We put our scripts in package.json
to make our lives easier.
So we can put:
"scripts": {
"preinstall": "node preinstall.js",
"postintall": "node postintall.js",
"build": "webpack",
"postbuild": "node index.js",
"postversion": "npm publish"
}
in our file so that we can run them with npm run preinstall
, npm run postinstall
, etc.
If we need to run multiple commands, we can use &&
.
Command-line tools like Webpack, Nodemon, etc. should be run as local dev dependencies to avoid conflicts.
Use Env Vars
We should make our app configurable so that we can run them in any environment.
We can set them in various places, including the command to start our app:
NODE_ENV=production MONGO_URL=mongo://localhost:27017 nodemon index.js
or in Nodemon’s own config, which is nodemon.json
:
{
"env": {
"NODE_ENV": "production",
"MONGO_URL": "mongo://localhost:27017/accounts"
}
}
Just remember not to check in any secrets for our app.
Event Loop
If we need to perform long-running tasks, then we need to queue them in the event loop.
There’re various ways to do this.
setImmediate
and setTimeout
both run in the next event loop cycle.
nextTick
works on the same cycle.
Use Class Inheritance
The class syntax makes inheritance easier with the extends
keyword.
It makes sure that we call the parent constructor and lets us inherit things without working with prototypes directly.
Even though the class syntax is syntactic sugar for prototypes, it makes our lives easier.
Name Things Appropriately
We should name things appropriately so that we don’t have to explain the meaning of them to people.
So instead of writing:
const foo = require('morgan')
// ...
app.use(foo('dev'))
We write:
const logger = require('morgan')
// ...
app.use(logger('dev'))
Using JavaScript?
We can use extensions to JavaScript like TypeScript to make our lives easier.
They often let us restrict data types in various ways that JavaScript can’t do.
TypeScript also provides other handy features like interfaces and type aliases to restrict the structure of our objects.
It also has type guards to infer types.
The TypeScript compiler can compile to JavaScript versions as early as ES3.
It should serve anyone’s needs.
Express Middleware
Express middleware lets us make our Express app modular.
Many Express add-ons are available as middleware.
They include things like body-parser for parsing request bodies and many more.
Routes are also middlewares.
They let us build our Express app easily.
Therefore, we should know how to create and use them.
Scale Up
We rely on async code in Node so that we run code that doesn’t block other parts from running.
It only has one thread so we can’t run anything else until that piece of code is done.
To use more than one core of a processor, we’ve to create a cluster.
PM2 is a simple process manager that lets us create clusters easily.
We run:
npm i -g pm2
to install it.
Then we run:
pm2 start server.js -i 4
to run server.js
with 4 instances with each instance running on its own core.
There’s also pm2-docker
for Dockerized apps.
We can put:
# ...
RUN npm install pm2 -g
CMD ["pm2-docker", "app.js"]
in our Dockerfile to run it.
Conclusion
We can scale up with process managers and some handy tricks would help us with developing easier.