JavaScript, как и любой другой язык, содержит внутри себя много готовых функций и модулей, облегчающих разработку. Все вместе они составляют стандартную библиотеку языка. В Node.js, например, это модули для работы с криптографией (шифрование), HTTP, файловой системой и многим другим. В браузере этот набор значительно меньше, но тоже присутствует.
// Пример встроенной функции
Math.round(5.34); // 5
// Встроенный в Node.js модуль для работы с файлами
import fs from "fs";
// Читает содержимое файла
const data = fs.readFileSync("path/to/file");
Какой бы хорошей ни была стандартная библиотека, она не может покрыть все задачи, возникающие во время разработки. Конечно, можно все недостающие компоненты реализовывать самостоятельно, но тогда разработка любого проекта превратится в бесконечный марафон. Слишком много типовых задач нужно решить в любом нетривиальном проекте.
В коммерческих проектах используются миллионы строк стороннего кода, написанные программистами по всему миру. Подобный код хранится в библиотеках, доступных для установки в проект. В JavaScript-мире их принято называть пакетами.
Какие задачи решают подобные пакеты? Совершенно разные. От небольших полезных функций для работы со строками или датами, до фреймворков, программных систем, формирующих архитектуру кода. Например, в JavaScript невероятно популярна библиотека lodash. Она предоставляет около сотни полезных функций, решающих типовые задачи по работе с массивами, строками и другими типами данных. Пара примеров:
// По общепринятому соглашению, lodash импортируется под именем _
import _ from "lodash";
// Пересечение массивов
_.intersection([2, 1], [2, 3]); // => [2]
// capitalize делает первую букву заглавной
_.capitalize("hello"); // Hello
Каждая из этих функций по отдельности может выглядеть небольшой. Однако чем больше проект, тем больше требуется подобных функций, и все вместе они превращаются в довольно большую кодовую базу. А ведь еще хотелось бы иметь хорошую документацию.
Обратите внимание на то, как происходит импорт кода из внешних библиотек. В этом случае имя пакета указывается без указания пути ./
. Так JavaScript понимает, что это именно пакет и не нужно искать файл с именем lodash.js.
// Так будет происходить поиск файла lodash.js в текущей директории
import _ from "./lodash.js";
// Так импортируется код из пакета
import _ from "lodash";
Установка
Если просто импортировать lodash в коде и затем запустить код на выполнение, то программа упадет с ошибкой: "lodash не найден". Для того чтобы воспользоваться сторонним пакетом, его нужно добавить в проект как зависимость. Так говорят потому что код проекта теперь зависит от этих библиотек. Для этого в npm предусмотрена команда установки:
# Обязательно выполнять в корне проекта
# только тогда lodash будет лежать в правильном месте
npm install lodash
Эта команда выполняет три действия. Сначала она скачивает пакет из NPM-хранилища в директорию node_modules в корне проекта. Если этой директории не было, то она автоматически создается. Затем она добавляет запись в package.json о том, что пакет lodash стал зависимостью. И наконец, создает или обновляет файл package-lock.json.
tree -L 1
.
├── node_modules
├── package.json
├── package-lock.json
└── index.js
Зависимости в package.json добавляются под ключом dependencies
. Здесь указаны все пакеты, используемые в проекте и не входящие в стандартную библиотеку.
"dependencies": {
"lodash": "^4.17.15"
}
В качестве ключа в зависимостях указывается имя пакета. Именно это имя используется при импорте пакета. Значением является последняя доступная версия на момент скачивания.
Теперь, когда Node.js встречает подобный импорт:
import React from "react";
Происходит попытка импортировать модуль из node_modules/react/...
Осталось разобраться с файлом package-lock.json. Мы расскажем о его предназначении позже в курсе, а сейчас опишем его общую концепцию.
Если кратко, то у зависимостей нашего проекта есть свои зависимости, а у них, в свою очередь, свои зависимости (зависимости зависимостей называются транзитивными зависимостями). Подобная цепочка может быть довольно длинной и на разных ее участках возможно появление одних и тех же пакетов, но разных версий. package-lock.json содержит описание всех пакетов, которые будут поставлены, включая все их зависимости с указанием конкретных версий. Это позволяет получать гарантированно одни и те же версии зависимостей для всех разработчиков проекта. Этот файл создается командой npm install
и потом используется при установке зависимостей. При наличии package-lock.json в проекте, установку зависимостей рекомендуется выполнять командой npm ci
# Если мы хотим в точности те же версии всех пакетов,
# какие были у остальных разработчиков этого проекта
npm ci
Связь с GIT
Программисты не так часто делают проекты "с нуля". Чаще всего они работают с готовыми проектами. Проекты же, в свою очередь, хранятся в git-репозиториях. Что нужно хранить в репозитории, а что нет, когда мы говорим о зависимостях?
Код самих зависимостей не является частью исходного кода. Его всегда добавляют в .gitignore. А вот файлы package.json и package-lock.json являются частью исходного кода и именно через них Node.js узнает о том, какие пакеты нужно поставить в систему.
Представьте, что вы клонируете готовый проект с гитхаба на свой компьютер и сразу пробуете запустить. Он упадет с ошибкой, так как код самих зависимостей в node_modules (как и сама директория) отсутствует. Чтобы он там появился, нужно запустить команду установки уже добавленных зависимостей:
# Выполняется в корне проекта
# Устанавливает все указанные зависимости
npm ci
Эта команда ничего не меняет в проекте. Она только лишь скачивает зависимости в директорию node_modules, базируясь на содержимом package.json и версиях из package-lock.json.
Предупреждения
Во время установки зависимостей npm выводит много разных сообщений. Среди них встречаются такие:
npm WARN deprecated minimatch@2.0.10: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue
Большинство подобных сообщений не влияют на работу приложения. Они лишь говорят о том что какие-то версии устарели или пакет больше не используется.
Самостоятельная работа
- Установите в проект hexlet-js пакет lodash
- Добавьте в файл index.js импорт функций из пакета lodash как в примерах выше
- Добавьте в файл index.js строчку
console.log(_.last(['one', 'two']));
- Запустите код, убедитесь что выводится
"two"
- Добавьте изменения на Github. Проследите, чтобы node_modules была исключена из отслеживания
- Изучите структуру директории node_modules
- Найдите исходники пакета lodash на Github и сравните с содержимым node_modules
Дополнительные материалы

Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
- Статья «Как учиться и справляться с негативными мыслями»
- Статья «Ловушки обучения»
- Статья «Сложные простые задачи по программированию»
- Урок «Как эффективно учиться на Хекслете»
- Вебинар «Как самостоятельно учиться»
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.