初识 peerDependencies

news2025/1/24 2:30:11

目录

初步认识 peerDependencies

semver 介绍

# 摘要

# 简介

# 语义化版本控制规范(SemVer)

# 合法语义化版本的巴科斯范式语法

# 为什么要使用语义化的版本控制?

# FAQ

示例讲解:vue-router 插件

# 说明

声明

验证


初步认识 peerDependencies

在某些情况下,你想表达你的包与宿主工具或库的兼容性,而不一定要做这个宿主的 require。这通常被称为插件。值得注意的是,您的模块可能会暴露主机文档所期望和指定的特定接口。

例如:

{
  "name": "tea-latte",
  "version": "1.3.5",
  "peerDependencies": {
    "tea": "2.x"
  }
}

这确保您的包 tea-latte 只能与主机包 tea 的第二个主要版本一起安装。npm install tea-latte 可能会产生以下依赖关系图

├── tea-latte@1.3.5
└── tea@2.2.0

在 npm 版本 3 到 6 中,peerDependencies 不会自动安装,如果在树中发现无效版本的对等依赖项,则会发出警告。从 npm v7 开始,默认安装 peerDependencies。

如果无法正确解析树,则尝试安装另一个具有冲突要求的插件可能会导致错误。出于这个原因,请确保您的插件要求尽可能广泛,而不是将其锁定到特定的补丁版本。

假设主机符合 semver,只有主机包主要版本的更改会破坏您的插件。因此,如果您使用过每个 1.x 版本的主机包,请使用 "^1.0""1.x" 来表达这一点。如果您依赖 1.5.2 中引入的功能,请使用 "^1.5.2"

semver 介绍

# 摘要

版本格式:主版本号.次版本号.修订号,版本号递增规则如下:

  1. 主版本号:当你做了不兼容的 API 修改,
  2. 次版本号:当你做了向下兼容的功能性新增,
  3. 修订号:当你做了向下兼容的问题修正。

先行版本号及版本编译信息可以加到“主版本号.次版本号.修订号”的后面,作为延伸。

# 简介

在软件管理的领域里存在着被称作“依赖地狱”的死亡之谷,系统规模越大,加入的包越多,你就越有可能在未来的某一天发现自己已深陷绝望之中。

在依赖高的系统中发布新版本包可能很快会成为噩梦。如果依赖关系过高,可能面临版本控制被锁死的风险(必须对每一个依赖包改版才能完成某次升级)。而如果依赖关系过于松散,又将无法避免版本的混乱(假设兼容于未来的多个版本已超出了合理数量)。当你项目的进展因为版本依赖被锁死或版本混乱变得不够简便和可靠,就意味着你正处于依赖地狱之中。

作为这个问题的解决方案之一,我提议用一组简单的规则及条件来约束版本号的配置和增长。这些规则是根据(但不局限于)已经被各种封闭、开放源码软件所广泛使用的惯例所设计。为了让这套理论运作,你必须先有定义好的公共 API。这可能包括文档或代码的强制要求。无论如何,这套 API 的清楚明了是十分重要的。一旦你定义了公共 API,你就可以透过修改相应的版本号来向大家说明你的修改。考虑使用这样的版本号格式:X.Y.Z(主版本号.次版本号.修订号)修复问题但不影响 API 时,递增修订号;API 保持向下兼容的新增及修改时,递增次版本号;进行不向下兼容的修改时,递增主版本号。

我称这套系统为“语义化的版本控制”,在这套约定下,版本号及其更新方式包含了相邻版本间的底层代码和修改内容的信息。

# 语义化版本控制规范(SemVer)

