Categories
Node.js Best Practices

Node.js Best Practices — Express Apps

Spread the love

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 Gzip Compression

We should use gzip compression to compress our assets.

This way, the user needs to download less data to their computers.

We can do that with the compression middleware with Express:

const compression = require('compression')
const express = require('express')
const app = express()
app.use(compression())

For high traffic sites, we should enable gzip compression in our reverse proxy.

Don’t Use Synchronous Functions

Synchronous functions are definitely a bad idea for many parts of the app.

Any potentially long-running code should be async.

This way, they won’t block the rest of the app from running’

Synchronous calls can add up and slow down our app significantly.

We can use the --trace-sync-io command-line flag to print warnings and a stack trace whenever synchronous code is run.

This is useful for tracing synchronous code in the development environment.

Do Logging Correctly

To do logging correctly, we should use better loggers than console.log or console.error .

Some libraries like Winston can help with logging.

It has much better features than the console methods.

The debug module is useful for logging messages for debugging.

We can enable debugging with it with the DEBUG environment variable.

Handle Exceptions Properly

We can handle exceptions with try-catch or catch with promises.

Also, we should ensure our app automatically restarts when an unhandled error is encountered.

The best way is to avoid our app crashing.

What we shouldn’t do is to listen to the uncaughtException event.

It’s emitted when an exception bubbles all the way back to the event loop.

Adding an event listener to the uncaughtException event will change the default behavior of the process than encounters the exception.

The process will continue to run despite the exception.

Then the state of the process becomes unreliable and unpredictable because of this.

We can use try-catch with synchronous code:

app.get('/search', function(req, res) {
  const jsonStr = req.query.params
  try {
    const jsonObj = JSON.parse(jsonStr)
    res.send('Success')
  } catch (e) {
    res.status(400).send('Invalid JSON')
  }
})

We can call catch with promises:

app.get('/', function (req, res, next) {
  queryDb()
    .then((data)  => {
      // ...
      return makeCsv(data)
    })
    .then(function (csv) {
      // ...
    })
    .catch(next)
})

app.use(function (err, req, res, next) {
  // handle error
})

We have next in catch which is called when an error occurs.

This will call the middleware below it.

Set NODE_ENV to “production”

We should set NODE_ENV to production so that Express cache view templates, cache CSS files, and generate less verbose warnings.

These changes will make the app speed up by a factor of 3.

Ensure Our App Automatically Restarts

Our app should automatically restart when an error occurs.

This way, it won’t go offline when it crashes.

We can do this with a process manager.

It would restart the app when the Node app crashes.

The init system provided by our OS may restart the process without a process manager.

Conclusion

We should make some basic changes like gzip compression, ensure automatic restart, and catch errors.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *