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.
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.
Uncaught TypeError: Property description must be an object: undefined app.js:66355
.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
Turns out that our
package.json listed the following:
^ 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.
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
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
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!