如何使用npm安装软件包的多个版本

how to install multiple versions of package using npm

由于https://github.com/npm/npm/issues/2943,npm将永远不支持对软件包进行别名并安装同一软件包的多个版本的功能。

github问题上发布的变通办法可能适用于纯JS模块,但是随着npm成为前端软件包管理的标准,软件包现在包括各种资产,例如CSS。

有没有解决办法来安装同一软件包的多个版本?

我想出的最好的主意是"克隆"一个程序包,并以稍微不同的名称发布它。

例如,如果需要多个版本的jquery,则可以只发布名为jquery-alias1jquery-alias2jquery-alias3等的软件包,然后在package.json中设置适当的版本。

或者,您可以根据软件包的版本号命名它们,例如jquery-1.11.xjquery-2.1.x等。

不过,这两种方法似乎都是草率的。 有更好的吗?


从npm v6.9.0开始,npm现在支持软件包别名。它实现了与Yarn相同的语法:

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

这会将以下内容添加到package.json

1
2
3
4
"dependencies": {
  "jquery2":"npm:jquery@^2.2.4",
  "jquery3":"npm:jquery@^3.4.1"
}

也可以使用这种语法直接从GitHub安装。例如,如果要同时安装npm注册表版本和软件包foobar的GitHub分支,请执行以下操作:

1
2
npm install foobar
npm install foobar-fork@github:username/foobar


我想在这里发布信息给像我这样使用Yarn并降落在这里的任何人。它或多或少是NPM的直接替代品,支持开箱即用的别名:

1
2
3
4
5
6
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

(例如,贷方转到https://github.com/callemall/material-ui/issues/7195#issuecomment-314547601)


听起来" JSPM"可能正是您要寻找的工具。 JSPM建立在NPM之上,但允许您从多个来源(github,npm等)提取软件包。它使用前端的System.js通用模块加载器来加载模块,并"使用平面版本管理将其下载到带有版本后缀的文件夹中",这很容易理解。

jspm.io

使用jspm安装软件包时,可以将该软件包别名为特定名称,以后可以在模块中专门require对其命名。

1
2
3
4
5
6
7
8
9
$ jspm install jquery
... (status msgs) ...
ok   Installed jquery as github:components/jquery@^2.1.4 (2.1.4)

$ jspm install [email protected]
... (status msgs) ...
ok   Installed jqueryOne as github:components/[email protected] (1.11.3)

      github:components/jquery 1.11.3 2.1.4

然后在您的js中,您可以根据需要简单地require(jquery)和/或require(jqueryOne),允许您根据需要来回移动。

对于要使用其多个版本的任何软件包,这都是相同的。


由于npm的工作方式,很难做到干净整洁,所以我会避免尝试在生产中进行。

但是,对于集成测试和类似的用例,我创建了一个名为multidep的软件包,该软件包可让您安装同一软件包的多个版本,并像这样require安装它们:

1
2
3
4
var multidepPackages = require('multidep')('test/multidep.json');

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

就我而言,我需要安装一个比全局安装的版本更旧的create-react-app,因为我上的课程要求使用该较旧的版本进行作业。

我创建了一个新文件夹以包含此较旧的版本,将其cd入其中,然后执行了

1
npm init

设置完该shell package.json之后,我安装了所需的确切版本的create-react-app

1
npm install [email protected]

它使用旧版本的create-react-app创建了一个本地node_modules文件夹。

然后,我创建了一个简单的bash脚本(create-react-app.sh)作为该旧版本的快捷方式,并使用了bash
变量" $ @"以转发所有参数:

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

最后,我使这个简单的bash脚本可执行

1
chmod u+x create-react-app.sh

因此,直接运行此bash脚本将执行旧版本的create-react-app:

1
2
./create-react-app.sh  --version
1.5.2

install-npm-version(https://github.com/scott-lin/install-npm-version)是另一种选择。它可以在命令行上使用,也可以通过编程接口使用-用TypeScript编写的用于现代开发。

示例#1:安装到版本化(默认)目录

1
2
3
4
5
6
7
import inv = require('install-npm-version');

inv.Install('[email protected]');
// installs [email protected] to node_modules/[email protected]/

inv.Install('[email protected]');
// installs [email protected] to node_modules/[email protected]/

示例2:安装到自定义目录

1
2
3
4
import inv = require('install-npm-version');

inv.Install('[email protected]', { 'Destination': 'some/path/chalk' });
// installs [email protected] to node_modules/some/path/chalk/

示例3:使用无声或嘈杂的标准输出进行安装

1
2
3
4
import inv = require('install-npm-version');

inv.Install('[email protected]', { 'Verbosity': 'Silent' });
inv.Install('[email protected]', { 'Verbosity': 'Debug' });

示例#4:覆盖现有安装

1
2
3
4
5
6
7
8
9
10
import inv = require('install-npm-version');

inv.Install('[email protected]', { 'Destination': 'mydir' });
// installs [email protected] to node_modules/mydir/

inv.Install('[email protected]', { 'Destination': 'mydir' });
// does not install [email protected] since node_modules/mydir/ already exists

inv.Install('[email protected]', { 'Destination': 'mydir', 'Overwrite': true });
// installs [email protected] to node_modules/mydir/ by overwriting existing install

也可以选择NPM安装版本(https://github.com/scott113341/npm-install-version)。它实际上完成了此处其他一些解决方案的工作(在技术上讲),但是使用起来非常简单。可预见的是,安装了版本号(NPM使用的标准@version命令参数)的模块可以安装在具有该名称的node_modules下的子文件夹中。您还可以控制每个模块的目标目录-这对于构建系统很有用。

GitHub Docs的使用代码片段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const niv = require('npm-install-version');
const benchmark = require('./some-benchmark-function.js');

niv.install('[email protected]');
// installs [email protected] to node_modules/[email protected]/

niv.install('[email protected]');
// installs [email protected] to node_modules/[email protected]/

const csjs_old = niv.require('[email protected]');
const csjs_new = niv.require('[email protected]');
// 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