Резюме важных различий в поведении:
dependencies
установлены на обоих:
npm install
из каталога, содержащегоpackage.json
npm install $package
в любом другом каталоге
devDependencies
являются:
- также установлен на
npm install
в каталоге, содержащемpackage.json
, если только вы не передадите флаг--production
. - не установлен на
npm install "$package"
в любом другом каталоге, если вы не укажете ему опцию--dev
. - не устанавливаются транзитивно.
- 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 apeer-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
, поэтому обычно лучше размещать их только в одном месте.
ЗАКЛЮЧЕНИЕ
надеюсь теперь все понятно.
Спасибо, что читаете 🙏.
И если вам понравилось мое объяснение, помните, что хлопать можно больше одного раза 👏.
Хорошего дня