以下关键词 MUST、MUST NOT、REQUIRED、SHALL、SHALL NOT、SHOULD、SHOULD NOT、 RECOMMENDED、MAY、OPTIONAL 依照 RFC 2119 的叙述解读。

  1. 使用语义化版本控制的软件必须(MUST)定义公共 API。该 API 可以在代码中被定义或出现于严谨的文档内。无论何种形式都应该力求精确且完整。
  2. 标准的版本号必须(MUST)采用 X.Y.Z 的格式,其中 X、Y 和 Z 为非负的整数,且禁止(MUST NOT)在数字前方补零。X 是主版本号、Y 是次版本号、而 Z 为修订号。每个元素必须(MUST)以数值来递增。例如:1.9.1 -> 1.10.0 -> 1.11.0。
  3. 标记版本号的软件发行后,禁止(MUST NOT)改变该版本软件的内容。任何修改都必须(MUST)以新版本发行。
  4. 主版本号为零(0.y.z)的软件处于开发初始阶段,一切都可能随时被改变。这样的公共 API 不应该被视为稳定版。
  5. 1.0.0 的版本号用于界定公共 API 的形成。这一版本之后所有的版本号更新都基于公共 API 及其修改内容。
  6. 修订号 Z(x.y.Z | x > 0)必须(MUST)在只做了向下兼容的修正时才递增。这里的修正指的是针对不正确结果而进行的内部修改。
  7. 次版本号 Y(x.Y.z | x > 0)必须(MUST)在有向下兼容的新功能出现时递增。在任何公共 API 的功能被标记为弃用时也必须(MUST)递增。也可以(MAY)在内部程序有大量新功能或改进被加入时递增,其中可以(MAY)包括修订级别的改变。每当次版本号递增时,修订号必须(MUST)归零。
  8. 主版本号 X(X.y.z | X > 0)必须(MUST)在有任何不兼容的修改被加入公共 API 时递增。其中可以(MAY)包括次版本号及修订级别的改变。每当主版本号递增时,次版本号和修订号必须(MUST)归零。
  9. 先行版本号可以(MAY)被标注在修订版之后,先加上一个连接号再加上一连串以句点分隔的标识符来修饰。标识符必须(MUST)由 ASCII 字母数字和连接号 [0-9A-Za-z-] 组成,且禁止(MUST NOT)留白。数字型的标识符禁止(MUST NOT)在前方补零。先行版的优先级低于相关联的标准版本。被标上先行版本号则表示这个版本并非稳定而且可能无法满足预期的兼容性需求。范例:1.0.0-alpha、1.0.0-alpha.1、1.0.0-0.3.7、1.0.0-x.7.z.92。
  10. 版本编译信息可以(MAY)被标注在修订版或先行版本号之后,先加上一个加号再加上一连串以句点分隔的标识符来修饰。标识符必须(MUST)由 ASCII 字母数字和连接号 [0-9A-Za-z-] 组成,且禁止(MUST NOT)留白。当判断版本的优先层级时,版本编译信息可(SHOULD)被忽略。因此当两个版本只有在版本编译信息有差别时,属于相同的优先层级。范例:1.0.0-alpha+001、1.0.0+20130313144700、1.0.0-beta+exp.sha.5114f85。
  11. 版本的优先层级指的是不同版本在排序时如何比较。

                1、判断优先层级时,必须(MUST)把版本依序拆分为主版本号、次版本号、修订号及先行版本号后进行比较(版本编译信息不在这份比较的列表中)。

                2、由左到右依序比较每个标识符,第一个差异值用来决定优先层级:主版本号、次版本号及修订号以数值比较。

                        例如:1.0.0 < 2.0.0 < 2.1.0 < 2.1.1。

                3、当主版本号、次版本号及修订号都相同时,改以优先层级比较低的先行版本号决定。

                        例如:1.0.0-alpha < 1.0.0。

                4、有相同主版本号、次版本号及修订号的两个先行版本号,其优先层级必须(MUST)透过由左到右的每个被句点分隔的标识符来比较,直到找到一个差异值后决定:

                        a. 只有数字的标识符以数值高低比较。

                        b. 有字母或连接号时则逐字以 ASCII 的排序来比较。

                        c. 数字的标识符比非数字的标识符优先层级低。

                        d. 若开头的标识符都相同时,栏位比较多的先行版本号优先层级比较高。

                        例如:1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 <                         1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0。

# 合法语义化版本的巴科斯范式语法

<valid semver> ::= <version core>
                 | <version core> "-" <pre-release>
                 | <version core> "+" <build>
                 | <version core> "-" <pre-release> "+" <build>

<version core> ::= <major> "." <minor> "." <patch>

<major> ::= <numeric identifier>

<minor> ::= <numeric identifier>

<patch> ::= <numeric identifier>

<pre-release> ::= <dot-separated pre-release identifiers>

<dot-separated pre-release identifiers> ::= <pre-release identifier>
                                          | <pre-release identifier> "." <dot-separated pre-release identifiers>

<build> ::= <dot-separated build identifiers>

<dot-separated build identifiers> ::= <build identifier>
                                    | <build identifier> "." <dot-separated build identifiers>

<pre-release identifier> ::= <alphanumeric identifier>
                           | <numeric identifier>

<build identifier> ::= <alphanumeric identifier>
                     | <digits>

<alphanumeric identifier> ::= <non-digit>
                            | <non-digit> <identifier characters>
                            | <identifier characters> <non-digit>
                            | <identifier characters> <non-digit> <identifier characters>

<numeric identifier> ::= "0"
                       | <positive digit>
                       | <positive digit> <digits>

<identifier characters> ::= <identifier character>
                          | <identifier character> <identifier characters>

<identifier character> ::= <digit>
                         | <non-digit>

<non-digit> ::= <letter>
              | "-"

<digits> ::= <digit>
           | <digit> <digits>

<digit> ::= "0"
          | <positive digit>

<positive digit> ::= "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"

<letter> ::= "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J"
           | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T"
           | "U" | "V" | "W" | "X" | "Y" | "Z" | "a" | "b" | "c" | "d"
           | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n"
           | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x"
           | "y" | "z"


# 为什么要使用语义化的版本控制?

这并不是一个新的或者革命性的想法。实际上,你可能已经在做一些近似的事情了。问题在于只是“近似”还不够。如果没有某个正式的规范可循,版本号对于依赖的管理并无实质意义。将上述的想法命名并给予清楚的定义,让你对软件使用者传达意向变得容易。一旦这些意向变得清楚,弹性(但又不会太弹性)的依赖规范就能达成。

举个简单的例子就可以展示语义化的版本控制如何让依赖地狱成为过去。假设有个名为“救火车”的函数库,它需要另一个名为“梯子”并已经有使用语义化版本控制的包。当救火车创建时,梯子的版本号为 3.1.0。因为救火车使用了一些版本 3.1.0 所新增的功能,你可以放心地指定依赖于梯子的版本号大于等于 3.1.0 但小于 4.0.0。这样,当梯子版本 3.1.1 和 3.2.0 发布时,你可以将直接它们纳入你的包管理系统,因为它们能与原有依赖的软件兼容。

作为一位负责任的开发者,你理当确保每次包升级的运作与版本号的表述一致。现实世界是复杂的,我们除了提高警觉外能做的不多。你所能做的就是让语义化的版本控制为你提供一个健全的方式来发行以及升级包,而无需推出新的依赖包,节省你的时间及烦恼。

如果你对此认同,希望立即开始使用语义化版本控制,你只需声明你的函数库正在使用它并遵循这些规则就可以了。请在你的 README 文件中保留此页链接,让别人也知道这些规则并从中受益。

# FAQ

在 0.y.z 初始开发阶段,我该如何进行版本控制?
最简单的做法是以 0.1.0 作为你的初始化开发版本,并在后续的每次发行时递增次版本号。

如何判断发布 1.0.0 版本的时机?
当你的软件被用于正式环境,它应该已经达到了 1.0.0 版。如果你已经有个稳定的 API 被使用者依赖,也会是 1.0.0 版。如果你很担心向下兼容的问题,也应该算是 1.0.0 版了。

这不会阻碍快速开发和迭代吗?
主版本号为零的时候就是为了做快速开发。如果你每天都在改变 API,那么你应该仍在主版本号为零的阶段(0.y.z),或是正在下个主版本的独立开发分支中。

对于公共 API,若即使是最小但不向下兼容的改变都需要产生新的主版本号,岂不是很快就达到 42.0.0 版?
这是开发的责任感和前瞻性的问题。不兼容的改变不应该轻易被加入到有许多依赖代码的软件中。升级所付出的代价可能是巨大的。要递增主版本号来发行不兼容的改版,意味着你必须为这些改变所带来的影响深思熟虑,并且评估所涉及的成本及效益比。

为整个公共 API 写文档太费事了!
为供他人使用的软件编写适当的文档,是你作为一名专业开发者应尽的职责。保持项目高效的一个非常重要的部分是掌控软件的复杂度,如果没有人知道如何使用你的软件或不知道哪些函数的调用是可靠的,要掌控复杂度会是困难的。长远来看,使用语义化版本控制以及对于公共 API 有良好规范的坚持,可以让每个人及每件事都运行顺畅。

万一不小心把一个不兼容的改版当成了次版本号发行了该怎么办?
一旦发现自己破坏了语义化版本控制的规范,就要修正这个问题,并发行一个新的次版本号来更正这个问题并且恢复向下兼容。即使是这种情况,也不能去修改已发行的版本。可以的话,将有问题的版本号记录到文档中,告诉使用者问题所在,让他们能够意识到这是有问题的版本。

如果我更新了自己的依赖但没有改变公共 API 该怎么办?
由于没有影响到公共 API,这可以被认定是兼容的。若某个软件和你的包有共同依赖,则它会有自己的依赖规范,作者也会告知可能的冲突。要判断改版是属于修订等级或是次版等级,是依据你更新的依赖关系是为了修复问题或是加入新功能。对于后者,我经常会预期伴随着更多的代码,这显然会是一个次版本号级别的递增。

如果我变更了公共 API 但无意中未遵循版本号的改动怎么办呢?(意即在修订等级的发布中,误将重大且不兼容的改变加到代码之中)
自行做最佳的判断。如果你有庞大的使用者群在依照公共 API 的意图而变更行为后会大受影响,那么最好做一次主版本的发布,即使严格来说这个修复仅是修订等级的发布。记住, 语义化的版本控制就是透过版本号的改变来传达意义。若这些改变对你的使用者是重要的,那就透过版本号来向他们说明。

我该如何处理即将弃用的功能?
弃用现存的功能是软件开发中的家常便饭,也通常是向前发展所必须的。当你弃用部分公共 API 时,你应该做两件事:(1)更新你的文档让使用者知道这个改变,(2)在适当的时机将弃用的功能透过新的次版本号发布。在新的主版本完全移除弃用功能前,至少要有一个次版本包含这个弃用信息,这样使用者才能平顺地转移到新版 API。

语义化版本对于版本的字符串长度是否有限制呢?
没有,请自行做适当的判断。举例来说,长到 255 个字符的版本已过度夸张。再者,特定的系统对于字符串长度可能会有他们自己的限制。

