Сегодня, в пятой части перевода руководства по Node.js, мы завершим разбор возможностей npm, в частности, коснёмся таких вопросов, как выяснение установленных версий npm-пакетов, установка старых версий пакетов, обновление зависимостей, локальная и глобальная деинсталляция пакетов. Здесь же мы поговорим и об npx.
Часть 2: JavaScript, V8, некоторые приёмы разработки
Часть 3: Хостинг, REPL, работа с консолью, модули
Часть 4: npm, файлы package.json и package-lock.json
Часть 5: npm и npx
Выяснение версий установленных npm-пакетов
Для того чтобы узнать версии всех установленных в папке проекта npm-пакетов, включая их зависимости, выполните следующую команду:
npm list
В результате, например, может получиться следующее:
> npm list
/Users/flavio/dev/node/cowsay
└─┬ cowsay@1.3.1
├── get-stdin@5.0.1
├─┬ optimist@0.6.1
│ ├── minimist@0.0.10
│ └── wordwrap@0.0.3
├─┬ string-width@2.1.1
│ ├── is-fullwidth-code-point@2.0.0
│ └─┬ strip-ansi@4.0.0
│ └── ansi-regex@3.0.0
└── strip-eof@1.0.0
То же самое можно узнать и просмотрев файл package-lock.json
проекта, но древовидную структуру, которую выводит вышеописанная команда, удобнее просматривать.
Для того чтобы получить подобный список пакетов, установленных глобально, можно воспользоваться следующей командой:
npm list -g
Вывести только сведения о локальных пакетах верхнего уровня (то есть, тех, которые вы устанавливали самостоятельно и которые перечислены в package.json
) можно так:
npm list --depth=0
В результате, если, например, устанавливали вы только пакет cowsay, выведено будет следующее:
> npm list --depth=0
/Users/flavio/dev/node/cowsay
└── cowsay@1.3.1
Для того чтобы узнать версию конкретного пакета, воспользуйтесь следующей командой:
npm list cowsay
В результате её выполнения получится примерно следующее:
> npm list cowsay
/Users/flavio/dev/node/cowsay
└── cowsay@1.3.1
Эта команда подходит и для выяснения версий зависимостей установленных вами пакетов. При этом в качестве имени пакета, передаваемого ей, выступает имя пакета-зависимости, а вывод команды будет выглядеть следующим образом:
> npm list minimist
/Users/flavio/dev/node/cowsay
└─┬ cowsay@1.3.1
└─┬ optimist@0.6.1
└── minimist@0.0.10
Запись о пакете-зависимости в этой структуре будет выделена.
Если вы хотите узнать о том, каков номер самой свежей версии некоего пакета, доступного в npm-репозитории, вам понадобится команда следующего вида:
npm view [package_name] version
В ответ она выдаёт номер версии пакета:
> npm view cowsay version
1.3.1
Установка старых версий npm-пакетов
Установка старой версии npm-пакета может понадобиться для решения проблем совместимости. Установить нужную версию пакета из npm можно, воспользовавшись следующей конструкцией:
npm install <package>@<version>
В случае с используемым нами в качестве примера пакетом cowsay, команда npm install cowsay
установит его самую свежую версию (1.3.1 на момент написания этого материала). Если же надо установить его версию 1.2.0, воспользуемся такой командой:
npm install cowsay@1.2.0
Указывать версии можно и устанавливая глобальные пакеты:
npm install -g webpack@4.16.4
Если вам понадобится узнать о том, какие версии некоего пакета имеются в npm, сделать это можно с помощью такой конструкции:
npm view <package> versions
Вот пример результата её работы:
> npm view cowsay versions
[ '1.0.0',
'1.0.1',
'1.0.2',
'1.0.3',
'1.1.0',
'1.1.1',
'1.1.2',
'1.1.3',
'1.1.4',
'1.1.5',
'1.1.6',
'1.1.7',
'1.1.8',
'1.1.9',
'1.2.0',
'1.2.1',
'1.3.0',
'1.3.1' ]
Обновление зависимостей проекта до их самых свежих версий
Когда вы устанавливаете пакет командой вида npm install <packagename>
, из репозитория загружается самая свежая из доступных версий и помещается в папку node_modules
. При этом соответствующие записи добавляются в файлы package.json
и package-lock.json
, находящиеся в папке проекта.
Кроме того, устанавливая некий пакет, npm находит и устанавливает его зависимости.
Предположим, мы устанавливаем уже знакомый вам пакет cowsay, выполняя команду npm install cowsay
. Пакет будет установлен в папку node_modules
проекта, а в файл package.json
попадёт следующая запись:
{
"dependencies": {
"cowsay": "^1.3.1"
}
}
В package-lock.json
так же будут внесены сведения об этом пакете. Вот его фрагмент:
{
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"cowsay": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/cowsay/-/cowsay-1.3.1.tgz",
"integrity": "sha512-3PVFe6FePVtPj1HTeLin9v8WyLl+VmM1l1H/5P+BTTDkMAjufp+0F9eLjzRnOHzVAYeIYFF5po5NjRrgefnRMQ==",
"requires": {
"get-stdin": "^5.0.1",
"optimist": "~0.6.1",
"string-width": "~2.1.1",
"strip-eof": "^1.0.0"
}
}
}
}
Из этих двух файлов можно узнать, что мы установили cowsay версии 1.3.1, и то, что правило обновления пакета указано в виде ^1.3.1
. В четвёртой части этой серии материалов мы уже говорили о правилах семантического версионирования. Напомним, что такая запись означает, что npm может обновлять пакет при выходе его минорных и патч-версий.
Если, например, выходит новая минорная версия пакета и мы выполняем команду npm update
, то обновляется установленная версия пакета и при этом сведения об установленном пакете обновляются в файле package-lock.json
, а файл package.json
остаётся неизменным.
Для того чтобы узнать, вышли ли новые версии используемых в проекте пакетов, можно воспользоваться следующей командой:
npm outdated
Вот результаты выполнения этой команды для проекта, зависимости которого давно не обновлялись:
Анализ устаревших зависимостей проекта
Некоторые из доступных обновлений пакетов представляют собой их мажорные релизы, обновления до которых не произойдёт при выполнении команды npm update
. Обновление до мажорных релизов этой командой не производится, так как они (по определению) могут содержать серьёзные изменения, не отличающиеся обратной совместимостью с предыдущими мажорными релизами, а npm стремится избавить разработчика от проблем, которые может вызвать использование подобных пакетов.
Для того чтобы обновиться до новых мажорных версий всех используемых пакетов, глобально установите пакет npm-check-updates
:
npm install -g npm-check-updates
Затем запустите утилиту, предоставляемую им:
ncu -u
Эта команда обновит файл package.json
, внеся изменения в указания о подходящих версиях пакетов в разделы dependencies
и devDependencies
. Это позволит npm обновить пакеты, используемые в проекте, до новых мажорных версий после запуска команды npm update
.
Если вы хотите установить самые свежие версии пакетов для только что только что загруженного проекта, в котором пока нет папки node_modules
, то, вместо npm update
, выполните команду npm install
.
Локальная или глобальная деинсталляция пакетов
Для того чтобы деинсталлировать пакет, ранее установленный локально (с использованием команды install <package-name>
), выполните команду следующего вида:
npm uninstall <package-name>
Если пакет установлен глобально, то для его удаления нужно будет воспользоваться флагом -g
(--global
). Например, подобная команда может выглядеть так:
npm uninstall -g webpack
При выполнении подобной команды текущая папка значения не имеет.
О выборе между глобальной и локальной установкой пакетов
Когда и почему пакеты лучше всего устанавливать глобально? Для того чтобы ответить на этот вопрос, вспомним о том, чем различаются локальная и глобальная установка пакетов:
- Локальные пакеты устанавливаются в директорию, в которой выполняют команду вида
npm install <package-name>
. Такие пакеты размещаются в папкеnode_modules
, находящейся в этой директории. - Глобальные пакеты устанавливаются в особую папку (в какую точно — зависит от конкретных настроек вашей системы) вне зависимости от того, где именно выполняют команду вида
npm install -g <package-name>
.
Подключение локальных и глобальных пакетов в коде осуществляется одинаково:
require('package-name')
Итак, какой же способ установки пакетов лучше всего использовать?
В общем случае, все пакеты следует устанавливать локально. Благодаря этому, даже если у вас имеются десятки Node.js-проектов, можно обеспечить, при необходимости, использование ими различных версий одних и тех же пакетов.
Обновление глобального пакета приводит к тому, что все проекты, в которых он применяется, будут использовать его новый релиз. Несложно понять, что это, в плане поддержки проектов, может привести к настоящему кошмару, так как новые релизы некоторых пакетов могут оказаться несовместимыми с их старыми версиями.
Если у каждого проекта имеется собственная локальная версия некоего пакета, даже при том, что подобное может показаться пустой тратой ресурсов, это — очень небольшая плата за возможность избежать негативных последствий, которые могут быть вызваны несовместимостью новых версий пакетов, обновляемых централизованно, с кодом проектов.
Пакеты следует устанавливать глобально в том случае, когда они представляют собой некие утилиты, вызываемые из командной строки, которые используются во множестве проектов.
Подобные пакеты можно устанавливать и локально, запуская предоставляемые ими утилиты командной строки с использованием npx, но некоторые пакеты, всё же, лучше устанавливать глобально. К таким пакетам, которые вам, вполне возможно, знакомы, можно отнести, например, следующие:
- npm
- create-react-app
- vue-cli
- grunt-cli
- mocha
- react-native-cli
- gatsby-cli
- forever
- nodemon
Не исключено, что в вашей системе уже имеются пакеты, установленные глобально. Для того чтобы об этом узнать, воспользуйтесь следующей командой:
npm list -g --depth 0
О зависимостях проектов
Когда пакет следует рассматривать как обычную зависимость проекта, необходимую для обеспечения его функционирования, а когда — как зависимость разработки?
При установке пакета с помощью команды вида npm install <package-name>
он устанавливается как обычная зависимость. Запись о таком пакете делается в разделе dependencies
файла package.json
(до выхода npm 5 такая запись делалась только при использовании флага --save
, теперь использовать его для этого необязательно).
Использование флага --save-dev
позволяет установить пакет как зависимость разработки. Запись о нём при этом делается в разделе devDependencies
файла package.json
.
Зависимости разработки — это пакеты, которые нужны в процессе разработки проекта, в ходе его обычного функционирования они не требуются. К таким пакетам относятся, например инструменты тестирования, Webpack, Babel.
Когда проект разворачивают, используя команду npm install
в его папке, в которой имеется папка, содержащая файл package.json
, это приведёт к установке всех зависимостей, так как npm предполагает, что подобная установка выполняется для целей работы над проектом.
Поэтому, если пакет требуется развернуть в продакшне, то, при его развёртывании, нужно использовать команду npm install --production
. Благодаря флагу --production
зависимости разработки устанавливаться не будут.
Утилита npx
Сейчас мы поговорим об одной весьма мощной команде, npx, которая появилась в npm 5.2. Одной из её возможностей является запуск исполняемых файлов, входящих в состав npm-пакетов. Мы уже рассматривали использование npx для запуска подобного файла из пакета cowsay. Теперь поговорим об этом подробнее.
▍Использование npx для упрощения запуска локальных команд
Node.js-разработчики опубликовали множество исполняемых файлов (утилит) в виде пакетов, которые предполагалось устанавливать глобально, что обеспечивало удобный доступ к их возможностям, так как запускать их из командной строки можно было, просто введя имя соответствующей команды. Однако работать в такой среде было весьма некомфортно в том случае, если требовалось устанавливать разные версии одних и тех же пакетов.
Применение команды вида npx commandname
приводит к автоматическому поиску нужного файла в папке проекта node_modules
. Это избавляет от необходимости знания точного пути к подобному файлу. Так же это делает ненужной глобальную установку пакета с обеспечением доступа к нему из любого места файловой системы благодаря использованию системной переменной PATH
.
▍Выполнение утилит без необходимости их установки
В npx имеется ещё одна интереснейшая возможность, благодаря которой утилиты можно запускать без их предварительной установки. Полезно это, в основном, по следующим причинам:
- Не требуется установка утилит.
- Можно запускать разные версии одних и тех же утилит, указывая нужную версию с помощью конструкции
@version
.
Посмотрим на то, как пользоваться этим механизмом, на примере уже известной вам утилиты cowsay
. Так, если пакет cowsay установлен глобально, выполнение в командной строке команды cowsay "Hello"
приведёт к выводу в консоль «говорящей» коровы:
_______
< Hello >
-------
^__^
(oo)_______
(__) )/
||----w |
|| ||
Если же пакет cowsay не будет установлен глобально, подобная команда выдаст ошибку.
Утилита npx позволяет выполнять подобные команды без их установки. Выглядит это, в рамках нашего примера, так:
npx cowsay "Hello"
Такая команда сработает, но, хотя «говорящая» корова, по большому счёту, особой пользы не приносит, тот же самый подход можно использовать и для выполнения куда более полезных команд. Вот несколько примеров:
- Существует инструмент командной строки, предназначенный для создания и запуска Vue-приложений. С использованием npx его можно вызвать так:
npx vue create my-vue-app
. - Для создания React-приложений можно пользоваться утилитой
create-react-app
. Её вызов через npx выглядит так:npx create-react-app my-react-app
.
После загрузки и использования соответствующего кода npx его удалит.
▍Запуск JavaScript-кода с использованием различных версий Node.js
Для того чтобы запускать некий код с использованием разных версий Node.js, можно, с использованием npx, обращаться к npm-пакету node
, указывая его версию. Выглядит это так:
npx node@6 -v #v6.14.3
npx node@8 -v #v8.11.3
Это позволяет отказаться от использования инструментов наподобие nvm или других менеджеров версий Node.js.
▍Запуск произвольных фрагментов кода, доступных по некоему адресу
Npx позволяет запускать не только код, опубликованный в npm. В частности, если у вас есть ссылка на некий фрагмент кода (скажем, опубликованного на GitHub gist), запустить его можно так:
npx https://gist.github.com/zkat/4bc19503fe9e9309e2bfaa2c58074d32
Конечно, при выполнении подобного кода нельзя забывать о безопасности. Npx даёт в руки разработчика большие возможности, но они означают и большую ответственность.
▍Итоги
Сегодня мы поговорили о некоторых полезных механизмах npm и об использовании npx. На данном этапе у вас должно сложиться базовое понимание устройства npm и методов работы с этим пакетным менеджером. Если вы хотите более глубоко изучить npm — обратитесь к странице документации проекта и побольше экспериментируйте.
В следующий раз мы обсудим некоторые базовые механизмы Node.js, понимание которых необходимо для успешной разработки приложений для этой платформы.
Уважаемые читатели! Пользуетесь ли вы npx?
Автор: ru_vds