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 Node’s Built-in Profiler
Node comes with its own profiler to let us watch the performance of our app.
To use it, we just add the --prof
option when we run our app:
node --prof app.js
Then we process our tick file that’s outputted from this by running:
node --prof-process isolate-0x???????-v8.log
And then we can read the tick file processing result.
There’s a [Summary]
section with the data that came from the profiling.
It consists of what kind of code is run like library and nonlibrary code.
It also shows what language the code is written in.
Use a Code Change Watcher to Automatically Restart Your Node App
To make developing Node apps easier, we should use a code change watcher.
With them, the app is restarted when we change our code files.
There are several packages that do that.
One of them is Nodemon.
We can install it by running:
npm install -g nodemon
Then we use nodemon
instead of node
to run our app.
Another package to do this is Forever.
We can install it by running:
npm install -g forever
Then we start our app by running:
forever start app.js
It has some options like appending logs to a file instead of stdout, saving the process ID to a file, etc.
Node-supervisor is another package we can use.
To install it, we run:
npm install -g supervisor
It has several options to change its behavior like not restarting on error, etc.
Properly Use Logging in Node.js
console.log
have a few problems.
Once we built our app, we’ve to remove them all to avoid polluting our log files.
Also, we have no options for filtering them.
A better alternative is to use the debug
module for logging.
To use it, we require it by writing:
const debug = require('debug')('my-app');
where 'my-app'
is our app name.
Then we can log things with the debug
function:
debug("hello world", someVar, someOtherVar);
We can pass in whatever we want to the function to log them.
To turn on debug messages when we run our app, we run:
DEBUG=my-app node app.js
The value for DEBUG
should match the name we passed in when we required it.
The name of the app instance can also be namespaced:
const debug = require("debug")("my-app:startup");
This lets us distinguish each level of debugging precisely.
So we can run:
DEBUG=my-app:startup node app.js
to log startup messages and:
DEBUG=my-app:* node app.js
to log all messages in the namespace.
Properly Use Promises
We should avoid creating new promise each time a request is made.
Instead, we can put it in a function and reuse it:
const axios = require('axios');
const makeRequest = (options) => {
return axios(options)
};
const getRequest = (url) => {
const options = {
method: "GET",
url
};
return makeRequest(options);
};
const getProfile = (profileId) => {
return getRequest(`/profile/${profileId}`);
};
We make a request Axios, which returns a promise.
This way, we can reuse the piece of generic request code for all requests.
Conclusion
We can profile our app with the built-in profiler.
Also, we can use packages to restart our app when code changes.
The debug
module is good for logging debug messages.
And we can create one common function that makes all HTTP requests.