Two versions of same npm package in Node applicati

2019-03-12 13:36发布

问题:

I'm working on a CLI tool in NodeJS that uses another NodeJs package that we develop, which is an SDK.

The thing is, we just published a V2 version of that SDK, and we want to offer the CLI user a legacy mode, so they can use either the first or second version of our SDK, like so:

$ cli do-stuff
#execute sdk v2

Or

$ LEGACY_MODE='on' cli do-stuff
#execute sdk v1

My problem is that I did not found any clean way to use two versions of the same dependency in my CLI. I tried to use npm-install-version package. It works well on my local environment, but after publishing my cli and doing npm install -g my-cli, it doesn't work anymore, because it creates a node_modules folder in the current folder, instead of the /usr/local/lib/node_modules/my-cli folder. I also tried multidep, and I have kind of the same issue.

For now, my package.json do not contain at all my sdk, but I would like to have something like :

"dependencies": {
  "my-sdk": "2.0.0"
  "my-sdk-legacy": "1.0.0"
}

Or

"dependencies": {
  "my-sdk": ["2.0.0", "1.0.0"]
}

I haven't found anything else yet. I'm thinking about publishing the first version of my sdk package with another name, like "my-sdk-legacy", but I would like to avoid that if possible.

Any solution for that ?

回答1:

So this is actually a quite common scenario which was addressed several times.

There is a closed issue for npm and open issue for yarn package managers.


The first solution was suggested by the author of NPM in this GH comment:

Publish a separate package under a different name. It will require a specific version inside.

{ "name": "express3",
  "version": "1.0.0",
  "description":"Express version 3",
  "dependencies": { "express":"3" } }

// index.js
module.exports = require('express')

In your case you'll publish my-sdk-v1 and my-sdk-v2. And from now you can easily install 2 versions of a package in one project without running into conflicts.

const mySDKLegacy = require('my-sdk-v1');
const mySDKModern = require('my-sdk-v2');

The second way pretty much the same idea proposed - use git url:

{
    "my-sdk-v1": "git://github.com/user/my-sdk#1.0.0",
    "my-sdk-v2": "git://github.com/user/my-sdk#2.0.0"
}

Unlike npm package, you are free to choose any name you wish! The source of truth is the git url.

Later npm-install-version popped up. Buuut, as you already proved, its usage is a bit limited. Since it spawns a child process to execute some commands and writes to tmp dirs. Not the most reliable way for a CLI.

To sum up: you're left with choices 1 & 2. I'd stick with the first one, since the github repo name & tags could change.

2nd option with git url is better when you want to change a version to depend more frequently. Imagine you want to publish a security patch for my-sdk-v1 legacy. Will be easier to reference a git url then publish my-sdk-v1.1 to npm again and again.



回答2:

So to just add up to current solutions you can also provide packages like so:

yarn add my-sdk-newest@npm:my-sdk

or in package.json

{
  ...
  "my-sdk-newest": "npm:my-sdk",
  "my-sdk": "1.0.0"
  ...
}

if you only care about specific legacy version and the newest.