Matthew Phillips
Matthew Phillips

Reputation: 112

Use different versions of NPM dependencies based on engine

I need to specify a different version of a dependency based on the Node engine. Something like this:

{
  "node": {
    "0.10.x": {
      "zombie": "2.5.1"
    },
    "0.12.x": {
      "zombie": "^3.5.0"
    }
  },
  "iojs": {
    "^3.0.0": {
      "zombie": "^4.0.0"
    }
  }
}

Is this either built-in or is there a module which enables this sort of thing?

Upvotes: 4

Views: 883

Answers (1)

Matthew Bakaitis
Matthew Bakaitis

Reputation: 11990

"Yes, but..."

Not built-in, but possible.

Wise to do? ...

:)

// simplifying for the answer, only looking at node versions...

var npm = require("npm");
var semver = require("semver");

if (semver.satisfies(process.version, "0.12.x")){
    npm.load(null, function(){
        installPkg("chalk", "0.5.1");
    })
}

function installPkg(pkg, ver) {
    if(require.resolve(pkg)){
        throw Error("package already installed");
    }
    var semverPkg = pkg + "@" + ver;
    npm.commands.install([semverPkg], function (err, result) {
        if (err) console.log("error loading chalk");
    });
}

Using NPM programatically is a little frustrating because it is not well documented. Semver is super cool when somebody else has done all the work for you, but building the compares/satisfies checks is tedious work.

Also, doing it this way, you probably don't want to try to install every time so you'd now also have to do some kind of startup check to be sure you aren't slowing down your app restart time as it re-installs every package every time..

You could work around that by checking for modules. There are a few ways to handle this one, if you decide to continue down this path.

First, you can use require.resolve() in a heavy-handed way to see if a module is present. (That's what's in the example above.)

Second, you can also use npm.commands.ls which may look a little like this:

if (semver.satisfies(process.version, "0.12.x")){
    npm.load(null, function(){
        npm.commands.ls([], function(err, data,lite){
            // parse the results from ls here, and install or not, etc...
            console.log(lite);
        });
    })
}

So yeah...this isn't technically a solution to the problem because the problem is broad. (Not fishing to get you to accept, just explaining that I feel your pain and have been down a similar road, which is why I previously explored semver and npm in detail.)

The painful bits:

  • parsing with semver is "fun"
  • maintaining a manifest of modules by node version is "fun"
  • using npm programatically is "fun"

Vs:

  • maintain a few different package.json versions
  • write some "DevOps" scripts to handle env-specific installs for you (grunt-node-version?)
  • spend less time looking at source code for npm, semver, etc...

Upvotes: 2

Related Questions