Как установить зависимости в node js

Руководство по Node.js, часть 4: npm, файлы package.json и package-lock.json

Сегодня мы публикуем четвёртую часть перевода руководства по Node.js. В этом материале мы начнём разговор об npm а также рассмотрим особенности файлов package.json и package-lock.json .

Основы npm

Npm (node package manager) — это менеджер пакетов Node.js. В первой части этого материала мы уже упоминали о том, что сейчас в npm имеется более полумиллиона пакетов, что делает его самым большим в мире репозиторием кода, написанного на одном языке. Это позволяет говорить о том, что в npm можно найти пакеты, предназначенные для решения практически любых задач.

Изначально npm создавался как система управления пакетами для Node.js, но в наши дни он используется и при разработке фронтенд-проектов на JavaScript. Для взаимодействия с реестром npm используется одноимённая команда, которая даёт разработчику огромное количество возможностей.

▍Загрузка пакетов

С помощью команды npm можно загружать пакеты из реестра. Ниже мы рассмотрим примеры её использования.

▍Установка всех зависимостей проекта

Если в проекте имеется файл package.json , то установить все зависимости этого проекта можно такой командой:

Эта команда загрузит всё, что нужно проекту, и поместит эти материалы в папку node_modules , создав её в том случае, если она не существует в директории проекта.

▍Установка отдельного пакета

Отдельный можно установить следующей командой:

Часто можно видеть, как эту команду используют не в таком вот простом виде, а с некоторыми флагами. Рассмотрим их:

  • Флаг —save позволяет установить пакет и добавить запись о нём в раздел dependencies файла package.json , который описывает зависимости проекта. Эти зависимости используются проектом для реализации его основного функционала, они устанавливаются в ходе его развёртывания на сервере (после выхода npm 5 записи об устанавливаемых пакетах в разделе зависимостей делаются автоматически, и без использования этого флага).
  • Флаг —save-dev позволяет установить пакет и добавить запись о нём в раздел, содержащий перечень зависимостей разработки (то есть — пакетов, которые нужны в ходе разработки проекта, вроде библиотек для тестирования, но не требуются для его работы) файла package.json , который называется devDependencies .

▍Обновление пакетов

Для обновления пакетов служит следующая команда:

Получив эту команду, npm проверит все пакеты на наличие их новых версий, и, если найдёт их новые версии, соответствующие ограничениям на версии пакетов, заданным в package.json , установит их.

Обновить можно и отдельный пакет:

▍Загрузка пакетов определённых версий

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

Возможность задавать конкретные версии необходимых проекту библиотек полезна в командной разработке, когда все члены команды пользуются в точности одними и теми же библиотеками. Переход на их новые версии так же осуществляется централизованно, путём внесения изменений в файл проекта package.json .

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

▍Запуск скриптов

Файл package.json поддерживает возможность описания команд (скриптов), запускать которые можно с помощью такой конструкции:

Например, вот как выглядят перечень скриптов, имеющийся в соответствующем разделе файла:

Весьма распространено использование этой возможности для запуска Webpack:

Такой подход даёт возможность заменить ввод длинных команд, чреватый ошибками, следующими простыми конструкциями:

▍Куда npm устанавливает пакеты?

При установке пакетов с использованием npm (или yarn) доступны два варианта установки: локальная и глобальная.

По умолчанию, когда для установки пакета используют команду наподобие npm install lodash , пакет оказывается в папке node_modules , расположенной в папке проекта. Кроме того, если была выполнена вышеописанная команда, npm также добавит запись о библиотеке lodash в раздел dependencies файла package.json , который имеется в текущей директории.

Глобальная установка пакетов выполняется с использованием флага -g :

Выполняя такую команду, npm не устанавливает пакет в локальную папку проекта. Вместо этого он копирует файлы пакета в некое глобальное расположение. Куда именно попадают эти файлы?

Для того чтобы это узнать, воспользуйтесь следующей командой:

В 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-разработке:

Такая команда установит библиотеку в локальную папку проекта node_modules .

Для того чтобы использовать её в своём коде, достаточно импортировать её с применением команды require :

