Эта статья одновременно публикуется в блоге автора:В 2018 году вы все еще устанавливаете только npm?
С развитием сообщества nodejs и даже в области интерфейсной веб-инженерии npm, инструмент управления пакетами, который поставляется с узлом, стал обязательным инструментом для каждого фронтенд-разработчика. Но реальность такова, что многие из нас до сих пор используют и понимают эту инфраструктуру nodejs по адресу:npm install
Здесь (вы когда-нибудь делали что-то вроде удаления всего каталога node_modules, а затем переустанавливали его?)
Конечно, сейчас npm может стать самым масштабным в мире.система управления пакетами, во многом благодаря его достаточномудружелюбный пользователь, видите ли, даже если я могу только выполнить установку, мне не нужно слишком беспокоиться о каких-либо серьезных проблемах. Но функция npm — это гораздо больше, чем просто установка. Эта статья поможет вам разобраться в принципах, функциях, и навыки работы с npm, о которых вы могли не знать, и (на мой взгляд) лучшие практики.
Вам лень читать документацию по npm, я помогу вам перевести и попробовать разобраться 🐶🐶🐶
1. npm init
Все мы знаем, что файл package.json — это файл описания, используемый для определения пакета, и мы также знаем, чтоnpm init
Команда используется для инициализации простого файла package.json После выполнения команды терминал запросит по очереди такие поля, как имя, версия, описание и т. д.
1.1 npm init выполняет поведение по умолчанию
И если вы хотите быть ленивым и не нажимать Enter все время, просто добавьте параметр --yes после команды, которая будет иметь тот же эффект, что и следующий шаг.
npm init --yes
1.2 Настройка поведения инициализации npm
Принцип работы команды npm init не сложен, достаточно вызвать скрипт и вывести инициализированный файл package.json. Соответственно реализация кастомной команды npm init тоже очень проста, создайте ее в домашнем каталоге.npm-init.js
То есть файл module.exports является конфигурационным содержимым package.json.Когда необходимо получить пользовательский ввод, используйтеprompt()
метод.
Например, напишите ~/.npm-init.js так:
const desc = prompt('description?', 'A new package...')
const bar = prompt('bar?', '')
const count = prompt('count?', '42')
module.exports = {
key: 'value',
foo: {
bar: bar,
count: count
},
name: prompt('name?', process.cwd().split('/').pop()),
version: prompt('version?', '0.1.0'),
description: desc,
main: 'index.js',
}
На этом этапе выполните его в каталоге ~/hellonpm init
получит package.json следующим образом:
{
"key": "value",
"foo": {
"bar": "",
"count": "42"
},
"name": "hello",
"version": "0.1.0",
"description": "A new package...",
"main": "index.js"
}
Помимо создания package.json, поскольку .npm-init.js является обычным модулем, это означает, что мы можем делать все, что может делать скрипт узла. Например, создайте README, .eslintrc и другие необходимые файлы проекта через fs, чтобы реализовать роль каркаса проекта.
2. Установка пакета зависимостей
Управление зависимостями — это основная функция npm, принцип которой заключается в выполненииnpm install
Установите зависимости в папку ./node_modules текущего каталога из зависимостей, devDependencies в package.json .
2.1 определение пакета
Мы все знаем, что если вы хотите вручную установить пакет, выполнитеnpm install <package>
команда сделает. Пакет третьего параметра здесь обычно является именем пакета, который мы хотим установить.В конфигурации по умолчанию npm найдет адрес пакета, соответствующий имени пакета, из источника по умолчанию (Реестр), загрузит и установит его. Но в мире npm, в дополнение к простому указанию имени пакета, пакет также может быть URL-адресом http/git url/путь к папке, указывающим на допустимое имя пакета.
читатьдокументация по нпм, мы найдем точное определение пакета, если выполняется одно из следующих условий от а) до g), это пакет:
# | иллюстрировать | пример |
---|---|---|
a) | Файл package.json, содержащий программу и описание программы.папка | ./local-module/ |
b) | А, содержащий (а)gzip сжатые файлы | ./module.tar.gz |
c) | тот, который можно скачать, чтобы получить (б) ресурсurl(обычно http(s) URL) | https://registry.npmjs.org/webpack/-/webpack-4.1.0.tgz |
d) | Формат<name>@<version> Строка, указывающая на опубликованный доступный URL-адрес источника npm (обычно это официальный источник npmjs.org), который удовлетворяет условию (c) |
webpack@4.1.0 |
e) | Формат<name>@<tag> Строка, в источнике npm это<tag> указать на<version> получать<name>@<version> , последний удовлетворяет условию (d) |
webpack@latest |
f) | Формат<name> строка, добавленная по умолчаниюlatest что получает лейбл<name>@latest Условие (е) выполнено |
webpack |
g) | Одинgit url, кодовая база, на которую указывает URL, удовлетворяет условию (a) | git@github.com:webpack/webpack.git |
2.2 Установите локальный пакет / пакет удаленного хранилища Git
Определение приведенной выше таблицы означает, что когда мы делимся пакетом зависимостей, нам не нужно публиковать пакет в источнике npm, прежде чем его можно будет предоставить пользователям для установки. Это очень полезно для сценариев, когда неудобно публиковать в удаленный источник (даже частный) или официальный источник нужно модифицировать, а пакет все равно нужно расшарить.
Сценарий 1: Справочник по локальному модулю
При разработке приложений nodejs межмодульные вызовы неизбежны.Например, на практике модули конфигурации, на которые нужно часто ссылаться, часто помещаются в корневой каталог приложения, поэтому после создания многих уровней каталогов и файлов, скорее всего, такой код:
const config = require('../../../../config.js');
Помимо уродливого внешнего вида, такие ссылки на пути не годятся для рефакторинга кода. И самосовершенствование как программиста говорит нам, что такой повторяющийся код означает, что пора отделить этот модуль для совместного использования другими модулями в приложении. Например, файл config.js в этом примере очень удобен для упаковки в виде пакета и размещения в каталоге node_modules для совместного использования с другими модулями в том же приложении.
Вместо того, чтобы вручную копировать файлы или создавать символические ссылки на каталог node_modules, npm предлагает более элегантное решение.
строить планы:
-
Создайте пакет конфигурации:
Добавьте папку конфигурации, переименуйте файл config.js в файл config/index.js, создайте package.json для определения пакета конфигурации.{ "name": "config", "main": "index.js", "version": "0.1.0" }
-
Добавьте зависимости в файл package.json прикладного уровня, а затем выполните
npm install
; или сразу перейти к шагу 3{ "dependencies": { "config": "file:./config" } }
-
(эквивалентно шагу 2) Выполнить непосредственно в каталоге приложения
npm install file:./config
В этот момент см.
node_modules
В каталоге мы найдем дополнительный файл с именемconfig
, указывая на верхний уровеньconfig/
Мягкая ссылка на папку. Это потому, что npm распознаетfile:
URL-адрес протокола, зная, что этот пакет необходимо получить непосредственно из файловой системы, автоматически создаст мягкую ссылку на node_modules для завершения процесса «установки».По сравнению с ручной мягкой цепочкой нам не нужно заботиться о разнице между командами Windows и Linux, но мы также можем явно закрепить информацию о зависимостях в поле зависимостей, и другие члены команды разработчиков могут выполнить
npm install
непосредственно после использования.
Сценарий 2: частный общий пакет git
Иногда у нас в команде будут некоторые кодовые/общие библиотеки, которые должны быть в команде.между разными проектамиОбщий доступ, но может быть неудобно публиковать в источнике из-за включения конфиденциального контента или слишком плохого кода.
В этом случае мы можем просто разместить зависимый пакет в частном репозитории git, а затем сохранить URL-адрес git в зависимостях.npm будет напрямую вызывать системную команду git, чтобы вытащить содержимое пакета из репозитория git в node_modules middle.
форматы URL-адресов git, поддерживаемые npm:
<protocol>://[<user>[:<password>]@]<hostname>[:<port>][:][/]<path>[#<commit-ish> | #semver:<semver>]
После пути git вы можете использовать #, чтобы указать конкретную ветку/фиксацию/тег git, или #semver: чтобы указать определенный диапазон semver.
Например:
git+ssh://git@github.com:npm/npm.git#v1.0.27
git+ssh://git@github.com:npm/npm#semver:^5.0
git+https://isaacs@github.com/npm/npm.git
git://github.com/npm/npm.git#v1.0.27
Сценарий 3: Исправление ошибок в пакетах с открытым исходным кодом
При использовании npm пакета обнаруживается, что в нем серьезная ошибка, но, возможно, автор сначала не поддерживает код, возможно, наша работа срочная и не хватает времени, чтобы подать вопрос автору, а затем потихоньку подождите, пока автор выпустит новую исправленную версию для исходного кода npm.
На этом этапе мы можем вручную войти в каталог node_modules, чтобы изменить соответствующее содержимое пакета, и, возможно, изменить строку кода, чтобы решить проблему. Но такой подход очень неразумный!
Во-первых, сам node_modules не стоит ставить в систему контроля версий, а модификации содержимого папки node_modules не будут записываться в запись коммита git; во-вторых, даже если мы будем настаивать на антипаттерне и поставим node_modules в систему управления версиями, ваши изменения также будет легко выполнить в следующий раз, когда член командыnpm install
илиnpm update
Когда он перезаписывается, а такой коммит может содержать десятки сотен обновлений пакетов, ваши собственные модификации могут легко утонуть в огромном списке diff-файлов.
строить планы:
Лучший способ - разветвить библиотеку git исходного автора.После устранения проблемы в собственном репо измените соответствующую зависимость в зависимостях на URL-адрес git вашей исправленной версии, чтобы решить проблему. (После разветвления кодовой базы также удобно отправить PR автору исходного кода, чтобы исправить проблему. После того, как исходная кодовая база устранит проблему, еще не поздно снова обновить нашу конфигурацию зависимостей.)
3. Как работает установка npm — структура каталогов node_modules
После выполнения npm install мы можем увидеть все зависимые пакеты в node_modules. Хотя пользователям не нужно обращать внимание на детали структуры папок в этом каталоге, достаточно обратиться к зависимым пакетам в бизнес-коде, но понимание содержимого node_modules может помочь нам лучше понять, как работает npm и что отличается от npm. 2 до npm 5 и улучшения.
Для простоты предположим, что каталогом приложения является app с двумя популярными пакетами.webpack
, nconf
В качестве примера пакета зависимостей. А для обычной установки используется "древняя" версия периода npm 2webpack@1.15.0
, nconf@0.8.5
.
3.1 npm 2
npm 2 использует простой рекурсивный метод установки при установке зависимостей. воплощать в жизньnpm install
После этого npm 2 устанавливается рекурсивно по очередиwebpack
а такжеnconf
Два пакета для Node_Modules. После выполнения мы увидим ./node_modules Этот каталог слоя содержит только эти два подкаталога.
node_modules/
├── nconf/
└── webpack/
Углубившись в каталог nconf или webpack, вы увидите, что в соответствующих модулях node_modules этих двух пакетов npm рекурсивно установил свои собственные зависимости. включать./node_modules/webpack/node_modules/webpack-core
, ./node_modules/conf/node_modules/async
и т.п. И каждый пакет имеет свой собственный пакет зависимостей, и собственные зависимости каждого пакета устанавливаются в свои собственные модули node_modules. Зависимости продвигаются слой за слоем, формируя целое дерево зависимостей, которое слой за слоем соответствует дереву файловой структуры в файловой системе.
Самый удобный способ просмотреть дерево зависимостей — выполнить его прямо в каталоге приложения.npm ls
Заказ.
app@0.1.0
├─┬ nconf@0.8.5
│ ├── async@1.5.2
│ ├── ini@1.3.5
│ ├── secure-keys@1.0.0
│ └── yargs@3.32.0
└─┬ webpack@1.15.0
├── acorn@3.3.0
├── async@1.5.2
├── clone@1.0.3
├── ...
├── optimist@0.6.1
├── supports-color@3.2.3
├── tapable@0.1.10
├── uglify-js@2.7.5
├── watchpack@0.2.9
└─┬ webpack-core@0.6.9
├── source-list-map@0.1.8
└── source-map@0.4.4
Преимущество такой структуры каталогов в том, что иерархическая структура очевидна, что удобно для управления дураками:
- Например, если вы устанавливаете новый пакет зависимостей, вы можете сразу увидеть подкаталоги в node_modules первого уровня.
- Когда имя требуемого пакета и номер версии известны, можно даже вручную скопировать требуемый пакет из другой папки в папку node_modules, а затем вручную изменить конфигурацию зависимостей в package.json
- Чтобы удалить пакет, вы также можете просто вручную удалить подкаталог пакета и удалить соответствующую строку в файле package.json.
Фактически, многие люди действительно практиковали это в эпоху npm 2, и они могут успешно устанавливать и удалять без каких-либо ошибок.
Но у такой файловой структуры есть и очевидные проблемы:
- Для сложных проектов структура каталогов в node_modules может быть слишком глубокой, что приводит к слишком длинному пути к глубокому файлу и вызывает ошибку, что путь к файлу не может превышать 260 символов в файловой системе Windows.
- Некоторые пакеты, от которых зависят несколько пакетов, скорее всего, будут повторно установлены во многих местах в каталоге node_modules приложения. По мере того, как масштаб проекта становится больше, а дерево зависимостей становится все более и более сложным, таких пакетов будет все больше и больше, что приведет к значительной избыточности.
- в нашем примере есть такая проблема,webpack
а такжеnconf
зависит отasync
Этот пакет, поэтому в файловой системе и webpack, и nconf имеют один и тот же установленный асинхронный пакет и одну и ту же версию в подкаталоге node_modules.
+-------------------------------------------+
| app/ |
+----------+------------------------+-------+
| |
| |
+----------v------+ +---------v-------+
| | | |
| webpack@1.15.0 | | nconf@0.8.5 |
| | | |
+--------+--------+ +--------+--------+
| |
+-----v-----+ +-----v-----+
|async@1.5.2| |async@1.5.2|
+-----------+ +-----------+
3,2 н/мин 3 — плоская структура
В основном для решения вышеуказанных проблем каталог node_modules в npm 3 был изменен на более плоскую иерархическую структуру. в файловой системеwebpack
, nconf
, async
Иерархическая связь становится связью уровня, которая находится в каталоге того же уровня.
+-------------------------------------------+
| app/ |
+-+---------------------------------------+-+
| |
| |
+----------v------+ +-------------+ +---------v-------+
| | | | | |
| webpack@1.15.0 | | async@1.5.2 | | nconf@0.8.5 |
| | | | | |
+-----------------+ +-------------+ +-----------------+
Хотя в webpack/node_modules и nconf/node_modules больше нет папки async, благодаря механизму загрузки модулей узла они оба могут найти асинхронную библиотеку в верхнем каталоге node_modules. Итак, в коде библиотеки webpack и nconfrequire('async')
Оператор выполняется без проблем.
Это только самый простой пример.В реальном проекте дерево зависимостей неизбежно будет иметь много уровней и много зависимых пакетов.Среди них будет много пакетов с одинаковым именем, но разных версий, которые существуют на разных уровнях зависимостей.Для этих сложных В некоторых ситуациях npm 3 просматривает все дерево зависимостей во время установки и вычисляет наиболее разумный метод установки папки, чтобы можно было переустановить все пакеты, от которых постоянно зависят.
Документация npm предоставляет более наглядный пример, объясняющий эту ситуацию:
если
package{dep}
Метод записи представляет пакет и его зависимости, затемA{B,C}
,B{C}
,C{D}
Структура зависимостей node_modules после установки выглядит следующим образом:
A
+-- B
+-- C
+-- D
Причина, по которой D также устанавливается на том же уровне, что и B и C, заключается в том, что npm установит пакет на более высокий уровень, насколько это возможно, без конфликтов.
если
A{B,C}
,B{C,D@1}
,C{D@2}
Зависимости, результирующая структура после установки:
A
+-- B
+-- C
`-- D@2
+-- D@1
Это связано с тем, что для npm пакеты с одинаковым именем, но разными версиями представляют собой два отдельных пакета, и на одном уровне не может быть двух подкаталогов с одинаковыми именами, поэтому D@2 помещается в подкаталог C, а другой D@ 1 был помещен в следующую более высокую директорию.
Очевидно, что после npm 3 древовидная структура зависимостей npm больше не соответствует иерархии папок один к одному. Чтобы просмотреть прямые зависимости приложения, передайтеnpm ls
спецификация команды--depth
Параметры для просмотра:
npm ls --depth 1
PS: В отличие от локальных зависимостей, если мы проходим
npm install --global
Когда пакет устанавливается глобально в глобальный каталог, результирующий каталог по-прежнему имеет «традиционную» структуру каталогов. И если вы используете npm 3 и хотите получить «традиционную» форму локального каталога node_modules, используйтеnpm install --global-style
команда сделает.
3.3 npm 5 — файл блокировки пакета
npm 5 был выпущен в 2017 году и в настоящее время является последней версией npm. В этой версии по-прежнему используется метод установки пакетов с плоскими зависимостями после npm 3. Кроме того, самым большим изменением является увеличениеpackage-lock.json
документ.
Роль package-lock.json заключается в следующем.запираниеВ зависимости от структуры установки, если вы посмотрите на структуру этого json, вы обнаружите, что существует однозначное соответствие с файловой иерархией каталога node_modules.
Возьмите зависимости как:app{webpack}
Например, проект app имеет такой фрагмент в файле package-lock.
{
"name": "app",
"version": "0.1.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
// ... 其他依赖包
"webpack": {
"version": "1.8.11",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-1.8.11.tgz",
"integrity": "sha1-Yu0hnstBy/qcKuanu6laSYtgkcI=",
"requires": {
"async": "0.9.2",
"clone": "0.1.19",
"enhanced-resolve": "0.8.6",
"esprima": "1.2.5",
"interpret": "0.5.2",
"memory-fs": "0.2.0",
"mkdirp": "0.5.1",
"node-libs-browser": "0.4.3",
"optimist": "0.6.1",
"supports-color": "1.3.1",
"tapable": "0.1.10",
"uglify-js": "2.4.24",
"watchpack": "0.2.9",
"webpack-core": "0.6.9"
}
},
"webpack-core": {
"version": "0.6.9",
"resolved": "https://registry.npmjs.org/webpack-core/-/webpack-core-0.6.9.tgz",
"integrity": "sha1-/FcViMhVjad76e+23r3Fo7FyvcI=",
"requires": {
"source-list-map": "0.1.8",
"source-map": "0.4.4"
},
"dependencies": {
"source-map": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
"integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
"requires": {
"amdefine": "1.0.1"
}
}
}
},
//... 其他依赖包
}
}
Разобраться в файле package-lock несложно, его структура вложена несколькими однотипными полями, в основномversion
, resolved
, integrity
, requires
, dependencies
Только эти поля.
-
version
,resolved
,integrity
Используется для записи точного номера версии, хэша содержимого и источника установки пакета, что определяет точную «идентификационную» информацию об устанавливаемом пакете. - Предполагая охват других полей, сосредоточьтесь только на файлах в файле
dependencies: {}
Мы обнаружим, что иерархия зависимостей в конфигурации JSON всего файла полностью контрастирует с иерархией папок node_modules в файловой системе. - просто следуйте
requires: {}
поле будет найдено снова, за исключением самого внешнегоrequires
За исключением того, что атрибут имеет значение true, требуемые атрибуты других слоев соответствуют их собственным зависимостям, записанным в package.json этого пакета.
Поскольку этот файл записывает структуру, уровень и номера версий всех пакетов в node_modules и даже источник установки, он фактически предоставляет возможность «сохранять» состояние node_modules. Пока есть такой файл блокировки, выполнение установки npm на этой машине даст точно такой же результат node_modules.
Это сценарий, в котором файл package-lock предназначен для оптимизации: раньше для записи зависимостей использовался только package.json из-за механизма semver range; файл package.json, сгенерированный A месяц назад, B выполняет npm install в соответствии с ним через месяц Полученные результаты node_modules, вероятно, будут иметь разные различия во многих пакетах Хотя ограничение механизма semver не позволяет одному и тому же package.json получать разные версии зависимых пакетов, один и тот же код устанавливает разные зависимые упаковок в разных средах.Все еще потенциальный фактор, который может привести к несчастному случаю.
Файл с той же функцией, существовавший до npm 5, назывался файлом npm shrinkwrap, оба имеют одинаковую функцию, разница в том, что последний нужно генерировать вручную, в то время как npm 5 будет генерировать файл блокировки пакета по умолчанию после выполнения npm. install, и рекомендуется сделать коммит в репозиторий git/svn.
Файл package-lock.json также вызвал значительныйспор. В npm 5.0, если файл package-lock уже существует, если вы вручную добавите зависимость к файлу package.json, а затем выполните npm install, новая зависимость не будет установлена в node_modules, и package-lock.json также не будет установлен. будут сделаны соответствующие обновления. Такая производительность несовместима с естественной ожидаемой производительностью пользователя. Впервые в npm 5.1ReleaseЭта проблема исправлена в этой версии. Эта штука говорит нам обновиться, не использовать 5.0.
- Но все еще есть несогласные с тем, что package-lock слишком сложен, и npm также предоставляет конфигурацию отключения для этого:
npm config set package-lock false
4. Управление версиями пакетов зависимостей
Установка пакета зависимостей не означает, что все в порядке, и поддержка и обновление версии также очень важны. В этой главе представлены важные сведения об управлении обновлением пакетов зависимостей.Если версия слишком длинная, перейдите к [4.3 Передовой опыт].
4.1 semver
Важной особенностью управления зависимостями npm является использованиеСемантическое управление версиями (semver)спецификация, как зависимостьВерсияПлан управления.
semver предусматривает, что номер версии пакета должен содержать 3 числа, а формат должен бытьMAJOR.MINOR.PATCH
, означает主版本号.小版本号.修订版本号
.
- ОСНОВНАЯ соответствует итерации с большим номером версии. При внесении изменений, несовместимых со старой версией, обновите ОСНОВНОЙ номер версии.
- MINOR соответствует итерациям второстепенной версии, а номер версии MINOR обновляется при наличии модификации или обновления функции, совместимой со старой версией API.
- PATCH соответствует номеру версии, как правило, номеру версии, исправляющей ОШИБКУ.
Для авторов пакетов (издателей) npm требует, чтобы номер версии был обновлен перед публикацией. нпм предоставляетnpm version
инструмент, выполнитьnpm version major|minor|patch
Вы можете просто добавить 1 к соответствующему числу в номере версии.
Если пакет является репозиторием git,
npm version
Также автоматически создает коммит git с обновленным номером версии и тегом с именем этого номера версии.
Для референтов пакетов нам нужно использовать диапазон semver соглашения semver в зависимостях, чтобы указать номер версии или диапазон версий требуемого пакета зависимостей. npm предоставляет веб-сайт https://semver.npmjs.com для простого вычисления диапазона соответствия введенного выражения. Примеры часто используемых правил следующие:
range | имея в виду | пример |
---|---|---|
^2.2.1 |
Все более новые версии под указанным ОСНОВНЫМ номером версии | соответствовать2.2.3 , 2.3.0 ; Несоответствие1.0.3 , 3.0.1
|
~2.2.1 |
Все более новые версии под указанным номером версии MAJOR.MINOR | соответствовать2.2.3 , 2.2.9 ; Несоответствие2.3.0 , 2.4.5
|
>=2.1 |
номер версии больше или равен2.1.0
|
соответствовать2.1.2 , 3.1
|
<=2.2 |
номер версии меньше или равен2.2
|
соответствовать1.0.0 , 2.2.1 , 2.2.11
|
1.0.0 - 2.0.0 |
Номера версий от 1.0.0 (включительно) до 2.0.0 (включительно) | соответствовать1.0.0 , 1.3.4 , 2.0.0
|
Любые два правила, соединенные пробелом, представляют логику «и», то есть пересечение двух правил:
Такие как>=2.3.1 <=2.8.0
Можно читать как:>=2.3.1
а также<=2.8.0
- может соответствовать
2.3.1
,2.4.5
,2.8.0
- но не совпадают
1.0.0
,2.3.0
,2.8.1
,3.0.0
Любые два правила, пройти||
Объединено для представления логики «или», объединения двух правил:
Такие как^2 >=2.3.1 || ^3 >3.2
- может соответствовать
2.3.1
,2,8.1
,3.3.1
- но не совпадают
1.0.0
,2.2.0
,3.1.0
,4.0.0
PS: В дополнение к этим, есть следующие более интуитивно понятные способы написания диапазона номеров версий:
-
*
илиx
соответствует всем основным версиям -
1
или1.x
соответствует всем версиям с основным номером версии 1 -
1.2
или1.2.x
подходит для всех версий, начиная с 1.2
PPS: В дополнение к обычным числовым номерам версий, semver также позволяетMAJOR.MINOR.PATCH
добавить-
Затем следуют теги, разделенные точками, как теги предварительной версии -Prerelese Tags, обычно считается нестабильной и не рекомендуется для промышленного использования. Например:
1.0.0-alpha
1.0.0-beta.1
1.0.0-rc.3
Наиболее распространенные в таблице выше^1.8.11
диапазон в этом формате, потому что мы используемnpm install <package name>
При установке пакета npm по умолчанию устанавливает текущую последнюю версию, например1.8.11
, затем добавьте к номеру установленной версии префикс^
число, будет^1.8.11
Написание конфигурации зависимостей package.json означает, что она может соответствовать всем версиям выше 1.8.11 и ниже 2.0.0.
4.2 Обновление версии зависимости
Вопрос, после установки пакета зависимостей выходит новая версия, как использовать npm для обновления версии? - ответ простnpm install
илиnpm update
, но в разных версиях npm, разных файлах package.json, package-lock.json производительность установки/обновления тоже разная.
Возьмем в качестве примера webpack и сделаем следующеепомещение:
- Наши инженерные проекты
app
Зависит от вебпака - При первоначальной инициализации проекта был установлен последний на тот момент пакет webpack@1.8.0, а зависимости в package.json были настроены следующим образом:
"webpack": "^1.8.0"
- Текущая (март 2018 г.) последняя версия веб-пакета
4.2.0
, последняя подрывная версия webpack 1.x1.15.0
Если мы используем npm 3, а проект не содержит package-lock.json, то в зависимости от того, пустой ли node_modules, результат выполнения install/update будет следующим (node 6.13.1, npm 3.10.10Экологический тест):
# | package.json (BEFORE) | node_modules (BEFORE) | command (npm 3) | package.json (AFTER) | node_modules (AFTER) |
---|---|---|---|---|---|
a) | webpack: ^1.8.0 |
webpack@1.8.0 | install |
webpack: ^1.8.0 |
webpack@1.8.0 |
b) | webpack: ^1.8.0 |
нулевой | install |
webpack: ^1.8.0 |
webpack@1.15.0 |
c) | webpack: ^1.8.0 |
webpack@1.8.0 | update |
webpack: ^1.8.0 |
webpack@1.15.0 |
d) | webpack: ^1.8.0 |
нулевой | update |
webpack: ^1.8.0 |
webpack@1.15.0 |
Из этой таблицы мы можем сделать следующие выводы о npm 3:
- Если локальный модуль node_modules уже установлен, повторное выполнение установки не приведет к обновлению версии пакета, но обновление будет обновлено, а если локальный модуль node_modules пуст, выполнение установки/обновления установит пакет обновления напрямую;
- npm update всегда будет обновлять пакет, чтобы он соответствовал semver, указанному в package.json.своевременнономер версии - в данном случае
^1.8.0
Последняя версия1.15.0
- Как только package.json задан, версия веб-пакета в package.json будет упорно оставаться неизменной, независимо от того, сделаете ли вы установку или обновление npm позже.
^1.8.0
стоять на месте
Неразумная часть здесь заключается в том, что если первый человек в команде установил его в началеwebpack@1.8.0
, а новые участники, которые присоединяются к проекту, выполняют инженерный код после проверкиnpm install
будут установлены по-другому1.15.0
Версия. Хотя semver предусматривает, что дополнительный номер версии должен быть обратно совместимым (номер дополнительной версии находится под тем же номером основной версии), но в случае, если есть издатели пакетов, которые не знакомы с этим соглашением и не следуют этому соглашению и публикуют несовместимые пакеты, Могут быть ошибки, вызванные различными зависимыми средами.
Ниже представлен дебют npm 5 с package-lock.json, эффект выполнения установки/обновления такой (node 9.8.0, npm 5.7.1Экологический тест):
Следующая таблица представляет собой простое выражение, в котором опущено имя пакета webpack, для установки используется аббревиатура i, для обновления используется аббревиатура up.
# | package.json (BEFORE) | node_modules (BEFORE) | package-lock (BEFORE) | command | package.json (AFTER) | node_modules (AFTER) |
---|---|---|---|---|---|---|
a) | ^1.8.0 |
@1.8.0 | @1.8.0 | i |
^1.8.0 |
@1.8.0 |
b) | ^1.8.0 |
нулевой | @1.8.0 | i |
^1.8.0 |
@1.8.0 |
c) | ^1.8.0 |
@1.8.0 | @1.8.0 | up |
^1.15.0 |
@1.15.0 |
d) | ^1.8.0 |
нулевой | @1.8.0 | up |
^1.8.0 |
@1.15.0 |
e) | ^1.15.0 |
@ 1.8.0 (старый) | @1.15.0 | i |
^1.15.0 |
@1.15.0 |
f) | ^1.15.0 |
@ 1.8.0 (старый) | @1.15.0 | up |
^1.15.0 |
@1.15.0 |
По сравнению с npm 3 основные отличия в установке и обновлении версий зависимостей:
- Всякий раз, когда выполняется установка, npm предпочтительно устанавливает веб-пакет в соответствии с версией, указанной в package-lock, избегая ситуации б) в таблице npm 3;
- Всякий раз, когда выполняется установка/обновление, файл package-lock всегда обновляется с помощью node_modules -- (так что вы можете думать о файле package-lock как о JSON-представлении node_modules)
- Если вы выполните обновление npm после установки node_modules, номер версии в package.json также будет изменен на
^1.15.0
Видно, что npm 5.1 делает номера версий, сохраненные в package.json и package-lock.json, более унифицированными, решая различные проблемы до npm. При соблюдении передового опыта члены команды могут легко поддерживать среду, в которой код приложения и зависимости node_modules согласованы.
Все счастливы.
4.3 Передовой опыт
Подводя итог, я считаю, что в эпоху 2018 года (узел 9.8.0, npm 5.7.1) управление версиями зависимостей должно быть таким:
-
Используйте нпм:
>=5.1
версия сохранитьpackage-lock.json
Открытая конфигурация файла по умолчанию -
Initialize: используется, когда первый автор инициализирует проект
npm install <package>
Установить зависимости, сохранить по умолчанию^X.Y.Z
Зависит от диапазона в package.json; коммитpackage.json
,package-lock.json
, не сдаватьnode_modules
содержание -
Инициализировать: Участник проектапервыйПосле проверки/клонирования кода проекта выполнитеоднажды
npm install
Установить зависимости -
не хочуВручную изменить package-lock.json
-
Зависимости обновления:
- Обновление минорной версии: локальное выполнение
npm update
Обновление до новой минорной версии - Обновление основной версии: локальное выполнение
npm install <package-name>@<version>
Обновление до новой основной версии - Вы также можете вручную изменить номер версии в package.json наОбновитьверсию (больше, чем существующий номер версии) и указав желаемый семвер, затем выполнить
npm install
- После локальной проверки отсутствия проблем с новой версией после обновления,представитьновый
package.json
,package-lock.json
документ
- Обновление минорной версии: локальное выполнение
-
Зависимости понижения версии:
-
правильный:
npm install <package-name>@<old-version>
Убедившись, что проблем нет,представитьфайлы package.json и package-lock.json -
Ошибка: ручная модификация
package.json
Номер версии — это более ранняя версия semver, поэтому модификация не вступит в силу, потому что она выполняется снова.npm install
еще установитьpackage-lock.json
заблокированная версия в
-
правильный:
-
Удалить зависимости:
- Plan A:
npm uninstall <package>
и представитьpackage.json
а такжеpackage-lock.json
- План Б. Удалите пакет, который нужно удалить, из поля зависимостей в package.json, затем выполните
npm install
и представитьpackage.json
а такжеpackage-lock.json
- Plan A:
-
Каждый раз, когда кто-то фиксирует обновление package.json, package-lock.json, остальная часть команды должна выполнить svn update/git pull после получения обновления.
npm install
Скрипт для установки обновленных зависимостей
поздравляю, ты наконец-то можешь поговоритьrm -rf node_modules
&& npm install
Попрощайтесь с этой волной операций (на самом деле нет)
5. npm scripts
5.1 Основное использование
Скрипты npm — еще одна важная особенность npm. Определив скрипт в поле scripts в package.json, например:
{
"scripts": {
"echo": "echo HELLO WORLD"
}
}
мы можем пройтиnpm run echo
команда для выполнения этого сценария, как выполнение команды в оболочкеecho HELLO WORLD
то же самое, см. вывод терминалаHELLO WORLD
.
—— Основное использование скриптов npm настолько просто, что он предоставляет простой интерфейс для вызова скриптов, связанных с проектом. Для получения более подробной информации, пожалуйста, обратитесь к статье Руан Ифэн.Руководство по использованию скриптов npm (октябрь 2016 г.).
Краткое изложение содержания статьи г-на Жуана:
-
npm run
При выполнении команды будет./node_modules/.bin/
каталог, добавленный в среду выполненияPATH
переменная, поэтому, еслипакет командной строкиНе устанавливается глобально, а устанавливается только в node_modules текущего проекта черезnpm run
Эту же команду можно вызвать. - Чтобы передать параметры при выполнении скрипта npm, вам нужно добавить их после команды
--
отмечены, напримерnpm run test -- --grep="pattern"
могу--grep="pattern"
параметр, переданныйtest
Заказ - npm предоставляет два механизма перехвата, pre и post, которые могут определять сценарий выполнения до и после сценария.
- Переменные выполнения: в
npm run
В среде выполнения скриптов многие сведения, относящиеся к среде выполнения, можно получить с помощью переменных среды.process.env
Доступ к объекту получает:-
npm_lifecycle_event
- имя запущенного скрипта -
npm_package_<key>
- Получить значение конфигурации поля в текущем пакете package.json: например,npm_package_name
получить имя пакета -
npm_package_<key>_<sub-key>
- Свойства вложенных полей в package.json: напримерnpm_pacakge_dependencies_webpack
можно получить в package.jsondependencies.webpack
Значение поля, которое является номером версии webpack
-
5.2 каталог node_modules/.bin
сказано вышеnode_modules/.bin
Каталог, в котором хранятся пакеты командной строки, установленные в каталоге зависимостей и доступные для вызова.
Что такое пакет командной строки? Напримерwebpack
Он принадлежит пакету командной строки. Если мы добавим при установке вебпака--global
параметры, их можно ввести прямо в терминалеwebpack
позвонить. Но если не добавить--global
параметры, мы будемnode_modules/.bin
Увидеть файл с именем webpack в каталоге, если ввести его прямо в терминале./node_modules/.bin/webpack
команда также может быть выполнена.
Это потому чтоwebpack
существуетpackage.json
определено в файлеbin
Поля:
{
"bin": {
"webpack": "./bin/webpack.js"
}
}
Формат конфигурации поля bin:<command>: <file>
, который命令名: 可执行文件
, Когда npm выполняет установку, он анализирует package.json каждого зависимого пакета.bin
поле и установите содержащиеся в нем записи в./node_modules/.bin
каталог, имя файла<command>
. Если он установлен в глобальном режиме, он создаст указатель на каталог bin глобального пути установки npm.<file>
названный<command>
мягкая цепь. следовательно,./node_modules/.bin/webpack
Когда файл вызывается из командной строки, он фактически выполняетсяnode ./node_modules/.bin/webpack.js
Заказ.
Как указано в предыдущем разделе,npm run
При выполнении команды будет./node_modules/.bin
ПрисоединяйсяPATH
Так что мы можем напрямую вызовать все зависимые пакеты, которые предоставляют интерфейс вызова командной строки. Так что здесь приходит лучшая практика:
Установите инструмент командной строки, зависящий от проекта, в папку, зависящую от проекта, а затем вызовите его через сценарии NPM, а не через глобальную установку.
Напримерwebpack
В качестве стандартного инструмента сборки для интерфейсных проектов, хотя мы все привыкли к глобальной установке и прямому использованию вызовов командной строки, разные проекты могут зависеть от разных версий веб-пакета, соответствующихwebpack.config.js
Файл конфигурации также может быть совместим только с определенной версией веб-пакета.Если мы установим только последнюю версию веб-пакета 4.x глобально и вызовем ее с помощью команды веб-пакета, сборка не будет успешной в проекте, который зависит от веб-пакета 3.x. .
Но если такие инструменты всегда устанавливаются локально, нам нужно вызвать команду, чтобы вручную добавить./node_modules/.bin
Этот длинный префикс слишком хлопотный, а мы, разработчики nodejs, ленивы. Таким образом, npm поставляется с новым инструментом, начиная с версии 5.2.npx
.
5.3 npx
Использование npx очень простое, то есть выполнитьnpx <command>
Вот оно, здесь<command>
По умолчанию./node_modules
Имя исполняемого скрипта, установленного в каталоге. Например, локально установленный пакет webpack выше, мы можем использовать его напрямую.npx webpack
Просто выполните его.
В дополнение к этому простейшему сценарию, разработчик команды npm cli Кэт Марчан также представляет в этой статье несколько других волшебных способов использования npx:Introducing npx: an npm package runner, отечественный разработчик robin.law перевел исходный текст на китайский языкЧто такое npx и зачем вам npx?.
Если вам интересно, вы можете перейти по ссылке, чтобы понять.Если вам лень переходить по ссылке, см. резюме:
Сценарий а) Выполнение двоичных пакетов одним щелчком мыши из удаленных источников npm
Помимо выполнения установленных команд в ./node_modules/.bin в пакете, вы также можете напрямую указать имя неустановленного бинарного пакета для выполнения. Например, в каталоге без package.json и node_modules выполните:
npx cowsay hello
npx будет загружен из источника npmcowsay
этот пакет (но не установлен) и выполните:
_______
< hello >
-------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Это использование отлично подходит для 1. простого тестирования или отладки функциональности этих бинарных пакетов в источниках npm локально; 2. вызова create-react-app или yeoman для инструментов создания шаблонов, которые часто нужно использовать только один раз для каждого проекта.
PS: здесь есть пасхалки, попробуйте эту команду:
npx workin-hard
Сценарий б) Выполнение GitHub Gist одним щелчком мыши
Помните [определение пакета 2.1], упомянутое ранее,npm install <package>
Может быть URL-адресом git, содержащим действительный package.json.
Так уж получилось, что GitHub Gist также является типом репозитория git, Коллекция npx позволяет легко делиться простыми скриптами с другими, и те, у кого есть ссылка, могут выполнять их, не устанавливая скрипт в свой локальный рабочий каталог. Загрузите package.json и исполняемый бинарный скрипт в gist, запуститеnpx <gist url>
Вы можете легко выполнить команду, определенную сутью.
Предоставлен оригинальный автор Кэт Марчан.этоСуть примера, выполняет:
npx https://gist.github.com/zkat/4bc19503fe9e9309e2bfaa2c58074d32
Получите приветствие от GitHubGist.
Сценарий c) Выполнение команд с разными версиями узла
Создано с помощью npx с Арией Стюартnode
Пакеты (https://www.npmjs.com/package/node) можно комбинировать для выполнения команд с указанной версией узла в одной строке.
Например, выполнить последовательно:
npx node@4 -e "console.log(process.version)"
npx node@6 -e "console.log(process.version)"
будет выводиться отдельноv4.8.7
а такжеv6.13.0
.
Обычно эту работу выполняетnvm
Этот тип инструмента управления версиями узла делает это, ноnpx node@4
Этот метод устраняет этап ручного переключения конфигурации nvm и является более кратким и простым.
6. конфигурация нпм
6.1 npm config
npm cli предоставляетnpm config
Команда для выполнения конфигурации, связанной с npm, черезnpm config ls -l
Просмотрите все конфигурации npm, включая конфигурацию по умолчанию. Страница документации npm содержит подробные инструкции для каждого элемента конфигурации https://docs.npmjs.com/misc/config.
Команда для изменения конфигурацииnpm config set <key> <value>
, мы используем связанные общие важные конфигурации:
-
proxy
,https-proxy
: укажите прокси, используемый npm -
registry
Укажите источник, когда npm загружает установочный пакет, по умолчаниюhttps://registry.npmjs.org/
Может быть указан как частный источник реестра -
package-lock
Указывает, генерировать ли файл блокировки пакета по умолчанию. Рекомендуется оставить значение по умолчанию true. -
save
true/false указывает, следует ли сохранять пакет в качестве зависимостей после установки npm, по умолчанию установлено значение true, начиная с npm 5.
Команда для удаления указанного элемента конфигурацииnpm config delete <key>
.
6.2 npmrc-файл
За исключением использования CLInpm config
Команда показывает изменения в конфигурации npm, и вы также можете изменить конфигурацию непосредственно через файл npmrc.
К таким файлам npmrc в порядке убывания приоритета относятся:
- Файл конфигурации проекта:
/path/to/my/project/.npmrc
- Файл конфигурации уровня пользователя:
~/.npmrc
- Глобальный файл конфигурации:
$PREFIX/etc/npmrc
(которыйnpm config get globalconfig
выходной путь) - встроенный файл конфигурации npm:
/path/to/npm/npmrc
С помощью этого механизма мы можем легко создать проект и каталог.npmrc
файлы для совместного использования конфигураций, связанных с запуском npm, которые должны быть разделены между командами. Например, если нам нужно получить доступ к источнику реестра.npmjs.org через прокси-сервер в среде интрасети компании или если нам нужно получить доступ к реестру интрасети, мы можем добавить файл .npmrc в рабочий проект и отправить кодовая база.
proxy = http://proxy.example.com/
https-proxy = http://proxy.example.com/
registry = http://registry.example.com/
Поскольку область действия файла .npmrc уровня проекта находится только в этом проекте, эти конфигурации не действуют в других каталогах. Для разработчиков, работающих с ноутбуками, это хороший способ изолировать рабочие проекты компании от учебных и исследовательских проектов дома в двух разных средах.
Объедините эту функцию с~/.npm-init.js
Комбинируя конфигурацию, конкретную конфигурацию .npmrc можно комбинировать с .gitignore, README и другими файлами в скаффолде npm init, чтобы еще больше сократить ручную настройку.
6.3 ограничения версии узла
Несмотря на то, что все команды проекта используют один и тот же код, на машине разработки каждого человека может быть установлена другая версия узла, а серверная часть может не совпадать с локальной машиной разработки.
Это еще один возможный источник несогласованности, но его не так уж сложно исправить, просто декларативные ограничения + ограничения сценариев.
утверждение:пройти черезpackage.json
изengines
Свойство объявляет требования среды выполнения версии, необходимые для запуска приложения. Например, в нашем проекте используетсяasync
, await
характеристика,Ознакомьтесь с таблицей совместимостиЗная, что минимальная поддерживаемая версия — 7.6.0, указанная конфигурация движков:
{
"engines": { "node": ">=7.6.0"}
}
Сильные ограничения(Необязательно): Вышеупомянутые поля используются только в качестве предлагаемых полей в npm.Если вы хотите добавить строгие ограничения в частные проекты, вам нужно написать свой собственный скрипт-хук, чтобы читать и анализировать диапазон semver поля Engines и сравнивать его с среды выполнения Проверьте и напомните соответствующим образом.
7. Краткий обзор лучших практик npm
- Инициализировать новый проект с помощью npm-init
- Унифицированная конфигурация проекта: элементы конфигурации npm, которыми должна делиться команда, закреплённые в файле .npmrc.
- Единая операционная среда, единый package.json, единый файл package-lock
- Разумное использование разнообразных источников для установки зависимостей:
npm install <git url>|<local file>
- Используйте npm:> = версия 5.2
- Используйте сценарии npm и сценарии npx (npm: >= 5.2) для управления сценариями, связанными с приложением.
8. Дополнительная информация
Ссылаться на
- Выступление члена команды npm Эшли Уильямс на Node.js Live 2016:You Don't Know npm, до нпм 5
- Ссылка на видео на ютубе:Node.js Live (Paris) - Ashley Williams, You Don't Know npm
- Слайды для презентаций:the ag_deck
- В этой статье 2015 года описывается, как упаковать нативные модули в зависимости node_modules, используя:Build modular application with npm local modules
- Хорошее введение в package-lock.json:Everything you wanted to know about package-lock.json
- Руан Ифэнруководство по использованию скриптов npm
- Кэт Марчан представляет npx:
- оригинальныйIntroducing npx: an npm package runner
- китайский языкЧто такое npx и зачем вам npx?
Документация
- официальная документация npm, без китайского перевода
- Китайская документация пряжи хоть и является конкурентом npm, но совместима с директориями package.json и node_modules, так что эти две части тоже можно отнести:
дальнейшее чтение
- Сэм Бойер "Итак, вы хотите разработать систему управления пакетами", с независимой от языка точки зрения, знакомит со всеми аспектами системы управления пакетами:So you want to write a package manager