Резюме важных различий в поведении:

dependencies установлены на обоих:

  • npm install из каталога, содержащего package.json
  • npm install $package в любом другом каталоге

devDependencies являются:

  • также установлен на npm install в каталоге, содержащем package.json, если только вы не передадите флаг --production.
  • не установлен на npm install "$package" в любом другом каталоге, если вы не укажете ему опцию --dev.
  • не устанавливаются транзитивно.

peerDependencies:

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

Транзитивность :

  • dependencies устанавливаются транзитивно: если A требует B, а B требует C, то устанавливается C, иначе B не может работать, как и A.
  • devDependencies не устанавливается транзитивно. Например. нам не нужно тестировать B для тестирования A, поэтому тестовые зависимости B можно опустить.

devDependencies

Источник: https://docs.npmjs.com/cli/v8/configuring-npm/package-json#devdependencies

dependencies необходимы для запуска, devDependencies только для разработки, например: модульные тесты, транспиляция CoffeeScript в JavaScript, минимизация, ...

Если вы собираетесь разработать пакет, вы загружаете его (например, через git clone), переходите в его корень, содержащий package.json, и запускаете:

npm install

Так как у вас есть актуальный исходник, то понятно, что вы хотите его развивать, поэтому по умолчанию также устанавливаются как dependencies (поскольку для разработки надо, конечно, запустить), так и devDependency зависимости.

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

npm install "$package"

В этом случае вам обычно не нужны зависимости для разработки, поэтому вы просто получаете то, что необходимо для использования пакета: dependencies.

Если вы действительно хотите установить пакеты разработки в этом случае, вы можете установить для параметра конфигурации dev значение true, возможно, из командной строки следующим образом:

npm install "$package" --dev

Параметр false по умолчанию, так как это гораздо менее распространенный случай.

одноранговые зависимости

Источник: https://docs.npmjs.com/cli/v8/configuring-npm/package-json#peerdependencies

С обычными зависимостями у вас может быть несколько версий зависимости: она просто устанавливается внутри node_modules зависимости.

Например. если dependency1 и dependency2 оба зависят от dependency3 в разных версиях, дерево проекта будет выглядеть так:

root/node_modules/
                 |
                 +- dependency1/node_modules/
                 |                          |
                 |                          +- dependency3 v1.0/
                 |
                 |
                 +- dependency2/node_modules/
                                            |
                                            +- dependency3 v2.0/

Плагины, однако, представляют собой пакеты, которым обычно не требуется другой пакет, который в данном контексте называется host. Вместо:

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

Например. если dependency1 и dependency2 одноранговые узлы зависят от dependency3, дерево проекта будет выглядеть так:

root/node_modules/
                 |
                 +- dependency1/
                 |
                 +- dependency2/
                 |
                 +- dependency3 v1.0/

Это происходит даже при том, что вы никогда не упоминаете dependency3 в своем файле package.json.

Я думаю, что это пример шаблона проектирования Инверсия управления.

Типичным примером одноранговых зависимостей является Grunt, хост и его плагины.

Например, в плагине Grunt типа https://github.com/gruntjs/grunt-contrib-uglify вы увидите следующее:

  • grunt is a peer-dependency
  • единственный require('grunt') находится под tests/: он фактически не используется программой.

Затем, когда пользователь будет использовать плагин, он неявно потребует плагин из Gruntfile, добавив строку grunt.loadNpmTasks('grunt-contrib-uglify'), но именно grunt пользователь будет вызывать напрямую.

Это бы не сработало, если бы для каждого плагина требовалась своя версия Grunt.

peerDependenciesMeta

Источник: https://docs.npmjs.com/cli/v8/configuring-npm/package-json#peerdependenciesmeta

Когда пользователь устанавливает ваш пакет, npm будет выдавать предупреждения, если пакеты, указанные в peerDependencies, еще не установлены. Поле peerDependenciesMeta служит для предоставления npm дополнительной информации о том, как должны использоваться ваши одноранговые зависимости. В частности, он позволяет помечать одноранговые зависимости как необязательные.

Например:

{
  "name": "tea-latte",
  "version": "1.3.5",
  "peerDependencies": {
    "tea": "2.x",
    "soy-milk": "1.2"
  },
  "peerDependenciesMeta": {
    "soy-milk": {
      "optional": true
    }
  }
}

Пометка одноранговой зависимости как необязательной гарантирует, что npm не выдаст предупреждение, если пакет soy-milk не установлен на хосте. Это позволяет вам интегрироваться и взаимодействовать с различными хост-пакетами, не требуя их установки.

связанные зависимости

Источник: https://docs.npmjs.com/cli/v8/configuring-npm/package-json#bundleddependencies

Это определяет массив имен пакетов, которые будут объединены при публикации пакета.

В тех случаях, когда вам нужно сохранить пакеты npm локально или сделать их доступными через загрузку одного файла, вы можете объединить пакеты в файл tarball, указав имена пакетов в массиве bundledDependencies и выполнив npm pack.

Например, если мы определим package.json следующим образом:

{   
  "name": "awesome-web-framework",   
  "version": "1.0.0",   
  "bundledDependencies": [     
    "renderized",     
    "super-streams"   
  ] 
}

мы можем получить файл awesome-web-framework-1.0.0.tgz, запустив npm pack. Этот файл содержит зависимости renderized и super-streams, которые можно установить в новом проекте, выполнив npm install awesome-web-framework-1.0.0.tgz. Обратите внимание, что имена пакетов не включают никаких версий, так как эта информация указана в dependencies.

Если это пишется как "bundleDependencies", то это тоже считается.

необязательные зависимости

Источник: https://docs.npmjs.com/cli/v8/configuring-npm/package-json#Optionaldependencies

Если можно использовать зависимость, но вы хотите, чтобы npm продолжил работу, если ее не удается найти или установить не удается, вы можете поместить ее в объект optionalDependencies. Это сопоставление имени пакета с версией или URL-адресом, как и у объекта dependencies. Разница в том, что сбои сборки не приводят к сбою установки. Запуск npm install --no-optional предотвратит установку этих зависимостей.

Ответственность за отсутствие зависимости по-прежнему лежит на вашей программе. Например, что-то вроде этого:

try {   
  var foo = require('foo')   
  var fooVersion = require('foo/package.json').version 
} catch (er) {   
  foo = null 
} 
if ( notGoodFooVersion(fooVersion) ) {   
  foo = null 
}  
// .. then later in your program ..  
if (foo) {   
  foo.doFooThings() 
}

Записи в optionalDependencies переопределяют записи с тем же именем в dependencies, поэтому обычно лучше размещать их только в одном месте.

ЗАКЛЮЧЕНИЕ

надеюсь теперь все понятно.

Спасибо, что читаете 🙏.

И если вам понравилось мое объяснение, помните, что хлопать можно больше одного раза 👏.

Хорошего дня