“v1.2.3” 是一个语义化版本号吗?
“v1.2.3” 并不是一个语义化的版本号。但是,在语义化版本号之前增加前缀 “v” 是用来表示版本号的常用做法。在版本控制系统中,将 “version” 缩写为 “v” 是很常见的。比如:git tag v1.2.3 -m "Release version 1.2.3" 中,“v1.2.3” 表示标签名称,而 “1.2.3” 是语义化版本号。

是否有推荐的正则表达式用以检查语义化版本号的正确性?
有两个推荐的正则表达式。第一个用于支持按组名称提取的语言(PCRE[Perl 兼容正则表达式,比如 Perl、PHP 和 R]、Python 和 Go)。

参见:https://regex101.com/r/Ly7O1x/3/

^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$


第二个用于支持按编号提取的语言(与第一个对应的提取项按顺序分别为:major、minor、patch、prerelease、buildmetadata)。主要包括 ECMA Script(JavaScript)、PCRE(Perl 兼容正则表达式,比如 Perl、PHP 和 R)、Python 和 Go。 参见:https://regex101.com/r/vkijKf/1/

^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*

示例讲解:vue-router 插件

贴上vue-router插件的package.json代码,可以看到其中 peerDependencies 值为 {"vue": "^3.2.0"}

{
  "name": "vue-router",
  "version": "4.3.2",
  "main": "index.js",
  "unpkg": "dist/vue-router.global.js",
  "jsdelivr": "dist/vue-router.global.js",
  "module": "dist/vue-router.mjs",
  "types": "dist/vue-router.d.ts",
  "exports": {
    "./auto-routes": {
      "types": "./vue-router-auto-routes.d.ts",
      "node": {
        "import": {
          "production": "./dist/vue-router.node.mjs",
          "development": "./dist/vue-router.node.mjs",
          "default": "./dist/vue-router.node.mjs"
        },
        "require": {
          "production": "./dist/vue-router.prod.cjs",
          "development": "./dist/vue-router.cjs",
          "default": "./index.js"
        }
      },
      "import": "./dist/vue-router.mjs",
      "require": "./index.js"
    },
    "./auto": {
      "types": "./vue-router-auto.d.ts",
      "node": {
        "import": {
          "production": "./dist/vue-router.node.mjs",
          "development": "./dist/vue-router.node.mjs",
          "default": "./dist/vue-router.node.mjs"
        },
        "require": {
          "production": "./dist/vue-router.prod.cjs",
          "development": "./dist/vue-router.cjs",
          "default": "./index.js"
        }
      },
      "import": "./dist/vue-router.mjs",
      "require": "./index.js"
    },
    ".": {
      "types": "./dist/vue-router.d.ts",
      "node": {
        "import": {
          "production": "./dist/vue-router.node.mjs",
          "development": "./dist/vue-router.node.mjs",
          "default": "./dist/vue-router.node.mjs"
        },
        "require": {
          "production": "./dist/vue-router.prod.cjs",
          "development": "./dist/vue-router.cjs",
          "default": "./index.js"
        }
      },
      "import": "./dist/vue-router.mjs",
      "require": "./index.js"
    },
    "./dist/*": "./dist/*",
    "./vetur/*": "./vetur/*",
    "./package.json": "./package.json"
  },
  "sideEffects": false,
  "author": {
    "name": "Eduardo San Martin Morote",
    "email": "posva13@gmail.com"
  },
  "funding": "https://github.com/sponsors/posva",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/vuejs/router.git"
  },
  "bugs": {
    "url": "https://github.com/vuejs/router/issues"
  },
  "homepage": "https://github.com/vuejs/router#readme",
  "files": [
    "index.js",
    "dist/*.{js,cjs,mjs}",
    "dist/vue-router.d.ts",
    "vue-router-auto.d.ts",
    "vue-router-auto-routes.d.ts",
    "vetur/tags.json",
    "vetur/attributes.json",
    "README.md"
  ],
  "peerDependencies": {
    "vue": "^3.2.0"
  },
  "vetur": {
    "tags": "vetur/tags.json",
    "attributes": "vetur/attributes.json"
  },
  "dependencies": {
    "@vue/devtools-api": "^6.5.1"
  },
  "devDependencies": {
    "@microsoft/api-extractor": "^7.40.1",
    "@rollup/plugin-alias": "^5.1.0",
    "@rollup/plugin-commonjs": "^25.0.7",
    "@rollup/plugin-node-resolve": "^15.2.3",
    "@rollup/plugin-replace": "^5.0.5",
    "@rollup/plugin-terser": "^0.4.4",
    "@sucrase/jest-plugin": "^3.0.0",
    "@types/jest": "^29.5.12",
    "@types/jsdom": "^21.1.6",
    "@types/nightwatch": "^2.3.30",
    "@vitejs/plugin-vue": "^5.0.4",
    "@vue/compiler-sfc": "^3.4.23",
    "@vue/server-renderer": "^3.4.23",
    "@vue/test-utils": "^2.4.4",
    "browserstack-local": "^1.5.5",
    "chromedriver": "^121.0.2",
    "connect-history-api-fallback": "^1.6.0",
    "conventional-changelog-cli": "^2.1.1",
    "dotenv": "^16.4.5",
    "faked-promise": "^2.2.2",
    "geckodriver": "^3.2.0",
    "jest": "^29.7.0",
    "jest-environment-jsdom": "^29.7.0",
    "jest-mock-warn": "^1.1.0",
    "nightwatch": "^2.6.22",
    "nightwatch-helpers": "^1.2.0",
    "rimraf": "^5.0.5",
    "rollup": "^3.29.4",
    "rollup-plugin-analyzer": "^4.0.0",
    "rollup-plugin-typescript2": "^0.36.0",
    "sucrase": "^3.34.0",
    "typescript": "~5.3.3",
    "vite": "^5.2.9",
    "vue": "^3.4.23"
  },
  "scripts": {
    "dev": "jest --watch",
    "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 1",
    "build": "rimraf dist && rollup -c rollup.config.mjs",
    "build:dts": "api-extractor run --local --verbose && tail -n +10 src/globalExtensions.ts >> dist/vue-router.d.ts",
    "build:playground": "vue-tsc --noEmit && vite build --config playground/vite.config.ts",
    "build:e2e": "vue-tsc --noEmit && vite build --config e2e/vite.config.mjs",
    "build:size": "pnpm run build && rollup -c size-checks/rollup.config.mjs",
    "dev:e2e": "vite --config e2e/vite.config.mjs",
    "test:types": "tsc --build tsconfig.json",
    "test:dts": "tsc -p ./test-dts/tsconfig.json",
    "test:unit": "jest --coverage",
    "test": "pnpm run test:types && pnpm run test:unit && pnpm run build && pnpm run build:dts && pnpm run test:e2e",
    "test:e2e": "pnpm run test:e2e:headless",
    "test:e2e:headless": "node e2e/runner.mjs --env chrome-headless",
    "test:e2e:native": "node e2e/runner.mjs --env chrome",
    "test:e2e:ci": "node e2e/runner.mjs --env chrome-headless --retries 2",
    "test:e2e:bs": "node e2e/runner.mjs --local -e android5 --tag browserstack",
    "test:e2e:bs-test": "node e2e/runner.mjs --local --env browserstack.local_chrome --tag browserstack"
  }
}