Как быть, если пакет представляет собой исполняемый файл?

В таком случае исполняемый файл попадёт в папку node_modules/.bin/ folder .

Посмотреть на то, как выглядит работа этого механизма можно, установив пакет cowsay. Он представляет собой шуточную программу, написанную для командной строки. Если передать этому пакету какой-нибудь текст, в консоли, в стиле ASCII-арта, будет выведено изображение коровы, которая «произносит» соответствующий текст. «Озвучивать» текст могут и другие существа.

Итак, после установки пакета с использованием команды npm install cowsay , он, вместе со своими зависимостями, попадёт в node_modules . А в скрытую папку .bin будут записаны символические ссылки на бинарные файлы cowsay.

Как их выполнять?

Конечно, можно, для вызова программы, ввести в терминале нечто вроде ./node_modules/.bin/cowsay , это рабочий подход, но гораздо лучше воспользоваться npx, средством для запуска исполняемых файлов npm-пакетов, включаемым в npm начиная с версии 5.2. А именно, в нашем случае понадобится такая команда:

Путь к пакету npx найдёт автоматически.

Файл package.json

Файл package.json является важнейшим элементов множества проектов, основанных на экосистеме Node.js. Если вы программировали на JavaScript, была ли это серверная или клиентская разработка, то вы, наверняка, уже встречались с этим файлом. Зачем он нужен? Что вам следует о нём знать и какие возможности он вам даёт?

Package.json представляет собой нечто вроде файла-манифеста для проекта. Он даёт в распоряжение разработчика множество разноплановых возможностей. Например, он представляет собой центральный репозиторий настроек для инструментальных средств, используемых в проекте. Кроме того, он является тем местом, куда npm и yarn записывают сведения об именах и версиях установленных пакетов.

▍Структура файла

Вот пример простейшего файла package.json :

Как видите, он пуст. Нет жёстких требований, касающихся того, что должно присутствовать в подобном файле для некоего приложения. Единственное требование к структуре файла заключается в том, что она должна следовать правилам формата JSON. В противном случае этот файл не сможет быть прочитан программами, которые попытаются получить доступ к его содержимому.

Если вы создаёте Node.js-пакет, который собираетесь распространять через npm, то всё радикальным образом меняется, и в вашем package.json должен быть набор свойств, которые помогут другим людям пользоваться пакетом. Подробнее мы поговорим об этом позже.

Вот ещё один пример package.json :

В нём задано свойство name , значением которого является имя приложения или пакета, материалы которого содержатся в той же папке, где находится этот файл.

Вот пример посложнее, который я взял из приложения-примера, написанного с использованием Vue.js:

Как видите, тут прямо-таки немеряно всего интересного. А именно, здесь можно выделить следующие свойства:

  • name — задаёт имя приложения (пакета).
  • version — содержит сведения о текущей версии приложения.
  • description — краткое описание приложения.
  • main — задаёт точку входа в приложение.
  • private — если данное свойство установлено в true , это позволяет предотвратить случайную публикацию пакета в npm.
  • scripts — задаёт набор Node.js-скриптов, которые можно запускать.
  • dependencies — содержит список npm-пакетов, от которых зависит приложение.
  • devDependencies — содержит список npm-пакетов, используемых при разработке проекта, но не при его реальной работе.
  • engines — задаёт список версий Node.js, на которых работает приложение.
  • browserlist — используется для хранения списка браузеров (и их версий), которые должно поддерживать приложение.

▍Свойства, используемые в package.json

Поговорим о свойствах, которые можно использовать в package.json . Здесь мы будем использовать термин «пакет», но всё, что сказано о пакетах, справедливо и для локальных приложений, которые не планируется использовать в роли пакетов.

Большинство свойств, которые мы опишем, используются лишь для нужд репозитория npm, некоторые используются программами, которые взаимодействуют с кодом, вроде того же npm.

Свойство name

Свойство name задаёт имя пакета:

Имя должно быть короче 214 символов, не должно включать в себя пробелы, должно состоять только из прописных букв, дефисов ( — ) и символов подчёркивания ( _ ).

