187

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?

VLAZ
  • 26,331
  • 9
  • 49
  • 67
mark
  • 4,678
  • 7
  • 36
  • 46
  • Isn't bower the standard in frontend package management which can [easily do this](http://stackoverflow.com/questions/16442012/bower-install-2-versions-of-jquery). – laggingreflex Oct 17 '14 at 01:55
  • Yes bower seems like an alternative here. It's too bad there doesn't seem to be an npm solution, as introducing another package management system to a large team can be difficult. Especially if you already have infrastructure set up to support npm (eg. a private npm registry server) – mark Oct 17 '14 at 18:12
  • Does this answer your question? [How to install with npm 2 different bootstrap version?](https://stackoverflow.com/questions/52125899/how-to-install-with-npm-2-different-bootstrap-version) – Julian Sep 07 '21 at 07:06

11 Answers11

258

npm supports package aliases as of v6.9.0. It implements the same syntax as Yarn:

npm install jquery2@npm:jquery@2
npm install jquery3@npm:jquery@3

This adds the following to package.json:

"dependencies": {
   "jquery2": "npm:jquery@^2.2.4",
   "jquery3": "npm:jquery@^3.4.1"
}

It is also possible to install directly from GitHub. For example, if you want to install both the npm registry version and a GitHub fork of the package foobar:

npm install foobar
npm install foobar-fork@github:username/foobar
Rens Baardman
  • 4,671
  • 4
  • 12
  • 12
  • 2
    yarn [also supports](https://yarnpkg.com/lang/en/docs/cli/add/#toc-yarn-add-alias) package aliasing – Greg K Sep 27 '19 at 10:49
  • Hi, I've tried these step to install 2 package is: "react-native-track-player": "1.1.4" and "react-native-track-player": "1.1.8". It work well on iOS, but on Android it show an error that "MusicManager$1 is defined multiple times". How can I prevent Android from building 1.1.8 ? – EmBeCoRau Jul 09 '20 at 06:34
  • Didn't work for me as alias of the dependancy differed to what it was looking for, i.e. it was looking for `eslint`, but didn't know it was now named `eslint6` – ckhatton Aug 12 '20 at 07:12
105

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 )

tmahle
  • 1,177
  • 1
  • 7
  • 4
  • 32
    Thank you. Just to clarify that the generic formula is `@npm:@` – katsos Sep 17 '18 at 14:13
  • Amazing. I tried to install `yarn add react-bootstrap4@npm:react-bootstrap@1.5.1`, but react webpacker complained it cannot find module `react-bootstrap4`. However, `yarn add react-bootstrap-next@npm:react-bootstrap@1.5.1` works as a charm – new2cpp Mar 03 '21 at 13:42
5

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.

JemBijoux
  • 104
  • 1
  • 5
4

In my case, I need to install a newer version 7 of react-table than the version I had installed i.e. react-table version 6 globally. So we were facing the problem for new development we need to use new version table without breaking old table functionality in application so I installed both the table with different key.

Ex.

  1. npm install react-table-7@npm:react-table@latest - new
  2. npm install react-table@npm:react-table@6.11.5 - old
Pang
  • 9,564
  • 146
  • 81
  • 122
Mayuri
  • 41
  • 1
3

I am not an expert in npm, but I had the following problem: two dependencies where competing for a version. I give the example, as for beginners it is hard to understand.

I have defined in package.json the following two dependencies:

"@ngtools/webpack": "^13.2.2",    
"angular-named-lazy-chunks-webpack-plugin": "^2.1.0",

they both demand a version of webpack, but a different one. They were competing. Your comments and solutions helped me, as I defined the following in devDependencies:

"webpack5": "npm:webpack@^5.68.0",
"webpack4": "npm:webpack@^4.46.0",

now, both "@ngtools/webpack" and "angular-named-lazy-chunks-webpack-plugin" are happy. The name webpack5 and webpack4 are random. I guess you can put whatever you like.

The error was:

npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: openpaas-ssp@0.0.0
npm ERR! Found: webpack@4.46.0
npm ERR! node_modules/webpack
npm ERR!   dev webpack@"^4.46.0" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer webpack@"^5.30.0" from @ngtools/webpack@13.2.2
npm ERR! node_modules/@ngtools/webpack
npm ERR!   dev @ngtools/webpack@"^13.2.2" from the root project

When I was setting the 5.30 for webpack, then "@ngtools/webpack" was satisfied, but I was getting the similar error from "angular-named-lazy-chunks-webpack-plugin"

Andreas Panagiotidis
  • 2,763
  • 35
  • 32
2

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');
Jo Liss
  • 30,333
  • 19
  • 121
  • 170
2

In my case, I needed to install an older version of create-react-app than the version I had installed globally, because I was taking a course that required this older version for the assignments.

I created a new folder just to contain this older version, cd'd into it, and did an

npm init

After setting up this shell package.json, I installed the exact version of create-react-app that I needed

npm install create-react-app@1.5.2

which created a local node_modules folder with the the older version of create-react-app.

Then I created a simple bash script (create-react-app.sh) as a shortcut to this older version, and used the bash variable "$@" to forward all arguments:

#!/bin/bash
{full-directory-path}/node_modules/create-react-app/index.js "$@"

Finally, I made this simple bash script executable

chmod u+x create-react-app.sh

So directly running this bash script will execute the older version of create-react-app:

./create-react-app.sh  --version
1.5.2
Stefan Musarra
  • 1,429
  • 14
  • 16
0

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
SylonZero
  • 1,207
  • 8
  • 9
0

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
Scott Lin
  • 1,532
  • 1
  • 18
  • 28
0

If trying to resolve conflicting peer dependencies after updating one package while another still relies on an old one, you can allow both to exist in different parts of your package tree:

npm install --legacy-peer-deps

Dave Skender
  • 611
  • 5
  • 11
0

from FrontEnd developer.

I just tried it, and its horrible idea, because:

other packages that depend on your installed packages do NOT account for package name changes.

E.g.

Consider: Chart.js with React-Chartjs-2

Sure you can install:

"react-chartjs-2-old": "npm:react-chartjs-2@^2.11.2",
"chart.js-old": "npm:chart.js@^2.9.4",

but you immediately get:

  • Node package error modules - because react-chartjs-2 is importing chart.js as a dependency and NOT chart.js-old
  • Webpack: looking for chart.js, NOT chart.js-old

Yes! Yes! ... You can go into node.modules and manually change all the dependency requirements.

It will work for a cute 'todo' list app where YouTuber is telling you 'its magic'... but in an enterprise team, there are rebuilds happening all the time and node.modules get deleted and reset everyday, sometimes every hour.

So you will have to manually go into node_modules and change them every-time they get reset.

And pushing 20gigs of node_modules onto Production, not sure if its viable.

As a result your full time job will become 'managing node module dependencies' as oppose to doing any sort of real dev work.

fruitloaf
  • 1,628
  • 15
  • 10