# 说明

vue-router在开发过程中依赖于vue包,但是又不希望将这个依赖关系包含在自己的发布版本中时,就可以使用 peerDependencies(同行依赖)。

让我更详细地解释一下 peerDependencies 的概念和用法:

1. 什么是 peerDependencies?

peerDependencies 是指一个软件包在运行时所需的依赖项,但是它希望这些依赖项由使用它的其他软件包提供,而不是自己将这些依赖项包含在自己的发布版本中。

2. 为什么使用 peerDependencies?

使用 peerDependencies 的主要目的是为了避免在一个项目中出现依赖项的重复版本。当一个软件包同时依赖于另一个软件包,并且两者都在自己的发布版本中包含了相同版本的依赖项时,这可能会导致冲突和版本不一致的问题。

通过将依赖项声明为 peerDependencies,软件包作者可以明确指定它的运行时依赖应该由使用它的其他软件包提供,从而确保所有使用者都使用同一版本的依赖项,避免了版本冲突和不一致的问题。

3. 如何声明 peerDependencies?

要声明 peerDependencies,您可以将依赖项添加到您的软件包的 package.json 文件中的 peerDependencies 字段中,例如:

{
  "name": "your-package",
  "peerDependencies": {
    "dependency-name": "^1.0.0"
  }
}

在上面的示例中,dependency-name 是您的软件包在运行时所需的同行依赖项的名称,^1.0.0 表示您的软件包兼容的依赖项的版本范围。

4. 使用 peerDependencies 的注意事项:

  • 使用者需要手动安装 peerDependencies。在使用您的软件包时,使用者需要确保安装了您声明的 peerDependencies。通常,npm 和 Yarn 在安装软件包时会自动安装相应的 peerDependencies,但是如果使用者手动管理依赖项或者使用其他包管理工具,则可能需要手动安装。
  • 确保对peerDependencies 的正确使用。在声明 peerDependencies 时,需要确保使用者确实能够提供所需的依赖项。通常情况下,应该将 peerDependencies 声明为您的软件包所需要的最小版本,以确保与使用者的兼容性。
  • 避免滥用 peerDependencies。尽管 peerDependencies 可以解决依赖项重复版本的问题,但是滥用会导致依赖项的管理变得复杂,并且可能会造成一些意想不到的问题。因此,在声明 peerDependencies 时应该谨慎选择,并且仅在确实需要时使用。

总的来说,peerDependencies 是一种在软件包开发中管理依赖项的重要机制,可以帮助开发者避免版本冲突和不一致的问题,同时提高了软件包的灵活性和可重用性。

声明

要在您的项目中声明对 vue 3.4.27 版本的 peerDependencies,您可以通过以下步骤完成:

1. 编辑 package.json:

打开您的项目的 package.json 文件,并添加或更新 peerDependencies 字段,如下所示:

