Nodejitsu

Save time managing and deploying your node.js app. Code faster with jitsu and npm

Analyze node.js Dependencies like MAGIC

About the author

Name
Location
Worldwide
nodejitsu nodejitsu

Dependencies are the careful balance between modularity, reuse, and ease-of-use. When working with Nodejitsu (and node.js in general) dependencies are managed through the package.json dependencies property. Creating a package.json is an important step in node.js application comprehension. For more information on this checkout npm and our CLI tool jitsu, both of which will help you understand creating package.json files.

Making sure your package.json has all the right ingredients is important! Nodejitsu is happy to announce the release of a simple and elegant tool for determining and analyzing your dependencies, aptly named: require-analyzer. This post will walk you through how to use the library as well as outline our jitsu integration and upcoming npm integration.


Using require-analyzer

There are two distinct ways to use the require-analyzer library: from the command line or through code. The command line tool is designed to work with package.json files; make sure that you have created one for your project beforehand.

Lets take a look at how I used require-analyzer to analyze its own dependencies:

  $ require-analyzer
  info:  require-analyzer starting in /path/to/require-analyzer
  warn:  No dependencies found
  info:  Analyzing dependencies...
  info:  Done analyzing raw dependencies
  info:  Retrieved packages from npm
  info:  Additional dependencies found
  data:  {
  data:    async: '>= 0.1.8',
  data:    findit: '>= 0.0.3',
  data:    npm: '>= 0.3.18'
  data:  }
  info:  Updating /path/to/require-analyzer/package.json
  info:  require-analyzer updated package.json dependencies

If you're a power user (you know who you are) don't fret: the require-analyzer API is fully available through pure node.js code. The easiest way to use require-analyzer programmatically is through the .analyze() method. This method will use fs.stat() on the path supplied and attempt one of three options:

  1. If it is a directory that has a package.json, analyze require statements from package.main
  2. If it is a directory with no package.json analyze every .js or .coffee file in the directory tree
  3. If it is a file, then analyze require statements from that individual file.

Lets dive into a quick sample usage:

var analyzer = require('require-analyzer');

var options = {  
  target: 'path/to/your/dependency' // e.g /Users/some-user/your-package
  reduce: true
};

var deps = analyzer.analyze(options, function (err, pkgs) {  
  //
  // Log all packages that were discovered
  //
  console.dir(pkgs);
});

//
// The call the `.analyze()` returns an `EventEmitter` which outputs
// data at various stages of the analysis operation.
//
deps.on('dependencies', function (raw) {  
  //
  // Log the raw list of dependencies (no versions)
  //
  console.dir(raw);
});

deps.on('search', function (pkgs) {  
  //
  // Log the results from the npm search operation with the current
  // active version for each dependency
  //
  console.dir(pkgs);
});

deps.on('reduce', function (reduced) {  
  //
  // Logs the dependencies after they have been cross-referenced with 
  // sibling dependencies. 
  //
  // (e.g. if 'foo' requires 'bar', 'bar' will be removed).
  //
  console.dir(reduced);
});

Integration with jitsu

Our primary motivation for writing require-analyzer was to make deploying to Nodejitsu easier than ever. Our CLI tool, jitsu, will look inside your package.json for the scripts.start property, then analyze the require statements used by that script automagically for you before your application is even deployed to our platform. Simple. Friction-free. Awesome. Work get's done. Go home early.

Here's a sample of the output:

  info:   Analyzing your application dependencies in bin/server
  info:   Found new dependencies
  data:   {
  data:       colors: '>= 0.5.0',
  data:       http-proxy: '>= 0.5.0',
  data:       loggly: '>= 0.3.2',
  data:       node-static: '>= 0.5.3',
  data:       optimist: '>= 0.1.9',
  data:       request: '>= 1.9.5',
  data:       winston: '>= 0.2.7'
  data:   }
  warn:   New dependencies will be added for you automatically.

Roadmap

If you're curious how require-analyzer works it's relatively straight-forward: it finds a set of files to require, then spawns a child process which monkey patches Module._load() in node.js core to observe your require() statements (code anyone?). require-analyzer then parses that output and cross references the results with packages installed via npm.

This approach is more elegant than some static analysis approaches used in other attempts at this problem, but it is by no means a perfect approach. Lazy loading of dependencies or dependencies used in binary scripts are not captured by the default CLI tool. These are issues we look forward to improving upon in the coming weeks.

Another important point of interest for us is the integration with npm. The name for the library actually came out of a discussion with isaacs (author of npm; much respect), and we've come to see that there is some shared ground between jitsu and npm (especially in the npm init command).

Stay tuned for more big announcements leading up to and during NodeConf.