Подобные ограничения существуют из-за того, что когда пакет публикуется в npm, его имя используется для формирования URL страницы пакета.

Если вы публиковали код пакета на GitHub, в общем доступе, то хорошим вариантом имени пакета является имя соответствующего GitHub-репозитория.

Свойство author

Свойство author содержит сведения об авторе пакета:

Оно может быть представлено и в таком формате:

Свойство contributors

Свойство contributors содержит массив со сведениями о людях, внёсших вклад в проект:

Это свойство может выглядеть и так:

Свойство bugs

В свойстве bugs содержится ссылка на баг-трекер проекта, весьма вероятно то, что такая ссылка будет вести на страницу системы отслеживания ошибок GitHub:

Свойство homepage

Свойство homepage позволяет задать домашнюю страницу пакета:

Свойство version

Свойство version содержит сведения о текущей версии пакета:

При формировании значения этого свойства нужно следовать правилам семантического версионирования. Это означает, в частности, что номер версии всегда представлен тремя цифрами: x.x.x.

Первое число — это мажорная версия пакета, второе — минорная версия, третье — патч-версия.

Изменение этих чисел несёт в себе определённый смысл. Так, релиз пакета, в котором лишь исправляются ошибки, приводит к увеличению значения патч-версии. Если выходит релиз пакета, изменения, внесённые в который, отличаются обратной совместимостью с предыдущим релизом — то меняется минорная версия. В мажорных версиях пакетов могут присутствовать изменения, которые делают эти пакеты несовместимыми с пакетами предыдущих мажорных версий.

Свойство license

Свойство license содержит сведения о лицензии пакета:

Свойство keywords

Свойство keywords содержит массив ключевых слов, имеющих отношение к функционалу пакета:

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

Свойство description

Свойство description содержит краткое описание пакета:

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

Свойство repository

Свойство repository указывает на то, где находится репозиторий пакета:

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

Используемую при разработке пакета систему контроля версий можно задать и в явном виде:

Один и тот же пакет может использовать разные системы контроля версий:

Свойство main

Свойство main задаёт точку входа в пакет:

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

Свойство private

Свойство private , установленное в true , позволяет предотвратить случайную публикацию пакета в npm:

Свойство scripts

Свойство scripts задаёт список скриптов или утилит, которые можно запускать средствами npm:

Эти скрипты являются приложениями командной строки. Запускать их можно с помощью npm или yarn, выполняя, соответственно, команды вида npm run XXXX или yarn XXXX , где XXXX — имя скрипта. Например, выглядеть это может так:

Скрипты можно называть так, как вам хочется, делать они могут практически всё, чего может пожелать разработчик.

Свойство dependencies

Свойство dependencies содержит список npm-пакетов, установленных в виде зависимостей пакета:

При установке пакета с использованиеме npm или yarn используются команды такого вида:

Эти пакеты автоматически добавляются в список зависимостей разрабатываемого пакета.

Свойство devDependencies

Свойство devDependencies содержит список npm-пакетов, установленных как зависимости разработки:

Этот список отличается от того, который хранится в свойстве dependencies , так как имеющиеся в нём пакеты устанавливаются лишь в системе разработчика пакета, при практическом использовании пакета они не применяются.

Пакеты попадают в этот список при их установке с помощью npm или yarn, выполняемой следующим образом:

Свойство engines

Свойство engines указывает, какие версии Node.js и других программных продуктов используются для обеспечения работы пакета:

Свойство browserlist

Свойство browserlist позволяет сообщить о том, какие браузеры (и их версии) собирается поддерживать разработчик пакета:

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

Показанное здесь в качестве примера значение свойства browserlist означает, что вы хотите поддерживать как минимум 2 мажорные версии всех браузеров с как минимум 1% использования (эти данные берутся с ресурса CanIUse.com), за исключением IE 8 и более старых версий этого браузера (подробнее об этом можно узнать на странице пакета browserlists).

▍Хранение в package.json настроек для различных программных инструментов

В package.json можно хранить настройки для различных вспомогательных инструментов вроде Babel или ESLint.

Каждому из таких инструментов соответствует особое свойство, наподобие eslintConfig или babel . Подробности об использовании подобных свойств можно найти в документации соответствующих проектов.

