플러그인에 대해 npm에서 피어 종속성을 사용하는 이유는 무엇입니까?


218

예를 들어, Grunt 플러그인이 grunt에 대한 종속성을 " 피어 종속성 " 으로 정의하는 이유는 무엇 입니까?

플러그인이 grunt-plug / node_modules 에서 자체 종속성으로 Grunt를 가질 수없는 이유는 무엇 입니까?

피어 종속성은 https://nodejs.org/en/blog/npm/peer-dependencies/에 설명되어 있습니다.

그러나 나는 그것을 정말로 얻지 못한다.

현재 Grunt 작업을 사용하여 소스 파일을 / dist / 폴더에 빌드하여 로컬 장치에서 제공하는 AppGyver 스테로이드와 함께 일하고 있습니다. 나는 npm에 아주 새롭고 grunt이므로 무슨 일이 일어나고 있는지 완전히 이해하고 싶습니다.

지금까지 나는 이것을 얻는다 :

[rootfolder] /package.json 은 npm grunt-steroids에게 개발 을 위해 npm 패키지에 의존 한다고 알려줍니다 .

  "devDependencies": {
    "grunt-steroids": "0.x"
  },

괜찮아. [rootfolder] 에서 npm install을 실행 하면 종속성을 감지하고 [rootfolder] / node_modules / grunt-steroids에 grunt-steroids를 설치 합니다.

그런 다음 Npm은 [rootfolder] /node_modules/grunt-steroids/package.json을 읽으 므로 grunt-steroids자체 종속성을 설치할 수 있습니다 .

"devDependencies": {
    "grunt-contrib-nodeunit": "0.3.0",
    "grunt": "0.4.4"
  },
"dependencies": {
    "wrench": "1.5.4",
    "chalk": "0.3.0",
    "xml2js": "0.4.1",
    "lodash": "2.4.1"
  },
"peerDependencies": {
    "grunt": "0.4.4",
    "grunt-contrib-copy": "0.5.0",
    "grunt-contrib-clean": "0.5.0",
    "grunt-contrib-concat": "0.4.0",
    "grunt-contrib-coffee": "0.10.1",
    "grunt-contrib-sass": "0.7.3",
    "grunt-extend-config": "0.9.2"
  },

" 종속성 "패키지는 [rootfolder] / node_modules / grunt-steroids / node_modules에 설치되어 있으며 이는 나에게 논리적입니다.

" devDependencies "가 설치되어 있지 않습니다. 확실하게 npm을 사용하여 감지하려고 시도하고 grunt-steroids개발하지 않는 것으로 감지 됩니다.

그러나 " peerDependencies "가 있습니다.

이것들은 [rootfolder] / node_modules에 설치되어 있는데 , 다른 root 플러그인 (또는 무엇이든)과의 충돌을 피하기 위해 [rootfolder] / node_modules / grunt-steroids / node_modules에 왜 없는지 이해하지 못 합니까?

답변:


421

TL; DR : [1] peerDependencies 은 노출 되지 않은 "비공개" 종속성 과 달리 소비 코드에 노출되고 사용되는 것으로 예상되는 종속성을위한 것이며 구현 세부 사항 일뿐입니다.

동료 상호 의존성 문제 해결

NPM의 모듈 시스템은 계층 적입니다. 보다 간단한 시나리오의 가장 큰 장점 중 하나는 npm 패키지를 설치할 때 해당 패키지에 자체 종속성이 있으므로 즉시 사용할 수 있다는 것입니다.

그러나 다음과 같은 경우에 문제가 발생합니다.

  • 프로젝트와 사용중인 일부 모듈은 다른 모듈에 따라 다릅니다.
  • 세 개의 모듈은 서로 대화해야합니다.

예에서

하자 당신이 구축하고 말하는 YourCoolProject당신이 모두를 사용 JacksModule 1.0하고 JillsModule 2.0. 그리고에 JacksModule의존 JillsModule하지만 다른 버전에 의존 한다고 가정 해 봅시다 1.0. 이 두 버전이 맞지 않는 한 아무런 문제가 없습니다. 표면 아래에서 JacksModule사용 되는 사실 JillsModule은 구현 세부 사항입니다. 우리는 JillsModule두 번 번들을 제공 하지만 안정적인 소프트웨어를 즉시 얻을 때 지불해야 할 가격은 적습니다.

그러나 이제는 어떤 식 으로든 JacksModule의존성을 드러내면 어떨까요 JillsModule? JillsClass예를 들어 인스턴스를 받아들입니다 . new JillsClass사용 2.0하는 라이브러리 버전 을 만들어 전달하면 jacksFunction어떻게됩니까? 모든 지옥은 풀릴 것이다! 간단한 것을 좋아 jillsObject instanceof JillsClass갑자기 돌아갑니다 false때문에 jillsObject실제의 인스턴스 인 다른 JillsClass2.0버전.