{
  "name": "your-project",
  "version": "1.0.0",
  "peerDependencies": {
    "vue": "^3.4.27"
  }
}


2. 安装 Vue:

然后,在您的项目中安装 Vue,确保安装的版本符合您在 peerDependencies 中声明的范围。您可以运行以下命令:

npm install vue@3.4.27 --save-peer

或者,如果您使用的是 Yarn:

yarn add vue@3.4.27 --peer


3. 更新依赖:

安装 Vue 后,您可能需要运行 npm installyarn 命令来更新您的项目的依赖项。

4. 验证配置:

最后,您可以确保 package.json 中的 peerDependencies 部分以及您安装的 Vue 版本符合预期。您可以通过查看 package.json 文件和运行 npm list vueyarn list vue 命令来验证。

这样,您的项目就声明了对 Vue 3.4.27 版本的 peerDependencies。任何使用您的项目的其他软件包都应该在运行时提供符合这个版本要求的 Vue。

验证

这里我随意打开了一个之前项目,查看了vue的同行依赖关系

PS D:\vinca\web> npm list vue
nuxt-app@2.0LTS D:\vinca\web   
├─┬ @chenfengyuan/vue-qrcode@2.0.0-rc.1
│ └── vue@3.4.21 deduped
├─┬ @element-plus/icons-vue@2.3.1      
│ └── vue@3.4.21 deduped
├─┬ @nuxtjs/seo@2.0.0-rc.10
│ └─┬ nuxt-link-checker@3.0.0-rc.7     
│   ├─┬ @vueuse/core@10.9.0
│   │ ├─┬ @vueuse/shared@10.9.0        
│   │ │ └─┬ vue-demi@0.14.7
│   │ │   └── vue@3.4.21 deduped       
│   │ └─┬ vue-demi@0.14.7
│   │   └── vue@3.4.21 deduped
│   ├─┬ floating-vue@5.2.0
│   │ └── vue@3.4.21 deduped
│   ├─┬ nuxt-site-config-kit@2.2.7
│   │ └─┬ site-config-stack@2.2.7
│   │   └── vue@3.4.21 deduped
│   └─┬ nuxt-site-config@2.2.7
│     └─┬ site-config-stack@2.2.7
│       └── vue@3.4.21 deduped
├─┬ @nuxtjs/sitemap@5.1.4
│ ├─┬ @nuxt/devtools-ui-kit@1.1.5
│ │ ├─┬ @vueuse/core@10.9.0
│ │ │ └─┬ vue-demi@0.14.7
│ │ │   └── vue@3.4.21 deduped
│ │ ├─┬ @vueuse/integrations@10.9.0
│ │ │ └─┬ vue-demi@0.14.7
│ │ │   └── vue@3.4.21 deduped
│ │ └─┬ @vueuse/nuxt@10.9.0
│ │   └─┬ vue-demi@0.14.7
│ │     └── vue@3.4.21 deduped
│ ├─┬ @vueuse/core@10.9.0
│ │ └─┬ vue-demi@0.14.7
│ │   └── vue@3.4.21 deduped
│ ├─┬ floating-vue@5.2.2
│ │ ├─┬ vue-resize@2.0.0-alpha.1
│ │ │ └── vue@3.4.21 deduped
│ │ └── vue@3.4.21 deduped
│ └─┬ site-config-stack@2.2.12
│   └── vue@3.4.21 deduped
├─┬ element-plus@2.6.3
│ ├─┬ @vueuse/core@9.13.0
│ │ ├─┬ @vueuse/shared@9.13.0
│ │ │ └─┬ vue-demi@0.14.7
│ │ │   └── vue@3.4.21 deduped
│ │ └─┬ vue-demi@0.14.7
│ │   └── vue@3.4.21 deduped
│ └── vue@3.4.21 deduped
├─┬ nuxt-og-image@3.0.0-rc.53
│ ├─┬ @vueuse/core@10.9.0
│ │ └─┬ vue-demi@0.14.7
│ │   └── vue@3.4.21 deduped
│ ├─┬ json-editor-vue@0.15.1
│ │ └── vue@3.4.21 deduped
│ └─┬ nuxt-icon@0.6.10
│   └─┬ @iconify/vue@4.1.1
│     └── vue@3.4.21 deduped
├─┬ nuxt-svgo@4.0.0
│ └── vue@3.4.21 deduped
├─┬ nuxt@3.10.3
│ ├─┬ @nuxt/devtools@1.1.5
│ │ ├─┬ @vue/devtools-applet@7.0.27
│ │ │ ├─┬ @vue/devtools-ui@7.0.27
│ │ │ │ ├─┬ @vueuse/components@10.9.0
│ │ │ │ │ └─┬ vue-demi@0.14.7
│ │ │ │ │   └── vue@3.4.21 deduped
│ │ │ │ ├─┬ @vueuse/core@10.9.0
│ │ │ │ │ ├─┬ @vueuse/shared@10.9.0
│ │ │ │ │ │ └─┬ vue-demi@0.14.7
│ │ │ │ │ │   └── vue@3.4.21 deduped
│ │ │ │ │ └─┬ vue-demi@0.14.7
│ │ │ │ │   └── vue@3.4.21 deduped
│ │ │ │ └── vue@3.4.21 deduped
│ │ │ ├─┬ vue-virtual-scroller@2.0.0-beta.8
│ │ │ │ ├─┬ vue-observe-visibility@2.0.0-alpha.1
│ │ │ │ │ └── vue@3.4.21 deduped
│ │ │ │ └── vue@3.4.21 deduped
│ │ │ └── vue@3.4.21 deduped
│ │ └─┬ @vue/devtools-kit@7.0.27
│ │   └── vue@3.4.21 deduped
│ ├─┬ @nuxt/vite-builder@3.10.3
│ │ ├─┬ @vitejs/plugin-vue-jsx@3.1.0
│ │ │ └── vue@3.4.21 deduped
│ │ ├─┬ @vitejs/plugin-vue@5.0.4
│ │ │ └── vue@3.4.21 deduped
│ │ └── vue@3.4.21 deduped
│ ├─┬ @unhead/vue@1.8.18
│ │ └── vue@3.4.21 deduped
│ ├─┬ unplugin-vue-router@0.7.0
│ │ └─┬ @vue-macros/common@1.10.1
│ │   └── vue@3.4.21 deduped
│ └── vue@3.4.21 deduped
├─┬ pinia@2.1.7
│ ├─┬ vue-demi@0.14.7
│ │ └── vue@3.4.21 deduped
│ └── vue@3.4.21 deduped
├─┬ vue-router@4.3.0
│ └── vue@3.4.21 deduped
└─┬ vue@3.4.21
  └─┬ @vue/server-renderer@3.4.21
    └── vue@3.4.21 deduped

