Сегодня мы публикуем четвёртую часть перевода руководства по Node.js. В этом материале мы начнём разговор об npm а также рассмотрим особенности файлов
Npm (node package manager) — это менеджер пакетов Node.js. В первой части этого материала мы уже упоминали о том, что сейчас в npm имеется более полумиллиона пакетов, что делает его самым большим в мире репозиторием кода, написанного на одном языке. Это позволяет говорить о том, что в npm можно найти пакеты, предназначенные для решения практически любых задач.
Изначально npm создавался как система управления пакетами для Node.js, но в наши дни он используется и при разработке фронтенд-проектов на JavaScript. Для взаимодействия с реестром npm используется одноимённая команда, которая даёт разработчику огромное количество возможностей.
С помощью команды
Если в проекте имеется файл
Эта команда загрузит всё, что нужно проекту, и поместит эти материалы в папку
Отдельный можно установить следующей командой:
Часто можно видеть, как эту команду используют не в таком вот простом виде, а с некоторыми флагами. Рассмотрим их:
Для обновления пакетов служит следующая команда:
Получив эту команду, npm проверит все пакеты на наличие их новых версий, и, если найдёт их новые версии, соответствующие ограничениям на версии пакетов, заданным в
Обновить можно и отдельный пакет:
В дополнение к стандартной загрузке пакетов, npm поддерживает и загрузку их определённых версий. В частности, можно заметить, что некоторые библиотеки совместимы лишь с некими крупными релизами других библиотек, то есть, если бы зависимости таких библиотек устанавливались бы без учёта версий, это могло бы нарушить их работу. Возможность установить определённую версию некоего пакета полезна и в ситуациях, когда, например, вам вполне подходит самый свежий релиз этого пакета, но оказывается, что в нём имеется ошибка. Ожидая выхода исправленной версии пакета, можно воспользоваться и его более старым но стабильным релизом.
Возможность задавать конкретные версии необходимых проекту библиотек полезна в командной разработке, когда все члены команды пользуются в точности одними и теми же библиотеками. Переход на их новые версии так же осуществляется централизованно, путём внесения изменений в файл проекта
Во всех этих случаях возможность указания версий пакетов, необходимых проекту, чрезвычайно полезна. Npm следует стандарту семантического версионирования (semver).
Файл
Например, вот как выглядят перечень скриптов, имеющийся в соответствующем разделе файла:
Весьма распространено использование этой возможности для запуска Webpack:
Такой подход даёт возможность заменить ввод длинных команд, чреватый ошибками, следующими простыми конструкциями:
При установке пакетов с использованием npm (или yarn) доступны два варианта установки: локальная и глобальная.
По умолчанию, когда для установки пакета используют команду наподобие
Глобальная установка пакетов выполняется с использованием флага
Выполняя такую команду, npm не устанавливает пакет в локальную папку проекта. Вместо этого он копирует файлы пакета в некое глобальное расположение. Куда именно попадают эти файлы?
Для того чтобы это узнать, воспользуйтесь следующей командой:
В macOS или Linux файлы пакетов могут оказаться в директории
Однако если вы используете для управления версиями Node.js nvm, путь к папке с глобальными пакетами может измениться.
Я, например, использую nvm, и вышеописанная команда сообщает мне о том, что глобальные пакеты устанавливаются по такому адресу:
Как использовать модули, установленные с помощью npm, локально или глобально, попадающие в папки
Такая команда установит библиотеку в локальную папку проекта
Для того чтобы использовать её в своём коде, достаточно импортировать её с применением команды
Как быть, если пакет представляет собой исполняемый файл?
В таком случае исполняемый файл попадёт в папку
Посмотреть на то, как выглядит работа этого механизма можно, установив пакет cowsay. Он представляет собой шуточную программу, написанную для командной строки. Если передать этому пакету какой-нибудь текст, в консоли, в стиле ASCII-арта, будет выведено изображение коровы, которая «произносит» соответствующий текст. «Озвучивать» текст могут и другие существа.
Итак, после установки пакета с использованием команды
Как их выполнять?
Конечно, можно, для вызова программы, ввести в терминале нечто вроде
Путь к пакету npx найдёт автоматически.
Файл
Вот пример простейшего файла
Как видите, он пуст. Нет жёстких требований, касающихся того, что должно присутствовать в подобном файле для некоего приложения. Единственное требование к структуре файла заключается в том, что она должна следовать правилам формата JSON. В противном случае этот файл не сможет быть прочитан программами, которые попытаются получить доступ к его содержимому.
Если вы создаёте Node.js-пакет, который собираетесь распространять через npm, то всё радикальным образом меняется, и в вашем
Вот ещё один пример
В нём задано свойство
Вот пример посложнее, который я взял из приложения-примера, написанного с использованием Vue.js:
Как видите, тут прямо-таки немеряно всего интересного. А именно, здесь можно выделить следующие свойства:
Все эти свойства используются либо npm либо другими инструментальными средствами, применяемыми в течение жизненного цикла приложения.
Поговорим о свойствах, которые можно использовать в
Большинство свойств, которые мы опишем, используются лишь для нужд репозитория npm, некоторые используются программами, которые взаимодействуют с кодом, вроде того же npm.
Свойство
Имя должно быть короче 214 символов, не должно включать в себя пробелы, должно состоять только из прописных букв, дефисов (
Подобные ограничения существуют из-за того, что когда пакет публикуется в npm, его имя используется для формирования URL страницы пакета.
Если вы публиковали код пакета на GitHub, в общем доступе, то хорошим вариантом имени пакета является имя соответствующего GitHub-репозитория.
Свойство
Оно может быть представлено и в таком формате:
Свойство
Это свойство может выглядеть и так:
В свойстве
Свойство
Свойство
При формировании значения этого свойства нужно следовать правилам семантического версионирования. Это означает, в частности, что номер версии всегда представлен тремя цифрами: x.x.x.
Первое число — это мажорная версия пакета, второе — минорная версия, третье — патч-версия.
Изменение этих чисел несёт в себе определённый смысл. Так, релиз пакета, в котором лишь исправляются ошибки, приводит к увеличению значения патч-версии. Если выходит релиз пакета, изменения, внесённые в который, отличаются обратной совместимостью с предыдущим релизом — то меняется минорная версия. В мажорных версиях пакетов могут присутствовать изменения, которые делают эти пакеты несовместимыми с пакетами предыдущих мажорных версий.
Свойство
Свойство
Правильный подбор ключевых слов помогает людям находить то, что им нужно, при поиске пакетов для решения неких задач, позволяет группировать пакеты и быстро оценивать их возможный функционал при просмотре сайта npm.
Свойство
Это свойство особенно важно в том случае, если вы планируете публиковать пакет в npm, так как оно позволяет пользователям сайта npm понять предназначение пакета.
Свойство
Обратите внимание, что у значения этого свойства имеется префикс
Используемую при разработке пакета систему контроля версий можно задать и в явном виде:
Один и тот же пакет может использовать разные системы контроля версий:
Свойство
Когда пакет импортируют в приложение, именно здесь будет осуществляться поиск того, что экспортирует соответствующий модуль.
Свойство
Свойство
Эти скрипты являются приложениями командной строки. Запускать их можно с помощью npm или yarn, выполняя, соответственно, команды вида
Скрипты можно называть так, как вам хочется, делать они могут практически всё, чего может пожелать разработчик.
Свойство
При установке пакета с использованиеме npm или yarn используются команды такого вида:
Эти пакеты автоматически добавляются в список зависимостей разрабатываемого пакета.
Свойство
Этот список отличается от того, который хранится в свойстве
Пакеты попадают в этот список при их установке с помощью npm или yarn, выполняемой следующим образом:
Свойство
Свойство
Этим свойством пользуются Babel, Autoprefixer и другие инструменты. Анализ этого списка позволяет им добавлять в пакет только те полифиллы и вспомогательные механизмы, которые нужны для перечисленных браузеров.
Показанное здесь в качестве примера значение свойства
В
Каждому из таких инструментов соответствует особое свойство, наподобие
В вышеприведённых примерах вы могли видеть, что номера версий пакетов задаются не только в виде обычных чисел, разделённых точками, но и с использованием неких специальных символов. Например, в виде
Учитывая то, что при использовании семантического версионирования все номера версий пакетов состоят из последовательностей, представляющих собой три числа, о смысле которых мы говорили выше, опишем следующие правила использования спецификаторов версий:
Есть и ещё некоторые правила:
Большинство вышеописанных спецификаторов можно комбинировать, например, задавая диапазоны подходящих версий пакетов-зависимостей. Скажем, конструкция вида
Файл
Цель этого файла заключается в отслеживании точных версий установленных пакетов, что позволяет сделать разрабатываемый продукт стопроцентно воспроизводимым в его исходном виде даже в случае, если те, кто занимается поддержкой пакетов, их обновили.
Этот файл решает весьма специфическую проблему, которая не решается средствами
В Git не коммитят папку
То же самое касается и спецификатора
Итак, кто-то пытается инициализировать проект, пользуясь командой
Файл
Эта концепция не нова, менеджеры пакетов, применяемые в других языках программирования (вроде менеджера Composer в PHP) используют похожую систему многие годы.
Файл
Версии зависимостей будут обновлены в
В этом примере продемонстрирована структура файла
Разберём этот файл. Мы устанавливаем пакет cowsay, который зависит от следующих пакетов:
Эти пакеты, в свою очередь, зависят от других пакетов, сведения о которых мы можем почерпнуть из свойств
Они добавляются в файл в алфавитном порядке, у каждого есть поле
Сегодня мы начали разговор об npm и разобрались со структурой и назначением файлов
Уважаемые читатели! Какой менеджер пакетов вы предпочитаете — npm или yarn?
package.json
и package-lock.json
.[Советуем почитать] Другие части цикла
Часть 1: Общие сведения и начало работы
Часть 2: JavaScript, V8, некоторые приёмы разработки
Часть 3: Хостинг, REPL, работа с консолью, модули
Часть 4: npm, файлы package.json и package-lock.json
Часть 5: npm и npx
Часть 6: цикл событий, стек вызовов, таймеры
Часть 7: асинхронное программирование
Часть 8: Руководство по Node.js, часть 8: протоколы HTTP и WebSocket
Часть 9: Руководство по Node.js, часть 9: работа с файловой системой
Часть 10: Руководство по Node.js, часть 10: стандартные модули, потоки, базы данных, NODE_ENV
Полная PDF-версия руководства по Node.js
Часть 2: JavaScript, V8, некоторые приёмы разработки
Часть 3: Хостинг, REPL, работа с консолью, модули
Часть 4: npm, файлы package.json и package-lock.json
Часть 5: npm и npx
Часть 6: цикл событий, стек вызовов, таймеры
Часть 7: асинхронное программирование
Часть 8: Руководство по Node.js, часть 8: протоколы HTTP и WebSocket
Часть 9: Руководство по Node.js, часть 9: работа с файловой системой
Часть 10: Руководство по Node.js, часть 10: стандартные модули, потоки, базы данных, NODE_ENV
Полная PDF-версия руководства по Node.js
Основы npm
Npm (node package manager) — это менеджер пакетов Node.js. В первой части этого материала мы уже упоминали о том, что сейчас в npm имеется более полумиллиона пакетов, что делает его самым большим в мире репозиторием кода, написанного на одном языке. Это позволяет говорить о том, что в npm можно найти пакеты, предназначенные для решения практически любых задач.
Изначально npm создавался как система управления пакетами для Node.js, но в наши дни он используется и при разработке фронтенд-проектов на JavaScript. Для взаимодействия с реестром npm используется одноимённая команда, которая даёт разработчику огромное количество возможностей.
▍Загрузка пакетов
С помощью команды
npm
можно загружать пакеты из реестра. Ниже мы рассмотрим примеры её использования.▍Установка всех зависимостей проекта
Если в проекте имеется файл
package.json
, то установить все зависимости этого проекта можно такой командой:npm install
Эта команда загрузит всё, что нужно проекту, и поместит эти материалы в папку
node_modules
, создав её в том случае, если она не существует в директории проекта.▍Установка отдельного пакета
Отдельный можно установить следующей командой:
npm install <package-name>
Часто можно видеть, как эту команду используют не в таком вот простом виде, а с некоторыми флагами. Рассмотрим их:
- Флаг
--save
позволяет установить пакет и добавить запись о нём в разделdependencies
файлаpackage.json
, который описывает зависимости проекта. Эти зависимости используются проектом для реализации его основного функционала, они устанавливаются в ходе его развёртывания на сервере (после выхода npm 5 записи об устанавливаемых пакетах в разделе зависимостей делаются автоматически, и без использования этого флага). - Флаг
--save-dev
позволяет установить пакет и добавить запись о нём в раздел, содержащий перечень зависимостей разработки (то есть — пакетов, которые нужны в ходе разработки проекта, вроде библиотек для тестирования, но не требуются для его работы) файлаpackage.json
, который называетсяdevDependencies
.
▍Обновление пакетов
Для обновления пакетов служит следующая команда:
npm update
Получив эту команду, npm проверит все пакеты на наличие их новых версий, и, если найдёт их новые версии, соответствующие ограничениям на версии пакетов, заданным в
package.json
, установит их.Обновить можно и отдельный пакет:
npm update <package-name>
▍Загрузка пакетов определённых версий
В дополнение к стандартной загрузке пакетов, npm поддерживает и загрузку их определённых версий. В частности, можно заметить, что некоторые библиотеки совместимы лишь с некими крупными релизами других библиотек, то есть, если бы зависимости таких библиотек устанавливались бы без учёта версий, это могло бы нарушить их работу. Возможность установить определённую версию некоего пакета полезна и в ситуациях, когда, например, вам вполне подходит самый свежий релиз этого пакета, но оказывается, что в нём имеется ошибка. Ожидая выхода исправленной версии пакета, можно воспользоваться и его более старым но стабильным релизом.
Возможность задавать конкретные версии необходимых проекту библиотек полезна в командной разработке, когда все члены команды пользуются в точности одними и теми же библиотеками. Переход на их новые версии так же осуществляется централизованно, путём внесения изменений в файл проекта
package.json
.Во всех этих случаях возможность указания версий пакетов, необходимых проекту, чрезвычайно полезна. Npm следует стандарту семантического версионирования (semver).
▍Запуск скриптов
Файл
package.json
поддерживает возможность описания команд (скриптов), запускать которые можно с помощью такой конструкции:npm <task-name>
Например, вот как выглядят перечень скриптов, имеющийся в соответствующем разделе файла:
{
"scripts": {
"start-dev": "node lib/server-development",
"start": "node lib/server-production"
}
}
Весьма распространено использование этой возможности для запуска Webpack:
{
"scripts": {
"watch": "webpack --watch --progress --colors --config webpack.conf.js",
"dev": "webpack --progress --colors --config webpack.conf.js",
"prod": "NODE_ENV=production webpack -p --config webpack.conf.js",
}
}
Такой подход даёт возможность заменить ввод длинных команд, чреватый ошибками, следующими простыми конструкциями:
$ npm watch
$ npm dev
$ npm prod
▍Куда npm устанавливает пакеты?
При установке пакетов с использованием npm (или yarn) доступны два варианта установки: локальная и глобальная.
По умолчанию, когда для установки пакета используют команду наподобие
npm install lodash
, пакет оказывается в папке node_modules
, расположенной в папке проекта. Кроме того, если была выполнена вышеописанная команда, npm также добавит запись о библиотеке lodash
в раздел dependencies
файла package.json
, который имеется в текущей директории.Глобальная установка пакетов выполняется с использованием флага
-g
:npm install -g lodash
Выполняя такую команду, npm не устанавливает пакет в локальную папку проекта. Вместо этого он копирует файлы пакета в некое глобальное расположение. Куда именно попадают эти файлы?
Для того чтобы это узнать, воспользуйтесь следующей командой:
npm root -g
В macOS или Linux файлы пакетов могут оказаться в директории
/usr/local/lib/node_modules
. В Windows это может быть нечто вроде C:\Users\YOU\AppData\Roaming\npm\node_modules
.Однако если вы используете для управления версиями Node.js nvm, путь к папке с глобальными пакетами может измениться.
Я, например, использую nvm, и вышеописанная команда сообщает мне о том, что глобальные пакеты устанавливаются по такому адресу:
/Users/flavio/.nvm/versions/node/v8.9.0/lib/node_modules
.▍Использование и выполнение пакетов, установленных с помощью npm
Как использовать модули, установленные с помощью npm, локально или глобально, попадающие в папки
node_modules
? Предположим, вы установили популярную библиотеку lodash
, содержащую множество вспомогательных функций, используемых в JavaScript-разработке:npm install lodash
Такая команда установит библиотеку в локальную папку проекта
node_modules
.Для того чтобы использовать её в своём коде, достаточно импортировать её с применением команды
require
:const _ = require('lodash')
Как быть, если пакет представляет собой исполняемый файл?
В таком случае исполняемый файл попадёт в папку
node_modules/.bin/ folder
.Посмотреть на то, как выглядит работа этого механизма можно, установив пакет cowsay. Он представляет собой шуточную программу, написанную для командной строки. Если передать этому пакету какой-нибудь текст, в консоли, в стиле ASCII-арта, будет выведено изображение коровы, которая «произносит» соответствующий текст. «Озвучивать» текст могут и другие существа.
Итак, после установки пакета с использованием команды
npm install cowsay
, он, вместе со своими зависимостями, попадёт в node_modules
. А в скрытую папку .bin
будут записаны символические ссылки на бинарные файлы cowsay.Как их выполнять?
Конечно, можно, для вызова программы, ввести в терминале нечто вроде
./node_modules/.bin/cowsay
, это рабочий подход, но гораздо лучше воспользоваться npx, средством для запуска исполняемых файлов npm-пакетов, включаемым в npm начиная с версии 5.2. А именно, в нашем случае понадобится такая команда:npx cowsay
Путь к пакету npx найдёт автоматически.
Файл package.json
Файл
package.json
является важнейшим элементов множества проектов, основанных на экосистеме Node.js. Если вы программировали на JavaScript, была ли это серверная или клиентская разработка, то вы, наверняка, уже встречались с этим файлом. Зачем он нужен? Что вам следует о нём знать и какие возможности он вам даёт?Package.json
представляет собой нечто вроде файла-манифеста для проекта. Он даёт в распоряжение разработчика множество разноплановых возможностей. Например, он представляет собой центральный репозиторий настроек для инструментальных средств, используемых в проекте. Кроме того, он является тем местом, куда npm и yarn записывают сведения об именах и версиях установленных пакетов.▍Структура файла
Вот пример простейшего файла
package.json
:{
}
Как видите, он пуст. Нет жёстких требований, касающихся того, что должно присутствовать в подобном файле для некоего приложения. Единственное требование к структуре файла заключается в том, что она должна следовать правилам формата JSON. В противном случае этот файл не сможет быть прочитан программами, которые попытаются получить доступ к его содержимому.
Если вы создаёте Node.js-пакет, который собираетесь распространять через npm, то всё радикальным образом меняется, и в вашем
package.json
должен быть набор свойств, которые помогут другим людям пользоваться пакетом. Подробнее мы поговорим об этом позже.Вот ещё один пример
package.json
:{
"name": "test-project"
}
В нём задано свойство
name
, значением которого является имя приложения или пакета, материалы которого содержатся в той же папке, где находится этот файл.Вот пример посложнее, который я взял из приложения-примера, написанного с использованием Vue.js:
{
"name": "test-project",
"version": "1.0.0",
"description": "A Vue.js project",
"main": "src/main.js",
"private": true,
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"start": "npm run dev",
"unit": "jest --config test/unit/jest.conf.js --coverage",
"test": "npm run unit",
"lint": "eslint --ext .js,.vue src test/unit",
"build": "node build/build.js"
},
"dependencies": {
"vue": "^2.5.2"
},
"devDependencies": {
"autoprefixer": "^7.1.2",
"babel-core": "^6.22.1",
"babel-eslint": "^8.2.1",
"babel-helper-vue-jsx-merge-props": "^2.0.3",
"babel-jest": "^21.0.2",
"babel-loader": "^7.1.1",
"babel-plugin-dynamic-import-node": "^1.2.0",
"babel-plugin-syntax-jsx": "^6.18.0",
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.0",
"babel-plugin-transform-runtime": "^6.22.0",
"babel-plugin-transform-vue-jsx": "^3.5.0",
"babel-preset-env": "^1.3.2",
"babel-preset-stage-2": "^6.22.0",
"chalk": "^2.0.1",
"copy-webpack-plugin": "^4.0.1",
"css-loader": "^0.28.0",
"eslint": "^4.15.0",
"eslint-config-airbnb-base": "^11.3.0",
"eslint-friendly-formatter": "^3.0.0",
"eslint-import-resolver-webpack": "^0.8.3",
"eslint-loader": "^1.7.1",
"eslint-plugin-import": "^2.7.0",
"eslint-plugin-vue": "^4.0.0",
"extract-text-webpack-plugin": "^3.0.0",
"file-loader": "^1.1.4",
"friendly-errors-webpack-plugin": "^1.6.1",
"html-webpack-plugin": "^2.30.1",
"jest": "^22.0.4",
"jest-serializer-vue": "^0.3.0",
"node-notifier": "^5.1.2",
"optimize-css-assets-webpack-plugin": "^3.2.0",
"ora": "^1.2.0",
"portfinder": "^1.0.13",
"postcss-import": "^11.0.0",
"postcss-loader": "^2.0.8",
"postcss-url": "^7.2.1",
"rimraf": "^2.6.0",
"semver": "^5.3.0",
"shelljs": "^0.7.6",
"uglifyjs-webpack-plugin": "^1.1.1",
"url-loader": "^0.5.8",
"vue-jest": "^1.0.2",
"vue-loader": "^13.3.0",
"vue-style-loader": "^3.0.1",
"vue-template-compiler": "^2.5.2",
"webpack": "^3.6.0",
"webpack-bundle-analyzer": "^2.9.0",
"webpack-dev-server": "^2.9.1",
"webpack-merge": "^4.1.0"
},
"engines": {
"node": ">= 6.0.0",
"npm": ">= 3.0.0"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}
Как видите, тут прямо-таки немеряно всего интересного. А именно, здесь можно выделить следующие свойства:
name
— задаёт имя приложения (пакета).version
— содержит сведения о текущей версии приложения.description
— краткое описание приложения.main
— задаёт точку входа в приложение.private
— если данное свойство установлено вtrue
, это позволяет предотвратить случайную публикацию пакета в npm.scripts
— задаёт набор Node.js-скриптов, которые можно запускать.dependencies
— содержит список npm-пакетов, от которых зависит приложение.devDependencies
— содержит список npm-пакетов, используемых при разработке проекта, но не при его реальной работе.engines
— задаёт список версий Node.js, на которых работает приложение.browserlist
— используется для хранения списка браузеров (и их версий), которые должно поддерживать приложение.
Все эти свойства используются либо npm либо другими инструментальными средствами, применяемыми в течение жизненного цикла приложения.
▍Свойства, используемые в package.json
Поговорим о свойствах, которые можно использовать в
package.json
. Здесь мы будем использовать термин «пакет», но всё, что сказано о пакетах, справедливо и для локальных приложений, которые не планируется использовать в роли пакетов.Большинство свойств, которые мы опишем, используются лишь для нужд репозитория npm, некоторые используются программами, которые взаимодействуют с кодом, вроде того же npm.
Свойство name
Свойство
name
задаёт имя пакета:"name": "test-project"
Имя должно быть короче 214 символов, не должно включать в себя пробелы, должно состоять только из прописных букв, дефисов (
-
) и символов подчёркивания (_
).Подобные ограничения существуют из-за того, что когда пакет публикуется в npm, его имя используется для формирования URL страницы пакета.
Если вы публиковали код пакета на GitHub, в общем доступе, то хорошим вариантом имени пакета является имя соответствующего GitHub-репозитория.
Свойство author
Свойство
author
содержит сведения об авторе пакета:{
"author": "Flavio Copes <flavio@flaviocopes.com> (https://flaviocopes.com)"
}
Оно может быть представлено и в таком формате:
{
"author": {
"name": "Flavio Copes",
"email": "flavio@flaviocopes.com",
"url": "https://flaviocopes.com"
}
}
Свойство contributors
Свойство
contributors
содержит массив со сведениями о людях, внёсших вклад в проект:{
"contributors": [
"Flavio Copes <flavio@flaviocopes.com> (https://flaviocopes.com)"
]
}
Это свойство может выглядеть и так:
{
"contributors": [
{
"name": "Flavio Copes",
"email": "flavio@flaviocopes.com",
"url": "https://flaviocopes.com"
}
]
}
Свойство bugs
В свойстве
bugs
содержится ссылка на баг-трекер проекта, весьма вероятно то, что такая ссылка будет вести на страницу системы отслеживания ошибок GitHub:{
"bugs": "https://github.com/flaviocopes/package/issues"
}
Свойство homepage
Свойство
homepage
позволяет задать домашнюю страницу пакета:{
"homepage": "https://flaviocopes.com/package"
}
Свойство version
Свойство
version
содержит сведения о текущей версии пакета:"version": "1.0.0"
При формировании значения этого свойства нужно следовать правилам семантического версионирования. Это означает, в частности, что номер версии всегда представлен тремя цифрами: x.x.x.
Первое число — это мажорная версия пакета, второе — минорная версия, третье — патч-версия.
Изменение этих чисел несёт в себе определённый смысл. Так, релиз пакета, в котором лишь исправляются ошибки, приводит к увеличению значения патч-версии. Если выходит релиз пакета, изменения, внесённые в который, отличаются обратной совместимостью с предыдущим релизом — то меняется минорная версия. В мажорных версиях пакетов могут присутствовать изменения, которые делают эти пакеты несовместимыми с пакетами предыдущих мажорных версий.
Свойство license
Свойство
license
содержит сведения о лицензии пакета:"license": "MIT"
Свойство keywords
Свойство
keywords
содержит массив ключевых слов, имеющих отношение к функционалу пакета:"keywords": [
"email",
"machine learning",
"ai"
]
Правильный подбор ключевых слов помогает людям находить то, что им нужно, при поиске пакетов для решения неких задач, позволяет группировать пакеты и быстро оценивать их возможный функционал при просмотре сайта npm.
Свойство description
Свойство
description
содержит краткое описание пакета:"description": "A package to work with strings"
Это свойство особенно важно в том случае, если вы планируете публиковать пакет в npm, так как оно позволяет пользователям сайта npm понять предназначение пакета.
Свойство repository
Свойство
repository
указывает на то, где находится репозиторий пакета:"repository": "github:flaviocopes/testing",
Обратите внимание, что у значения этого свойства имеется префикс
github
. Npm поддерживает префиксы и для некоторых других популярных сервисов подобного рода:"repository": "gitlab:flaviocopes/testing",
"repository": "bitbucket:flaviocopes/testing",
Используемую при разработке пакета систему контроля версий можно задать и в явном виде:
"repository": {
"type": "git",
"url": "https://github.com/flaviocopes/testing.git"
}
Один и тот же пакет может использовать разные системы контроля версий:
"repository": {
"type": "svn",
"url": "..."
}
Свойство main
Свойство
main
задаёт точку входа в пакет:"main": "src/main.js"
Когда пакет импортируют в приложение, именно здесь будет осуществляться поиск того, что экспортирует соответствующий модуль.
Свойство private
Свойство
private
, установленное в true
, позволяет предотвратить случайную публикацию пакета в npm:"private": true
Свойство scripts
Свойство
scripts
задаёт список скриптов или утилит, которые можно запускать средствами npm:"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"start": "npm run dev",
"unit": "jest --config test/unit/jest.conf.js --coverage",
"test": "npm run unit",
"lint": "eslint --ext .js,.vue src test/unit",
"build": "node build/build.js"
}
Эти скрипты являются приложениями командной строки. Запускать их можно с помощью npm или yarn, выполняя, соответственно, команды вида
npm run XXXX
или yarn XXXX
, где XXXX
— имя скрипта. Например, выглядеть это может так:npm run dev
Скрипты можно называть так, как вам хочется, делать они могут практически всё, чего может пожелать разработчик.
Свойство dependencies
Свойство
dependencies
содержит список npm-пакетов, установленных в виде зависимостей пакета:"dependencies": {
"vue": "^2.5.2"
}
При установке пакета с использованиеме npm или yarn используются команды такого вида:
npm install <PACKAGENAME>
yarn add <PACKAGENAME>
Эти пакеты автоматически добавляются в список зависимостей разрабатываемого пакета.
Свойство devDependencies
Свойство
devDependencies
содержит список npm-пакетов, установленных как зависимости разработки:"devDependencies": {
"autoprefixer": "^7.1.2",
"babel-core": "^6.22.1"
}
Этот список отличается от того, который хранится в свойстве
dependencies
, так как имеющиеся в нём пакеты устанавливаются лишь в системе разработчика пакета, при практическом использовании пакета они не применяются.Пакеты попадают в этот список при их установке с помощью npm или yarn, выполняемой следующим образом:
npm install --dev <PACKAGENAME>
yarn add --dev <PACKAGENAME>
Свойство engines
Свойство
engines
указывает, какие версии Node.js и других программных продуктов используются для обеспечения работы пакета:"engines": {
"node": ">= 6.0.0",
"npm": ">= 3.0.0",
"yarn": "^0.13.0"
}
Свойство browserlist
Свойство
browserlist
позволяет сообщить о том, какие браузеры (и их версии) собирается поддерживать разработчик пакета:"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
Этим свойством пользуются Babel, Autoprefixer и другие инструменты. Анализ этого списка позволяет им добавлять в пакет только те полифиллы и вспомогательные механизмы, которые нужны для перечисленных браузеров.
Показанное здесь в качестве примера значение свойства
browserlist
означает, что вы хотите поддерживать как минимум 2 мажорные версии всех браузеров с как минимум 1% использования (эти данные берутся с ресурса CanIUse.com), за исключением IE 8 и более старых версий этого браузера (подробнее об этом можно узнать на странице пакета browserlists).▍Хранение в package.json настроек для различных программных инструментов
В
package.json
можно хранить настройки для различных вспомогательных инструментов вроде Babel или ESLint.Каждому из таких инструментов соответствует особое свойство, наподобие
eslintConfig
или babel
. Подробности об использовании подобных свойств можно найти в документации соответствующих проектов.▍О версиях пакетов и семантическом версионировании
В вышеприведённых примерах вы могли видеть, что номера версий пакетов задаются не только в виде обычных чисел, разделённых точками, но и с использованием неких специальных символов. Например, в виде
~3.0.0
или ^0.13.0
. Здесь использованы так называемые спецификаторы версий, которые определяют диапазон версий пакетов, подходящих для использования в нашем пакете.Учитывая то, что при использовании семантического версионирования все номера версий пакетов состоят из последовательностей, представляющих собой три числа, о смысле которых мы говорили выше, опишем следующие правила использования спецификаторов версий:
~
: если вы задаёте версию в виде~0.13.0
это означает, что вас интересуют лишь патч-релизы пакета. То есть, пакет0.13.1
вам подойдёт, а0.14.0
— нет.^
: если номер версии задан в виде^0.13.0
, это означает, что вам подходят новые патч-версии и минорные версии пакета. То есть, вас устроят версии пакета0.13.1
,0.14.0
, и так далее.*
: воспользовавшись этим символом, вы сообщаете системе, что вас устроят любые свежие версии пакета, в том числе — его новые мажорные релизы.>
: подходят любые версии пакета, которые больше заданной.>=
: подходят любые версии пакета, которые равны или больше заданной.<=
: вас устроят пакеты, версии которых равны заданной или меньше её.<
: вас интересуют пакеты, версии которых меньше заданной.=
: вам нужна только заданная версия пакета.-
: используется для указания диапазона подходящих версий, например —2.1.0 - 2.6.2
.||
: позволяет комбинировать наборы условий, касающихся пакетов. Например это может выглядеть как< 2.1 || > 2.6
.
Есть и ещё некоторые правила:
- отсутствие дополнительных символов: если используется номер версии пакета без дополнительных символов, это значит, что вашему пакету нужна только заданная версия пакета-зависимости и никакая другая.
latest
: указывает на то, что вам требуется самая свежая версия некоего пакета.
Большинство вышеописанных спецификаторов можно комбинировать, например, задавая диапазоны подходящих версий пакетов-зависимостей. Скажем, конструкция вида
1.0.0 || >=1.1.0 <1.2.0
указывает на то, что планируется использовать либо версию пакета 1.0.0
, либо версию, номер которой больше или равен 1.1.0
, но меньше 1.2.0
.Файл package-lock.json
Файл
package-lock.json
используется с момента появления npm версии 5. Он создаётся автоматически при установке Node.js-пакетов. Что это за файл? Возможно, вы не знакомы с ним даже если знали о package.json
, который существует гораздо дольше него.Цель этого файла заключается в отслеживании точных версий установленных пакетов, что позволяет сделать разрабатываемый продукт стопроцентно воспроизводимым в его исходном виде даже в случае, если те, кто занимается поддержкой пакетов, их обновили.
Этот файл решает весьма специфическую проблему, которая не решается средствами
package.json
. В package.json
можно указать, какие обновления некоего пакета вам подходят (патч-версии или минорные версии) с использованием вышеописанных спецификаторов версий. В Git не коммитят папку
node_modules
, так как обычно она имеет огромные размеры. Когда вы пытаетесь воссоздать проект на другом компьютере, то использование команды npm install
приведёт к тому, что, если, при использовании спецификатора ~
в применении к версии некоего пакета, вышел его патч-релиз, установлен будет не тот пакет, который использовался при разработке, а именно этот патч-релиз.То же самое касается и спецификатора
^
. Если же при указании версии пакета спецификаторы не использовались, то будет установлена именно его указанная версия и проблема, о которой идёт речь, окажется в такой ситуации неактуальной.Итак, кто-то пытается инициализировать проект, пользуясь командой
npm install
. При выходе новых версий пакетов окажется, что этот проект отличается от исходного. Даже если, следуя правилам семантического версионирования, минорные релизы и патч-релизы не должны содержать в себе изменений, препятствующих обратной совместимости, все мы знаем, что ошибки способны проникать (и проникают) куда угодно.Файл
package-lock.json
хранит в неизменном виде сведения о версии каждого установленного пакета и npm будет использовать именно эти версии пакетов при выполнении команды npm install
.Эта концепция не нова, менеджеры пакетов, применяемые в других языках программирования (вроде менеджера Composer в PHP) используют похожую систему многие годы.
Файл
package-lock.json
нужно отправить в Git-репозиторий, что позволит другим людям скачать его в том случае, если проект является общедоступным, или тогда, когда его разработкой занимается команда программистов, или если вы используете Git для развёртывания проекта.Версии зависимостей будут обновлены в
package-lock.json
после выполнения команды npm update
.▍Пример файла package-lock.json
В этом примере продемонстрирована структура файла
package-lock.json
, который входит в состав пакет cowsay, устанавливаемого в пустой папке командой npm install cowsay
:{
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"ansi-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.
0.0.tgz",
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
},
"cowsay": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/cowsay/-/cowsay-1.3.1.tgz"
,
"integrity": "sha512-3PVFe6FePVtPj1HTeLin9v8WyLl+VmM1l1H/5P+BTTDkM
Ajufp+0F9eLjzRnOHzVAYeIYFF5po5NjRrgefnRMQ==",
"requires": {
"get-stdin": "^5.0.1",
"optimist": "~0.6.1",
"string-width": "~2.1.1",
"strip-eof": "^1.0.0"
}
},
"get-stdin": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.
1.tgz",
"integrity": "sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g="
},
"is-fullwidth-code-point": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/
is-fullwidth-code-point-2.0.0.tgz",
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
},
"minimist": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10
.tgz",
"integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8="
},
"optimist": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
"integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
"requires": {
"minimist": "~0.0.1",
"wordwrap": "~0.0.2"
}
},
"string-width": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
"requires": {
"is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^4.0.0"
}
},
"strip-ansi": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
"requires": {
"ansi-regex": "^3.0.0"
}
},
"strip-eof": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="
},
"wordwrap": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
"integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc="
}
}
}
Разберём этот файл. Мы устанавливаем пакет cowsay, который зависит от следующих пакетов:
- get-stdin
- optimist
- string-width
- strip-eof
Эти пакеты, в свою очередь, зависят от других пакетов, сведения о которых мы можем почерпнуть из свойств
requires
, которые имеются у некоторых из них:- ansi-regex
- is-fullwidth-code-point
- minimist
- wordwrap
- strip-eof
Они добавляются в файл в алфавитном порядке, у каждого есть поле
version
, есть поле resolved
, указывающее на расположение пакета, и строковое свойство integrity
, которое можно использовать для проверки целостности пакета.Итоги
Сегодня мы начали разговор об npm и разобрались со структурой и назначением файлов
package.json
и package-lock.json
. В следующий раз продолжим разбирать возможности npm и коснёмся использования npx.Уважаемые читатели! Какой менеджер пакетов вы предпочитаете — npm или yarn?