동료 종속성이이를 해결하는 방법

그들은 npm에게 말한다

이 패키지가 필요하지만 내 모듈 전용 버전이 아니라 프로젝트의 일부인 버전이 필요합니다.

NPM이 패키지 프로젝트에 설치되고 있음을 볼 때 하지 않는 그 의존성을 가지고, 또는이가 호환되지 않는 버전 그것의를, 설치 과정에서 사용자에게 경고합니다.

언제 피어 종속성을 사용해야합니까?

  • 당신이 라이브러리를 작성하는 경우 다른 프로젝트에서 사용하고, 수
  • 이 라이브러리는 다른 라이브러리를 사용 하고 있습니다.
  • 사용자가 다른 라이브러리에서도 작업 할 것을 기대 / 필요

일반적인 시나리오는 더 큰 프레임 워크를위한 플러그인입니다. Gulp, Grunt, Babel, Mocha 등을 생각해보십시오. Gulp 플러그인을 작성하는 경우, 플러그인이 개인용 Gulp 버전이 아니라 사용자 프로젝트에서 사용하는 것과 동일한 Gulp에서 작동하기를 원합니다.


주석

  1. 너무 오래; 읽지 않았다. 너무 긴 것으로 간주되는 텍스트에 대한 짧은 요약을 나타내는 데 사용됩니다.

2
플러그인을 빌드 할 때 피어 종속성에 대해 패키지 종속성의 복제본을 가져야합니까? OP 예제에서 우리는 "grunt": "0.4.4"devDependencies와 peerDependencies에 있음을 알 수 있습니다. 복제본을 갖는 것이 나에게 의미 grunt가 있습니다. 라이브러리는 peerDependencies 버전 잠금을 고려하는 한 자체 버전을 사용할 수 있습니다. 그 맞습니까? 아니면 OP 예가 매우 나쁜 예입니까?
Vadorequest

4
Grunt의 팬인 Grunt 플러그인을 만드는 사람들을 상상할 수 있습니다. 그들이 그것을 만드는 데 사용하는 빌드 프로세스와 함께? 개발자 의존성으로 추가하면 분리 할 수 ​​있습니다. 기본적으로 빌드 타임과 런타임의 두 단계가 있습니다. 빌드 시간 동안 개발자 종속성이 필요합니다. 런타임시 규칙 및 피어 종속성이 필요합니다. 물론 의존성의 의존성으로 모든 것이 빠르게 혼란스러워집니다 :)
Stijn de Witt

1
이 답변에 감사드립니다! 그냥 경우, 귀하의 예제에서, 명확하게 JacksModule의존 JillsModule ^1.0.0JillsModule의 피어 종속되는 JacksModuleYourCoolProject사용하고 JacksModule그리고 JillsModule ^2.0.0우리가 설치하는 우리에게 알려 드릴 것입니다 NPM에 의해 피어 종속성 경고, 얻을 것이다, JillsModule ^1.0.0물론입니다. 그러면 어떻게됩니까? ?를 통해 YourCoolProject두 가지 버전의 가져 JillsModule오기를 할 수 있습니다 import jillsModule from "...". 그리고 내가 사용할 때 JacksModule인스턴스를 전달해야 한다는 것을 어떻게 기억 JillsModule v1.0.0합니까?
토닉 스

1
@tonix 글쎄, 그것은 당신이 버전 비 호환성을 갖는 문제가 될 것입니다. peerDependencies는이를 해결하지 못합니다. 그러나 문제를 명백하게하는 데 도움이됩니다. 두 버전을 자동으로 사용하는 대신 버전 불일치가 명확하게 표시되기 때문입니다. 라이브러리를 선택하는 앱 개발자는 솔루션을 찾아야합니다.
Stijn de Witt

2
@tonix 또는 세 번째 옵션 : 리포지토리를 복제하고 JacksModule이를 업그레이드 JillsModule ^2.0.0하여 프로젝트 관리자에게 PR을 제공하십시오. 이 종속성이 오래되었다는 버그를 먼저 제출하여 업데이트하는 데 도움이 될 수 있습니다. 좋은 PR을 만들면 대부분의 라이브러리 관리자가이를 병합하고 감사합니다. 관리자가 응답하지 않으면 이름 아래에 네임 스페이스가 지정된 NPM에 포크를 게시하고 대신 포크를 사용할 수 있습니다. 어쨌든 해결책이 있지만 peerDependencies독자적으로 해결하지는 않습니다.
Stijn de Witt

26

먼저 기사를 다시 읽는 것이 좋습니다. 약간 혼란 스럽지만 winston-mail의 예제는 그 이유를 보여줍니다.

예를 들어, 테스트 된 최신 버전이기 때문에 객체에 winston-mail@0.2.3지정된 "winston": "0.5.x"것으로 가정 해 봅시다 "dependencies". 당신의 최신 버전을 찾아 볼 수 있도록 앱 개발자는 최신의 그리고 최고의 물건을 원 winston하고의를 winston-mail하고로 package.json에 넣어

{
  "dependencies": {  
    "winston": "0.6.2",  
    "winston-mail": "0.2.3"  
  }  
}

그러나 이제 npm install을 실행하면 예기치 않은 종속성 그래프가 생성됩니다.

├── winston@0.6.2  
└─┬ winston-mail@0.2.3                
  └── winston@0.5.11

이 경우 몇 가지 문제가 발생할 수있는 여러 버전의 패키지가있을 수 있습니다. 피어 종속성을 통해 npm 개발자는 사용자에게 루트 폴더에 특정 모듈이 있는지 확인할 수 있습니다. 그러나 특정 버전의 패키지를 설명하면 다른 버전을 사용하는 다른 패키지에 문제가 발생할 수 있다는 점은 정확합니다. 이 문제는 기사에서 알 수 있듯이 npm 개발자와 관련이 있습니다.

한 가지 조언 : 정기적 인 종속성과는 달리 피어 종속성 요구 사항 은 관대해야합니다 . 피어 종속성을 특정 패치 버전으로 잠그면 안됩니다.

따라서 개발자는 peerDependencies 를 정의하기 위해 semver 를 따라야합니다. GitHub에서 grunt-steroids 패키지에 대한 이슈를 열어야합니다.


1
당신은 그렇게 multiple versions of a package which would cause some issues말하지만 패키지 관리자의 요점이 아닌가? 프로젝트에 동일한 패키지의 두 가지 버전이있는 동일한 기사에서 더 자세히 설명합니다. 하나는 개발자가 제공하고 다른 하나는 타사 라이브러리가 제공합니다.
Adam Beck

1
피어 종속성의 요점을 이해한다고 생각하지만 winston예제 에서 winston-mail내 버전이 피어 종속성과 일치하지 않기 때문에 라이브러리 를 사용할 수 없습니까? 라이브러리를 전혀 사용할 수없는 것보다 1 라이브러리의 최신 및 최대에서 일시적으로 다운 그레이드하는 것이 좋습니다.
Adam Beck

1
첫 번째 의견에 대해서는 이해하고 사용하는 한 테스트와 관련이 있습니다. 예를 들어 특정 타사 패키지에 대해 귀하가 테스트 한 패키지가있는 경우 하나의 패키지인지 확실하지 않습니다. 패키지가 작동하는 종속성 변경 (버그 수정, 주요 기능 업데이트). 따라서 특정 플러그인 버전을 지정할 수 있으며 테스트와 함께 저장됩니다.
Fer to

1
두 번째 의견 : 문서에서 개발자가 패키지 종속성에 관대하고 "0.2.1"대신 "~ 0.2.1"-> "0.2.x"대신 semver를 사용해야한다고 말하는 이유입니다. "0.3.x"또는 "> = 0.2.1"-> "0.2.x"에서 "1.x"또는 "x.2"까지의 모든 항목이 아닙니다. .. (실제로 npm 패키지에는 바람직하지 않습니다. ~
Fer To

15

peerDependencies 가능한 가장 간단한 예제로 설명했습니다.

{
  "name": "myPackage",
  "dependencies": {
    "foo": "^4.0.0",
    "react": "^15.0.0"
  }
}


{
  "name": "foo"
  "peerDependencies": {
    "react": "^16.0.0"
  }
}

이 버전의 반응 설치하려고하기 때문에 오류가 발생합니다 myPackage에에 설치 NPM 실행 ^15.0.0foo반작용 만 호환되는 ^16.0.0.

peerDependencies가 설치되지 않았습니다.


왜 foo 안에 16을 반응으로 넣지 않겠습니까? 그렇게하면 15와 16 모두 사용 가능하고 foo는 16을 사용할 수 있고 mypackage는 15를 사용할 수 있습니까?
nitinsh99

React는 런타임에 부트 스트랩되는 프레임 워크입니다. React 15와 React 16이 동일한 페이지에 존재하기 위해서는 최종 사용자에게 굉장히 무겁고 문제가되는 동시에 부스트해야합니다. fooReact 15와 React 16 모두에서 작동 하면 peerDependency를로 나열 할 >=15 < 17 있습니다.
Jens Bodal

nitinsh99 내 대답은 peerDependencies에 의해 throw 오류를 제거하는 방법, 가능하지 간단한 예와 peerDependencies의 목적을 설명했다
크리스토퍼 Tokar

@ nitinsh99 패키지 의존성 내부에 반응을 추가하면 후크와 같은 문제가 발생합니다
Masood
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.