This is a short postmortem regarding an issue we found this morning on a production NodeJS application at SoundHound. The application hasn’t launched yet, so I can’t disclose it, but the lesson we learned is applicable to all NodeJS apps that run on remote servers.

Background

We use Browserify to generate a bundled app.js file consisting of all the modules that we are using on the client. This generally includes React components, Flux Stores/Actions, and other utilities such as UnderscoreJS.

We noticed this morning that one of our production Node Apps was throwing JavaScript errors when rendering React components. Here was the error:

Uncaught TypeError: Property description must be an object: undefined app.js:66355

Normally, a JavaScript error is usually our fault, but it turns out that the line in question was within the .extend() method within UnderscoreJS. Oddly, the issue was not happening locally or on our staging server. It was only happening on production. A little debugging showed that the production website was using UnderscoreJS@1.8.2, while the staging website and our local versions were on UnderscoreJS@1.7.0.

Turns out that our package.json listed the following:

"underscore": “^1.7.0”

Where the ^ means “Compatible with version”. As we hadn’t run npm install locally or on the staging server for a while, those two servers had Underscore@1.7.0. We had recently run npm install on our production server, and it got Underscore@1.8.2. Turns out that Underscore@1.8.0 fixed an issue with extend() that broke what we were doing.

Solution

The solution that we decided to go with was to run npm shrinkwrap locally. This command generates a JSON file based on the contents of your node_modules directory. If you run npm install on a project that has npm-shrinkwrap.json, npm will use the shrink-wrap JSON to drive installation instead of looking at package.json. This is a good way to make sure that the dependencies on your remote servers are exactly the same as your local dependencies.

If you ever wish to update a local dependency, you can run `npm update <module> and then run npm shrinkwrap again to generate a new npm-shrinkwrap.json.

Once we generated the npm-shrinkwrap.json, we just removed node_modules from the production server, ran npm install, and saw that the production server was now using Underscore@1.7.0 instead of Underscore@1.8.2, which solved the issue.

More importantly, we ensured that such an issue would not occur again, since our development dependencies will be replicated on our staging and production environments.

Moral of the story

Use npm shrinkwrap when you are pushing code to remote servers, so you know what your dependencies are.

If you have any tips on how to make NodeJS deployments easier, add them in the comments below!

2 Comments

Cancel

  1. Why not instead add these changes “$npm config set save=true
    $ npm config set save-exact=true, to your .npmrc file?