在 npm 的依赖关系图中,deduped 表示已经被去重了。这意味着在整个依赖树中,有两个或多个依赖项指向了同一个版本的软件包。当 npm 发现这种情况时,它会去除重复的依赖项,只保留一个,并在其他依赖项中引用这个已去重的依赖项。

这种去重机制有助于减少依赖项的重复,减小项目的体积,同时确保所有依赖项都使用同一版本的软件包,从而避免版本冲突和其他问题。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1789310.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

信息系统项目管理师0143:过程概述(9项目范围管理—9.2项目范围管理过程—9.2.1过程概述)

点击查看专栏目录 文章目录 9.2 项目范围管理过程9.2.1 过程概述 9.2 项目范围管理过程 9.2.1 过程概述 项目范围管理过程包括&#xff1a; 规划范围管理&#xff1a;为了记录如何定义、确认和控制项目范围及产品范围&#xff0c;创建范围管理计划。收集需求&#xff1a;为了…

以sqlilabs靶场为例,讲解SQL注入攻击原理【18-24关】

【less-18】 打开时&#xff0c;获取了自己的IP地址。&#xff0c;通过分析源码知道&#xff0c;会将用户的user-agent作为参数记录到数据库中。 提交的是信息有user-Agent、IP、uname信息。 此时可以借助Burp Suite 工具&#xff0c;修改user_agent&#xff0c;实现sql注入。…

小白级教程—安装Ubuntu 20.04 LTS服务器

下载 本教程将使用20.04版进行教学 由于官方速度可能有点慢&#xff0c;可以下方的使用清华镜像下载 https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/ 点击20.24版本 选择 ubuntu-20.04.6-live-server-amd64.iso 新建虚拟机 下载好后 我们使用 VMware 打开它 这里选…

103、python-第三阶段-13-大数据分布式集群运行

hadoop集群 4个多G的数据在集群中用了2.9分钟&#xff0c;如果在一个机器上运行大概需要十几分钟&#xff0c;所以集群速度还是很快的。

sql 查询 不满足 (一个教师编号 的角色 (role =‘2‘or(role=‘1‘and role =‘0‘)) )

sql 查询 不满足 &#xff08;一个教师编号 的角色 &#xff08;role 2’or&#xff08;role1’and role ‘0’&#xff09;&#xff09; &#xff09; 准备 一个 teacher 表 和数据 表 teacher 和数据 -- ---------------------------- -- Table structure for teacher -- …

短期业绩波动较大被券商不予评级,金种子酒背靠华润如何发力?

《港湾商业观察》施子夫 王璐 虽然一季度成功实现了扭亏为盈&#xff0c;但从近些年年报来看&#xff0c;金种子酒&#xff08;600199.SH&#xff09;的业绩压力依然不容小觑。白酒主业萎靡不振时&#xff0c;金种子酒开始了剥离非主营业务。 这些措施能否有利于主业向好&am…

MQ之初识kafka

1. MQ简介 1.1 MQ的诞生背景 以前网络上的计算机&#xff08;或者说不同的进程&#xff09;传递数据&#xff0c;通信都是点对点的&#xff0c;而且要实现相同的协议&#xff08;HTTP、 TCP、WebService&#xff09;。1983 年的时候&#xff0c;有个在 MIT 工作的印度小伙突发…

