Rush StackShopBlogEvents
Skip to main content

优先版本

背景

Rush 通过在公共文件夹下创建了一个虚假的 rush-common 项目来实现一次性安装,该项目引用了每个项目的。例如,假设 rush.json 内有两个项目 "project1" 和 "project2"。生成的文件可能如下:

common/temp/package.json

{
"name": "rush-common",
"description": "Temporary file generated by the Rush tool",
"private": true,
"version": "0.0.0",
"dependencies": {
"@rush-temp/project1": "file:./projects/project-1.tgz",
"@rush-temp/project2": "file:./projects/project-2.tgz"
}
}

包管理器认为每个以 "@rush-temp" 命名的项目都是 rush-common 项目的直接依赖。通常而言,NPM 会首先安装项目的直接依赖(在 node_modules 树的根目录),然后再下载间接依赖。但是,由于你的项目的直接依赖现在已经间接依赖 rush-common 项目了,所以 npm install 的行为可能有些不同。

假如 project-1/package.json 如下:

{
"name": "project-1",
"version": "1.0.0",
"dependencies": {
"library-a": "1.0.1",
"library-b": "1.1.3"
}
}

接着假设 library-a (来自于互联网)如下:

{
"name": "library-a",
"version": "1.0.1",
"dependencies": {
"library-b": "^1.0.0"
}
}

如果你在 project-1 下执行 npm install, 你会得到一个如下所示的 node_modules 文件夹,甚至如果 library-b@1.4.4 在 NPM 上有版本的话:

node_modules/
library-a/ (1.0.1)
library-b/ (1.1.3)

尽管 library-b@1.4.4 满足 "1.0.0" 的语义化版本,但是 NPM 不会下载它,因此 1.1.3(被 project-1 安装)已经满足它。

但是 common/temp/package.json 并不能保证上述行为。相反,由于 project-2 的依赖,你可能会得到这样的结果:

node_modules/
project-1/
library-b/ (1.1.3)
library-a/ (1.0.1)
library-b/ (1.4.4)

这也是语义化版本的一个有效解决方案。当使用 Rush 和 NPM 的 peer dependencies 时,可能会出现相似的问题。

优先的版本

为了控制上述影响,Rush 引入了“优先版本”的概念,这些依赖会被显式的添加到 common/temp/package.json 顶层。

你可以通过配置文件 common-versions.json 来“固定”版本,例如:

common/config/rush/common-versions.json

{
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/common-versions.schema.json",
"preferredVersions": {
"css-loader": "1.2.3"
}
}

这将会导致 css-loader 添加到 common/temp/package.json 中,如下所示:

{
"name": "rush-common",
"description": "Temporary file generated by the Rush tool",
"private": true,
"version": "0.0.0",
"dependencies": {
"css-loader": "1.2.3",
"@rush-temp/project1": "file:./projects/project-1.tgz",
"@rush-temp/project2": "file:./projects/project-2.tgz"
}
}

注意:如果你发布一个包,当你添加优先版本时候应当非常小心,因为这可能会产生一个与普通用户通过 NPM 安装你的库的不同结果。

隐性的优先版本

默认情况下,Rush 会自动将你的所有项目的直接依赖添加到 common/temp/package.json 中。在上面的例子中,这些“隐性的优先版本”可能会像这样:

common/temp/package.json

{
"name": "rush-common",
"description": "Temporary file generated by the Rush tool",
"private": true,
"version": "0.0.0",
"dependencies": {
"css-loader": "1.2.3", // <---- 明确制定的优先版本
"library-a": "~1.0.0", // <---- 隐形的优先版本
"library-b": "1.1.3", // <---- 隐形的优先版本
"@rush-temp/project1": "file:./projects/project-1.tgz",
"@rush-temp/project2": "file:./projects/project-2.tgz",
}
}

对于某个依赖而言,除了在不同的项目中指定不同的版本范围外,Rush 会自动将所有的直接依赖添加到 common/temp/package.json 中。在上述示例中,Rush 不知道哪个版本应当被认为是隐性的优先。例如,如果 project1project2 指定了不同的 library-b 版本,之后你可能需要使用 common-version.json 来解决问题。

对于较老的包管理器,自动添加这个这些条目会减少间接依赖的重复。然而,隐性的优先版本可能会导致某些不兼容 peerDependencies 范围的依赖出现问题。如果你遇到了同级依赖而导致的安装错误,建议通过设定 [common/config/rush/common-version.json] 中的 implicitlyPreferredVersionsfalse 来禁用这个行为。