how to install multiple versions of package using

2019-03-09 11:46发布

问题:

Due to https://github.com/npm/npm/issues/2943, npm will never support the ability to alias packages and install multiple versions of the same package.

The workarounds posted on the github issue might work for pure-JS modules, but as npm becomes a standard for frontend package management, packages now include various assets such as CSS.

Is there any workaround to install multiple versions of the same package?

The best idea I've come up with is to "clone" a package, and publish it with a slightly different name.

For example, if you need multiple versions of jquery, you could just publish packages called jquery-alias1, jquery-alias2, jquery-alias3 etc, and then set the appropriate versions in your package.json.

Or you could name the packages according to their version number, eg jquery-1.11.x, jquery-2.1.x, etc..

Both of these approaches seem sloppy though. Are there better ones?

回答1:

I wanted to post here for anyone like me that is using Yarn and landed here. It is a more or less drop-in replacement for NPM that supports aliasing out of the box:

yarn add material-ui@latest
yarn add material-ui-next@npm:material-ui@next
then

import FlatButton from 'material-ui/FlatButton'; // v0.x
import Button from 'material-ui-next/Button'; // v1.x

(credit for example goes to https://github.com/callemall/material-ui/issues/7195#issuecomment-314547601 )



回答2:

It sounds like "JSPM" might be exactly the tool you're looking for. JSPM builds on top of NPM but allows you to pull packages from multiple sources (github, npm, etc). It uses the System.js universal module loader on the front end for loading modules, and "uses flat version management to download into version-suffixed folders" that are easy to reason about.

jspm.io

When you install a package with jspm you can alias that package to a particular name, which you can later require specifically in your modules.

$ jspm install jquery
... (status msgs) ...
ok   Installed jquery as github:components/jquery@^2.1.4 (2.1.4)

$ jspm install jqueryOne=jquery@1.11.3
... (status msgs) ...
ok   Installed jqueryOne as github:components/jquery@1.11.3 (1.11.3)

      github:components/jquery 1.11.3 2.1.4

Then in your js, you can simply require(jquery) and/or require(jqueryOne) as necessary, allowing you to go back and forth as necessary.

This goes the same for any package which you'd like to use multiple versions of.



回答3:

This is quite difficult to do cleanly, due to the way npm works, so I would avoid attempting to do it in production.

However, for integration testing and similar use cases, I created a package called multidep, which lets you install multiple versions of the same package and require them like so:

var multidepPackages = require('multidep')('test/multidep.json');

var jquery1 = multidepRequire('jquery', '1.11.3');
var jquery2 = multidepRequire('jquery', '2.1.4');


回答4:

NPM Install Version (https://github.com/scott113341/npm-install-version) is also an option. It essentially does what some of the other solutions here do (technically-speaking) but is quite straightforward to use. Modules installed with a version number (standard @version command param used by NPM) are predictably installed in a sub-folder under node_modules with that name. You can also control the destination dir per module - which is useful with build systems.

Usage code snippet from the GitHub Docs:

const niv = require('npm-install-version');
const benchmark = require('./some-benchmark-function.js');

niv.install('csjs@1.0.0');
// installs csjs@1.0.0 to node_modules/csjs@1.0.0/

niv.install('csjs@1.0.1');
// installs csjs@1.0.1 to node_modules/csjs@1.0.1/

const csjs_old = niv.require('csjs@1.0.0');
const csjs_new = niv.require('csjs@1.0.1');
// require the old and new versions of csjs

benchmark([csjs_old, csjs_new], 'some-test-input');
// run our fake benchmark function on the old and new versions of csjs


回答5:

install-npm-version (https://github.com/scott-lin/install-npm-version) is yet another option. It can be used on the command line, or through a programmatic interface -- written in TypeScript for modern development.

Example #1: Install to versioned (default) directory

import inv = require('install-npm-version');

inv.Install('chalk@2.4.0');
// installs chalk@2.4.0 to node_modules/chalk@2.4.0/

inv.Install('chalk@2.4.1');
// installs chalk@2.4.1 to node_modules/chalk@2.4.1/

Example #2: Install to custom directory

import inv = require('install-npm-version');

inv.Install('chalk@2.4.0', { 'Destination': 'some/path/chalk' });
// installs chalk@2.4.0 to node_modules/some/path/chalk/

Example #3: Install with silent or noisy standard output

import inv = require('install-npm-version');

inv.Install('chalk@2.4.0', { 'Verbosity': 'Silent' });
inv.Install('chalk@2.4.0', { 'Verbosity': 'Debug' });

Example #4: Overwrite an existing installation

import inv = require('install-npm-version');

inv.Install('chalk@2.4.0', { 'Destination': 'mydir' });
// installs chalk@2.4.0 to node_modules/mydir/

inv.Install('chalk@2.4.1', { 'Destination': 'mydir' });
// does not install chalk@2.4.1 since node_modules/mydir/ already exists

inv.Install('chalk@2.4.1', { 'Destination': 'mydir', 'Overwrite': true });
// installs chalk@2.4.1 to node_modules/mydir/ by overwriting existing install