Менеджеры пакетов отвечают за установку, обновление и удаление программных пакетов и зависимостей. NPM широко используется в качестве стандартного менеджера пакетов для JavaScript. Однако многие компании уже внедряют менеджер пакетов PNPM ввиду его огромных преимуществ.

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

Что такое pnpm

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

Почему не npm и не yarn

npm использует node_modules с сумбурной структурой зависимостей. Это приводит к следующим проблемам:

  • Архитектура дерева зависимостей слишком сложна
  • Некоторые пакеты могут быть продублированы
  • Модули имеют доступ к пакетам, от которых они не зависят

Рассмотрим следующий пример. Одному из наших проектов нужен модуль express. У модуля express есть пакет зависимостей с именем debug. Вот как будет выглядеть структура в node_modules:

myProject
  |--node_modules
    |--debug
    |--express 

Теперь в нашем коде мы можем прописать require('debug'), хотя у нас нет для него прямой зависимости в файле package.json. Какие проблемы могут быть этим вызваны:

  • express будет обновлять свою зависимость debug с критическими изменениями.
  • express больше не будет зависеть от debug.

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

Дублирующиеся пакеты - еще одна проблема. В этом плане yarn, конечно, немного лучше с точки зрения оптимизации дискового пространства, так как использует механизмы хоистинга; однако в некоторых случаях такой подход не работает.

Как pnpm решает эти проблемы

pnpm использует жесткие и символьные ссылки (симлинки) для поддержания полустрогой структуры node_modules. Жесткая ссылка - это прямая ссылка на определенный файл. При мягкой ссылке существует файл, содержимое которого указывает на другой путь. Симлинки - это ссылки, которые pnpm использует для создания вложенной структуры зависимостей.

Давайте теперь посмотрим на pnpm-версию модуля express.

myProject
  |--node_modules
    |--express (симлинк)
    |--.pnpm
      |--registry.npmjs.org
        |--express
        |  |--4.0.0
        |    |--node_modules
        |      |--express (жесткая ссылка)
        |      |--debug (симлинк)
        |--debug
           |--1.0.0
             |--node_modules
               |--debug (жесткая ссылка)

Первое, на что можно обратить внимание - наш код уже не может получить доступ к пакету debug, потому что он не находится в корне папки node_modules. pnpm создал специальную папку с именем .pnpm, которая содержит жесткие ссылки на все модули.

Если мы посмотрим глубже на express 4.0.0, то увидим, что модуль представляет собой жесткую ссылку на глобальное хранилище pnpm и символьную ссылку debug на жесткую ссылку debug, которая также ссылается на глобальное хранилище pnpm.

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

Ниже приведена схема фактического pnpm-хранилища, содержащего пакеты. Здесь хранятся все загруженные зависимости.

.pnpm
  |--registry.npmjs.org
    |--express
    |  |--4.0.0
    |    |--node_modules
    |      |--express (актуальный пакет)
    |--debug
       |--1.0.0
          |--node_modules
             |--debug (актуальный пакет)

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

Преимущества pnpm

Рассмотрим преимуществ pnpm по сравнению с npm и yarn.

Эффективность дискового пространства

Как показано на схеме предыдущего раздела, pnpm использует файловую систему с адресацией по-содержимому для хранения пакетов и зависимостей на диске. Это означает, что один и тот же пакет не будет дублироваться. Даже с разными версиями одного и того же пакета pnpm достаточно умен, чтобы повторно использовать максимальное количество кода. Если в пакете одной версии 500 файлов, а в другой версии на один файл больше, то pnpm не будет записывать 501 файл для второй версии; вместо этого он создаст жесткую ссылку на исходные 500 файлов и запишет только один новый файл. Для крупных репозиториев это может иметь большое значение. Представьте сценарий, где один пакет нужен сотням других пакетов, которые будут съедать место на вашем диске, если вы не используете pnpm.

Улучшенная скорость

Скорость установки пакета с pnpm значительно выше, чем с npm и yarn. Если вы взгляните на тесты производительности, то убедитесь, что в большинстве случаев pnpm работает лучше, чем npm и yarn.

Безопасность

pnpm, как и yarn, имеет специальный файл с контрольной суммой всех установленных пакетов. Это гарантирует целостность всех установленных пакетов до выполнения их кода.

С точки зрения непривилегированного доступа pnpm также превосходит npm и yarn. В случае npm и yarn, если пакет A зависит от пакета B, а B зависит от C, то A неявно получает доступ к C, даже если A не объявил C в качестве своей зависимости. Эта проблема усугубляется при установке большого количества пакетов одного репозитория. pnpm использует другой алгоритм разрешения зависимостей и другую структуру папок node_modules, что предотвращает несанкционированный доступ к ненужным пакетам.

CLI-интерфейс pnpm

Интерфейс командной строки pnpm довольно прост и удобен. Вот некоторые из основных команд:

  • pnpm init - создает файл package.json
  • pnpm install - устанавливает все пакеты, перечисленные в качестве зависимостей в package.json
  • pnpm add [имя_модуля]@[версия] - устанавливает определенную версию пакета и добавляет ее в список зависимостей в package.json
  • pnpm remove [имя_модуля] - удаление пакета из зависимостей и из package.json
  • pnpm list - отображает дерево локально установленных модулей

Переход с npm/yarn на pnpm

Если в ваших проектах используется npm или yarn, то переход на pnpm не составит особого труда. Вот сравнение команд между npm, yarn и pnpm.

npm команда yarn команда pnpm аналог
npm install   yarn pnpm install
npm install [module_name] yarn add [module_name] pnpm add [module_name]
npm uninstall [module_name] yarn remove [module_name] pnpm remove [module_name]
npm update yarn upgrade pnpm update
npm list yarn list pnpm list
npm run [scriptName] yarn [scriptName] pnpm [scriptName]
npx [command] yarn dlx [command] pnpm dlx [command]
npm exec yarn exec [commandName] pnpm exec [commandName]
npm init [initializer] yarn create [initializer] pnpm create [initializer]