▍О версиях пакетов и семантическом версионировании

3.0.0 или ^0.13.0 . Здесь использованы так называемые спецификаторы версий, которые определяют диапазон версий пакетов, подходящих для использования в нашем пакете.

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

: если вы задаёте версию в виде

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

Файл 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 :

Сегодня мы начали разговор об npm и разобрались со структурой и назначением файлов package.json и package-lock.json . В следующий раз продолжим разбирать возможности npm и коснёмся использования npx.

Уважаемые читатели! Какой менеджер пакетов вы предпочитаете — npm или yarn?

Установка и обновление зависимостей в JavaScript

Установка и обновление зависимостей JavaScript

И снова привет! В прошлом посте мы начали рассматривать процесс управления зависимостями в JavaScript, разобрали основы: что такое npm-пакет, как выглядит манифест пакета, в каких полях прописываются зависимости и в принципе что такое дерево зависимостей, а также основы семантического версионирования (semver). Если вы пропустили предыдущий пост, то рекомендую начать с него.

Сегодня мы пойдем немного дальше и более подробно рассмотрим как работает semver, как правильно прописывать диапазоны зависимостей, а также устанавливать и обновлять их.

npm shell autocomplete

В моих постах я буду часто упоминать npm и различные команды с его использованием. Чтобы сделать набор команд в терминале чуточку удобнее, предлагаю установить автодополнения в ваш shell.

Сделать это достаточно легко, достаточно выполнить следующие команды:

Для Bash:

Для Z shell:

Это добавит в конфигурационный файл shell-а необходимый скрипт. После этого, если вы напишите: npm smth… а затем нажмете [TAB] , то shell автоматически дополнит вашу команду или предложит варианты дополнения.

Инициализация проекта

Как мы уже успели обсудить, проектом в npm является любая директория в которой находится манифест (файл package.json). Вы можете создать манифест вручную в любом редакторе кода, либо выполнить команду npm init. По умолчанию данная команда задаст вам серию вопросов в интерактивном режиме и сгенерирует простейший манифест в текущей директории на основе ваших ответов.

Однако я предпочитаю вызывать команду следующим образом: npm init -y , а затем править манифест в редакторе. При таком вызове npm не будет задавать вопросов, а просто сгенерирует минимальный манифест со значениями по умолчанию.

Использование инициализаторов

Говоря про npm init, нельзя не упомянуть про возможность использования специальных пакетов инициализаторов (npm initializers). Данные пакеты облегчают создание новых проектов генерируя необходимый boilerplate-код.

Используется это следующим образом: npm init <initializer> , где <initializer> — это название инициализатора (например: esm или react-app ).

Инициализатор по сути — это специальный npm-пакет с префиксом create- , который загружается из npm registry в момент вызова команды и выполняется. У каждого инициализатора могут быть свои аргументы, настройки и поведение.

Например так можно создать React-приложение используя инициализатор create-react-app: npm init react-app — my-react-app . Два минуса позволяют разделить аргументы CLI, которые передаются в команду npm init от тех, что передаются в сам инициализатор. Особенность инициализатора React, например, в том, что проект будет создан не в текущей директории, а в поддиректории с названием, которое вы укажете при вызове (в примере: my-react-app) .

Вы можете и сами написать свой инициализатор и опубликовать его в registry. Это может быть особенно удобно в корпоративной среде, где существует множество стандартов и соглашений — вы можете оформить их все в виде инициализатора и опубликовать его в закрытом npm registry. Таким образом разработчики внутри компании смогут быстро создавать новые проекты.

Добавление зависимостей в проект

Как мы выяснили ранее, зависимости прописываются в манифесте проекта в полях: dependencies, devDependencies, peerDependencies или optionalDependencies. Чтобы добавить новую зависимость в проект необходимо использовать команду: npm install <package-name> или сокращенно: npm i <package-name> .

Пример: npm i lodash .

Данная команда установит lodash самой свежей стабильной версии и добавит эту зависимость в поле dependencies манифеста проекта.