软理复习范围

1.直觉主义逻辑常采用三值逻辑来处理命题的真值&#xff0c;包括以下三个真值&#xff1a; 真&#xff08;True&#xff09;&#xff1a;表示命题是确定为真的。假&#xff08;False&#xff09;&#xff1a;表示命题是确定为假的。未知&#xff08;Unknown&#xff09;&#…

Keil编译bin格式固件方法

打开Option选项卡&#xff0c;选择User&#xff0c;在After Build/Rebuild下面增加以下命令&#xff1a; fromelf.exe --bin -o "L.bin" "#L"

短剧APP开发,推动短剧市场的全新发展

近几年&#xff0c;短剧火爆出圈&#xff0c;迎来了爆发式增长态势&#xff0c;市场规模一跃达到了百亿元&#xff01;短剧节奏快、剧情爽、情节猎奇&#xff0c;极大地满足了用户的追剧需求&#xff0c;深受大众的喜爱。 短剧巨大的市场发展前景也衍生出了各种新的短剧发展赛…

FSR 3 - Upscaling for Unity(性能优化工具)

FSR 3 - Upscaling for Unity已在Unity版本2021、2022和2023中进行了测试! 使用FSR 3 Upscaling for Unity提升帧数! FSR 3是一种升级技术,它基于较低分辨率的输入创建高质量和高分辨率的帧。通过使用这种方法,您的项目可以在极低的分辨率下运行,而不会损失视觉质量,也不…

连锁实体店同城引流的两种方式

连锁实体店开在哪里&#xff0c;它的影响力就在哪里&#xff0c;所以&#xff0c;连锁店的选址很重要&#xff0c;这点是毋庸置疑的&#xff0c;今天我们聊聊连锁实体店引流的两种方式。 1、同城引流新客到店 实体店的覆盖范围在3-5公里 使用抖音同城引流快速覆盖这个范围内的…

产品经理:做好有效的客户需求分析

需求分析是产品开发过程中的重要环节&#xff0c;它直接决定了产品是否能够满足市场需求和用户期望。通过深入了解客户需求&#xff0c;产品经理可以确保产品功能的设计符合用户的实际需求&#xff0c;从而提高产品的用户满意度和市场竞争力。 一、识别用户需求 识别用户需求…

从头搭hadoop集群--模版虚拟机的配置

软件说明&#xff1a; VMware Workstation Pro MobaXterm_Personal_12.4 映像文件&#xff1a;CentOS-7-x86_64-DVD-1908.iso jdk版本&#xff1a;jdk1.8.0_111 映射文件和jdk文件如下&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/18dsDlLk4WeW2Y8O2jUSkGQ?pw…

微服务学习Day9-分布式事务Seata

文章目录 分布式事务seata引入理论基础CAP定理BASE理论 初识Seata动手实践XA模式AT模式TCC模式SAGA模式 高可用 分布式事务seata 引入 理论基础 CAP定理 BASE理论 初识Seata 动手实践 XA模式 AT模式 TCC模式 Service Slf4j public class AccountTCCServiceImpl implements A…

运维开发介绍

目录 1.什么是运维开发 2.作用 3.优点 4.缺点 5.应用场景 5.1.十个应用场景 5.2.网站和Web应用程序 6.案例 7.小结 1.什么是运维开发 运维开发&#xff08;DevOps&#xff09;是一种结合软件开发&#xff08;Development&#xff09;与信息技术运维&#xff08;Opera…

使用Vue.js将form表单传递到后端

一.form表单 <form submit.prevent"submitForm"></form> form表单像这样写出来&#xff0c;然后把需要用户填写的内容写在form表单内。 二.表单内数据绑定 <div class"input-container"><div style"margin-left: 9px;"&…

Java Web学习笔记4——HTML、CSS

HTML&#xff1a; HTML&#xff1a;超文本标记语言。 超文本&#xff1a;超越了文本的限制&#xff0c;比普通文本更强大。除了文字信息&#xff0c;还可以定义图片、音频、视频等内容。 标记语言&#xff1a;有标签构成的语言。 HTML标签都是预定义好的&#xff0c;例如&a…

云服务(ECS)Docker安装vulhub安装详解

本文以xshell进行远程控制 1.以ssh连接云服务器 ssh 服务器名公网ip [D:\~]$ ssh root47.99.138.9 在弹框中输入密码 2.安装docker curl -s http://get.docker.com/ | sh rootiZbp1fm14idjlfp53akni8Z:~# curl -s https://get.docker.com/ | sh # Executing docker insta…

【二进制部署k8s-1.29.4】十一、metallb的安装部署

文章目录 简介 一.安装metallb二.配置metallb三.验证metallb 简介 本章节主要讲解安装metallb-v0.7.1的安装&#xff0c;metallb算是平民版的负载均衡&#xff0c;用于测试、访问量较小的情况还是比较不错的&#xff0c;但是对于请求量比较的时候&#xff0c;由于流量都集中在一…