Зачем использовать одноранговые зависимости в npm для плагинов?

Почему, например, плагин Grunt определяет свою зависимость от grunt как " равноправные зависимости "?

Почему плагин не может просто иметь Grunt как свою собственную зависимость в grunt-plug/node_modules?

Зависимости пира описаны здесь: https://nodejs.org/en/blog/npm/peer-dependencies/

Но я не совсем понимаю.

пример

Сейчас я работаю со стероидами AppGyver, которые используют задачи Grunt для сборки моих исходных файлов в папку/dist/для обслуживания на локальном устройстве. Я новичок в npm и хрюкаю, поэтому я хочу полностью понять, что происходит.

Пока я получаю это:

[rootfolder]/package.json сообщает npm, что это зависит от пакета nru grunt-steroids для разработки:

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

Хорошо. Запуск npm install в [rootfolder] обнаруживает зависимость и устанавливает grunt-стероиды в [rootfolder]/node_modules/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, а не развиваться на нем.

Но тогда у нас есть " взаимные зависимости ".

Они установлены в [rootfolder]/node_modules, и я не понимаю, почему там, а не в [rootfolder]/node_modules/grunt-steroids/node_modules, чтобы избежать конфликтов с другими подключаемыми плагинами (или чем-то еще)?

Ответ 1

TL; DR: [1]peerDependencies предназначены для зависимостей, которые предоставляются (и предполагается, что будут использоваться) потребляющим кодом, в отличие от "частных" зависимостей, которые не предоставляются и являются лишь подробностями реализации.

Проблема взаимозависимости решает

Система модулей NPM является иерархической. Одним из больших преимуществ для более простых сценариев является то, что при установке пакета npm этот пакет приносит с собой свои собственные зависимости, поэтому он будет работать "из коробки".

Но проблемы возникают, когда:

  • И ваш проект, и используемый вами модуль зависят от другого модуля.
  • Три модуля должны общаться друг с другом.

В примере

Допустим, вы YourCoolProject и используете как JacksModule 1.0 и JillsModule 2.0. И давайте предположим, что JacksModule также зависит от JillsModule, но от другой версии, скажем, 1.0. Пока эти 2 версии не встречаются, проблем нет. Тот факт, что JacksModule использует JillsModule под поверхностью, является лишь деталью реализации. Мы JillsModule дважды, но это небольшая цена, когда мы получаем стабильное программное обеспечение из коробки.

Но что теперь, если JacksModule каким-то JacksModule раскрывает свою зависимость от JillsModule. Например, он принимает экземпляр JillsClass... Что произойдет, когда мы создадим new JillsClass с использованием библиотеки версии 2.0 и передадим его в jacksFunction? Весь ад вырвется на свободу! Простые вещи, такие как jillsObject instanceof JillsClass, неожиданно возвращают false потому что jillsObject на самом деле является экземпляром другого JillsClass, версии 2.0.

Как это делают коллегиальные зависимости?

Они говорят нпм

Мне нужен этот пакет, но мне нужна версия, которая является частью проекта, а не какая-то версия, приватная для моего модуля.

Когда npm обнаружит, что ваш пакет устанавливается в проект, который не имеет этой зависимости или имеет несовместимую версию, он предупредит пользователя во время процесса установки.

Когда вы должны использовать зависимости от сверстников?

  • Когда вы создаете библиотеку для использования другими проектами, и
  • Эта библиотека использует какую-то другую библиотеку, и
  • Вы ожидаете/нуждаетесь в работе пользователя с этой другой библиотекой

Распространенные сценарии - это плагины для больших фреймворков. Подумайте о таких вещах, как Gulp, Grunt, Babel, Mocha и т.д. Если вы пишете плагин Gulp, вы хотите, чтобы этот плагин работал с тем же Gulp, который использует пользовательский проект, а не с вашей собственной частной версией Gulp.


Аннотации

  1. Слишком долго; не читал Используется для обозначения краткого описания текста, который считается слишком длинным.

Ответ 2

Я бы порекомендовал вам сначала прочитать статью снова. Это немного сбивает с толку, но пример с winston-mail показывает вам ответ:

Например, давайте притворимся, что [email protected] указал "winston": "0.5.x" в своем объекте "dependencies" поскольку эта последняя версия была проверена. Как разработчик приложений, вам нужны самые последние и самые лучшие вещи, поэтому вы ищите последние версии winston и winston-mail и помещаете их в свой package.json как

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

Но теперь запуск npm install приводит к неожиданному графу зависимостей

├── [email protected]  
└─┬ [email protected]                
  └── [email protected]

В этом случае возможно иметь несколько версий пакета, что может вызвать некоторые проблемы. Зависимости между равноправными узлами позволяют разработчикам npm убедиться, что у пользователя есть определенный модуль (в корневой папке). Но вы правы в том, что описание одной конкретной версии пакета может привести к проблемам с другими пакетами, использующими другие версии. Эта проблема связана с разработчиками npm, как говорится в статьях

Один совет: требования зависимости от сверстников, в отличие от требований для обычных зависимостей, должны быть снисходительными. Вы не должны блокировать ваши одноранговые зависимости до определенных версий исправлений.

Поэтому разработчики должны следовать semver для определения peerDependencies. Вы должны открыть вопрос для пакета grunt-стероидов на GitHub...

Ответ 3

peerDependencies объясняется на простейшем возможном примере:

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


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

запуск npm install в myPackage выдаст ошибку, потому что он пытается установить React версии ^15.0.0 И foo который совместим только с React ^16.0.0.

peerDependencies НЕ установлены.

Ответ 4

Как говорится в официальном Blueprint Если вы видите ошибки UNMET PEER DEPENDENCY, вы должны вручную установить React:

npm install --save react react-dom react-addons-css-transition-group

вы можете найти его здесь