Аналогично можно устанавливать сразу несколько зависимостей одновременно: npm i lodash express passport .

Команда install также позволяет выбрать в какое поле будет добавлена зависимость используя флаги:

  • -P, —save-prod
    установка в dependencies (работает по умолчанию)
  • -D, —save-dev
    установка в devDependencies
  • -O, —save-optional
    установка в optionalDependencies

Если вам нужно установить зависимость в peerDependencies, то придётся сделать это вручную т. к. npm не предусматривает для этого специальной команды. Как вариант, можно сначала установить зависимость в dependencies при помощи команды npm install, а потом перенести ее вручную в peerDependencies, в этом случае вам не придется угадывать свежую версию пакета (если вдруг ваш IDE не поддерживает автоматическую интеграцию с npm).

Конечно, зависимость можно добавить в список и самостоятельно в редакторе кода, но я всегда рекомендую использовать команды npm для добавления зависимостей, т. к. это дает более надежный результат: вы гарантированно получаете последнюю версию нужного пакета и список зависимостей будет корректно отсортирован в лексикографическом порядке (что позволит избежать конфликтов при мерже в Git).

Добавление зависимости старой версии

Если по какой-то причине вы хотите добавить зависимость не самой свежей версии, то вы можете указать нужную версию через символ «@»:

  • npm i lodash@3.9.2
  • npm i lodash@3

Однако делать это рекомендуется только в самом крайнем случае. Об этом я расскажу подробнее чуть позже.

Установка зависимостей

Выше мы рассмотрели варианты добавления зависимостей в проект, но как установить зависимости, которые уже прописаны в манифесте, если вы к примеру только сделали git clone?

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

Существует возможность установить только одну категорию зависимостей:

  • —only=prod[uction]
  • —only=dev[elopment]

Это может быть полезно, если вы хотите, к примеру, только запустить программу на Node.js, но не работать над ней.

Просмотр установленных зависимостей

Прежде чем мы поговорим про обновление зависимостей было бы полезно научиться просматривать их. Для этой цели в npm также предусмотрена специальная команда: npm ls.

Синтаксис команды выглядит следующим образом: npm ls [<package-name>] , где <package-name> это опциональное название пакета, который вы хотите найти в дереве зависимостей.

Если вызвать команду без аргументов, то она выведет полное дерево зависимостей (не ослепните, дерево может быть огромным):

Крошечная порция результата выдачи команды npm ls в большом проекте.

Иногда бывает необходимо найти ту или иную транзитивную зависимость в дереве проекта, чтобы понять какие пакеты «тянут» ее, для этого можно передать название пакета в команду: npm ls lodash .

Результат поиска пакета lodash в дереве зависимостей крупного проекта при помощи команды npm ls lodash.

Нужно заметить, что команда npm ls имеет возможность ограничения глубины поиска при помощи опции depth. Например следующая команда выведет только список прямых зависимостей проекта:

Как вы уже догадались, по умолчанию команда работает со всем деревом целиком.

Также вы можете использовать опции dev или prod для того, чтобы вывести только зависимости из полей dependencies или devDependencies:

  • npm ls —dev[elopment]
  • npm ls —prod[uction]

Использование же опции json позволяет получить дерево зависимостей в формате пригодном для машинной обработки, в этом режиме npm выводит более подробную информацию о пакетах, а не только название и версию. Данный режим может быть также полезен для отладки и сравнения двух деревьев (например в разных ветках проекта):

Обновление зависимостей

Как мы уже рассмотрели в предыдущем посте в npm для управления зависимостями используется система семантического версионирования (semver). Благодаря ей вы можете обновлять зависимости в своем проекте с предсказуемыми результатами: к примеру, если зависимость обновилась с версии 1.2.3 до версии 1.2.4 (patch update) или 1.3.0 (minor update), то это не сломает ваш проект, т. к. по правилам semver такие обновления не должны нарушать обратной совместимости. А если обновление производится с версии 1.2.3 до версии 2.0.0 или выше, то здесь вам следует обязательно заглянуть в журнал изменений (changelog) данного пакета, чтобы убедиться, что обновление ничего не сломает, возможно вам придется внести изменения в свой код, чтобы восстановить совместимость.

Несмотря на то, что semver гарантирует достаточно высокий уровень безопасности при обновлении, к сожалению, бывают случаи когда разработчики какого-то пакета могут нарушать правила и вносить критические изменения в patch или minor обновлениях (в первую очередь это касается непопулярных пакетов, которыми управляют менее опытные разработчики).

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

Версии зависимостей

Давайте теперь рассмотрим как именно прописываются версии зависимостей в манифесте проекта и какие механизмы дает нам semver для управления процессом обновления. Как я уже упомянул выше, при установке зависимости npm автоматически устанавливает самую свежую версию и включает наиболее свободный режим обновления для данной зависимости: разрешает как patch, так и minor обновления.

В package.json это выглядит следующим образом:

Символ «^» (caret, hat или «крышечка») указывается перед номером версии и имеет специальный смысл в semver. В данном случае это означает, что версия зависимости lodash должна обновляться до максимально доступной, но не выше 5.0.0 , т. е. разрешает patch и minor обновления, но запрещает обновления нарушающие обратную совместимость.

Помимо крышечки существует еще довольно много способов задать диапазон версии, все их можно посмотреть в описании пакета semver, который и реализует данный функционал в npm, однако в 99% случаев зависимости стоит указывать именно через крышечку (как делает npm по умолчанию), т. к. это дает наибольшую гибкость при обновлении зависимостей и в то же время защищает вас от критических изменений.

Фиксация версий зависимостей

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

Это гарантирует, что lodash будет установлен в ваш проект именно версии 4.17.17 , ни больше, ни меньше.

Однако фиксация версий зависимостей вызывает ряд существенных недостатков:

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

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

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

Просмотр устаревших зависимостей

Новые версии пакетов регулярно выходят, по этой причине, пакеты, установленные в вашем проекте могут устаревать и их необходимо регулярно обновлять. Команда npm outdated позволяет вам вывести список устаревших пакетов.

Результат команды npm outdated в проекте, где установлены две устаревшие зависимости.

Данная команды выводит таблицу со следующими колонками:

Колонка Описание
Package Название пакета
Current Текущая установленная версия
Wanted Максимальная версия, которая удовлетворяет диапазону semver прописанному в манифесте проекта
Latest Версия пакета, которую автор указал в качестве самой свежей (как правило максимально доступная версия пакета)
Location Место расположения зависимости в дереве

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

Чтобы просмотреть полный список всех устаревших зависимостей можно использовать следующую команду:

Обновление устаревших зависимостей

Фактическое обновление устаревших зависимостей в npm производится при помощи команды npm update.

Данная команда проверяет версии установленных зависимостей по отношению к версиям доступным в npm registry учитывая диапазоны версий semver указанных в манифесте вашего проекта. Если установленная версия того или иного пакета в вашем проекте отличается от максимальной версии доступной в registry (учитывая ограничение semver), то более свежая версия будет загружена и установлена, а манифест будет обновлен, чтобы минимальная версия в диапазоне соответствовала установленной. Важно заметить, что весь этот процесс протекает без нарушения semver, т. е. вызов npm update никогда не приведет к нарушению диапазонов версий, указанных в вашем манифесте.

Приведем пример: допустим в вашем проекте указан следующий диапазон версий пакета lodash: ^4.16.4 . Вызов npm update приведет к тому, что пакет будет обновлен до версии 4.17.19 , а манифест будет автоматически изменен чтобы содержать следующий диапазон: ^4.17.19 .

По аналогии с командой npm outdated, команда npm update также поддерживает аргумент depth и по умолчанию обновляет только прямые зависимости проекта, не трогая зависимости в глубине дерева. Поэтому, чтобы обновить все зависимости в проекте необходимо вызывать команду следующим образом:

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

npm-check

В качестве альтернативы командам npm outdated и npm update хочу предложить интересный инструмент под названием npm-check.

Вы можете установить его при помощи следующей команды:

Данный инструмент поддерживает интерактивный режим, позволяя вам выбрать галочками те пакеты, которые вы хотите обновить. Кроме того, он позволяет обновлять пакеты не только в рамках ограничений semver, но и игнорируя их, перепрыгивая с одной мажорной версии зависимости на другую. Разумеется делать это нужно осмысленно: тщательно изучая журнал изменений каждого мажорно-обновляемого пакета на наличие нарушений обратной совместимости. И никогда не забывайте тестировать ваш код после любых обновлений!

Результат вызова npm-check в проекте: доступно два обновления, одно мажорное и одно минорное.

Также результат вызова npm-check, но уже в интерактивном режиме: галочками можно выбрать зависимости, которые вы хотите обновить.

В качестве очень полезного бонуса — npm-check позволяет обнаружить, если какая-то из зависимостей не используется в проекте:

npm-check сообщает о том, что пакет lodash возможно не используется в проекте.

Рекомендую всегда держать этот незаменимый инструмент (или аналогичный) в своем арсенале.

Удаление зависимостей

Ну и наконец, давайте рассмотрим как мы можем удалять ранее добавленные в проект зависимости. Для этого существует команда npm uninstall или сокращенно: rm , r или un . Чтобы удалить один или несколько пакетов, мы можем вызвать команду следующим образом:

Данная команда удалит указанные пакеты как из файловой системы проекта, так и из его манифеста.

Workflow работы с npm-проектом

На данном этапе мы уже рассмотрели несколько полезных команд и инструментов, давайте попробуем обобщить наши знания для того, чтобы выработать некий workflow для работы над JavaScript-проектами. Не переживайте, потом мы его доработаем, когда углубимся в другие важные вопросы.

  • Инициализация проекта:
  • npm init
    (интерактивно)
  • npm init -y
    (с последующим редактированием в IDE)
  • npm install <dependency>
  • npm install <dependency-1> <dependency-2>…
  • npm install -D <dev-dependency>…
  • npm outdated
    (просмотр прямых устаревших зависимостей)
  • npm outdated —depth=9999
    (просмотр всех устаревших зависимостей)
  • npm update
    (обновление прямых устаревших зависимостей с учетом semver)
  • npm update —depth=9999
    (обновление всех устаревших зависимостей с учетом semver)
  • npm-check
    (просмотр прямых устаревших зависимостей)
  • npm-check -u
    (интерактивное обновление прямых устаревших зависимостей)
  • npm rm <dependency>

Продолжение следует

В данном посте мы более подробно рассмотрели процесс инициализации проекта, добавления, установки и обновления зависимостей. Рассмотрели как semver работает на практике при обновлении зависимостей.

В следующем посте мы поговорим про выбор зависимостей и про такие важные аспекты как качество и надежность. Увидимся через неделю, а пока подписывайтесь и следите за обновлениями!

Как установить зависимости package.json в текущем каталоге с помощью npm

У меня есть веб-приложение: fooapp. У меня есть package.json в корне. Я хочу установить все зависимости в конкретном node_modules directory . Как это сделать?

Что я хочу

Предположим, что у меня есть две зависимости widget . Я хочу закончить с такой структурой каталогов:

Что я получаю

когда я запускаю npm install fooapp/ , я получаю следующее:

npm создает копию каталога моего приложения в каталоге node_modules и устанавливает пакеты внутри другого каталога node_modules.

Я понимаю, что это имеет смысл для установки пакета. Но я не require() мое веб-приложение внутри чего-то другого, я запускаю его напрямую. Я ищу простой способ установки моих зависимостей в конкретный каталог node_modules.

2 ответа

изнутри вашего каталога приложений (то есть, где находится package.json) будут устанавливаться зависимости для вашего приложения, а не устанавливать его как модуль как описано здесь, Они будут помещены в. / node_modules относительно вашего файла package.json(это на самом деле немного сложнее, чем это, поэтому проверьте npm docs здесь).

Вы можете перемещать директорию node_modules в родительский каталог вашего приложения, если хотите, потому что механизм node ‘require’ понимает это. Однако, если вы хотите обновить зависимости приложений с помощью установки/обновления, npm не увидит перемещенный "node_modules" и вместо этого создаст новый каталог, опять же относительно package.json.

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *