Автор оригинала: Shubheksha Jalan.
Эшли Уильямс является одним из лидеров сообщества Node.js. Она твитна о новых менеджерах по пакетам.
Я действительно не понимал, что она имела в виду, поэтому я решил раскопать и прочитать о том, как работают менеджеры пакетов.
Это было правильно, когда новый ребенок на блоке менеджера пакета JavaScript – Пряжа – только что прибыл и генерировал много гудок.
Поэтому я использовал эту возможность, чтобы также понять Как и почему пряжа делает вещи по-разному из NPM Отказ
У меня было так весело исследовать это. Я хотел бы, чтобы я сделал так давно. Поэтому я написал это простое введение в NPM и пряжу, чтобы поделиться тем, что я узнал.
Давайте начнем с некоторых определений:
Что такое пакет?
Пакет – это многоразовая часть программного обеспечения, которое можно загрузить из глобального реестра в локальную среду разработчика. Каждый пакет может или не может зависеть от других пакетов.
Что такое менеджер по пакетам?
Проще говоря – менеджер пакетов – это кусок программного обеспечения, который позволяет вам управлять зависимости (внешний код, написанный вами или кем-то еще), что ваш проект должен работать правильно.
Большинство менеджеров по пакетам жонглирует следующие произведения вашего проекта:
Код проекта
Это код вашего проекта, для которого вам нужно управлять различными зависимостями. Как правило, весь этот код проверяется в систему управления версией, как Git.
Манифест файл
Это файл, который отслеживает все ваши зависимости (управляемые пакеты). Он также содержит другие метаданные о вашем проекте. В мире JavaScript этот файл ваш Package.json.
Код зависимости
Этот код представляет ваши зависимости. Не следует мутировать в течение жизни вашего приложения и должна быть доступна в память вашего проекта в памяти, когда он необходимо.
Блокировка файла
Этот файл написан автоматически самим менеджером пакета. Он содержит всю информацию, необходимую для воспроизведения дерева источника полной зависимости. Он содержит информацию о каждом из зависимостей вашего проекта, наряду с их соответствующими версиями.
Это стоит указывать на этот момент, что пряжа использует LOCKFILE, а NPM нет. Мы поговорим о последствиях этого различия в немного.
Теперь, когда я познакомил вас с частями менеджера пакета, давайте обсудим сами зависимости.
Плоские против вложенных зависимостей
Чтобы понять разницу между плоским схемами зависимости от вложенных зависимостей, давайте попробуем визуализацию графа зависимостей зависимостей в вашем проекте.
Важно иметь в виду, что зависимости вашего проекта зависит от собственных зависимостей. И эти зависимости могут в свою очередь, имеют некоторые зависимости общего.
Чтобы сделать это ясно, скажем, наше приложение зависит от зависимостей A, B и C, а C зависит от A.
Плоские зависимости
Как показано на изображении, как приложение, так и C имеют в качестве их зависимости. Для разрешения зависимостей в плоской схеме зависимости существует только один слой зависимостей, которые требуется ваш менеджер пакета для прохождения.
Долгая история короткая – у вас может быть только одна версия определенного пакета в вашем исходном дереве, так как для всех ваших зависимостей есть одно общее пространство имен.
Предположим, что пакет A обновляется до версии 2.0. Если ваше приложение совместимо с версией 2.0, но пакет C не, то нам нужны две версии пакета A, чтобы сделать наше приложение правильно. Это известно Зависимость ада.
Вложенные зависимости
Одно простое решение для решения проблемы зависимости ада состоит в том, чтобы иметь две разные версии пакета A – версии 1.0 и версии 2.0.
Это где вложенные зависимости вступают в игру. В случае вложенных зависимостей каждая зависимость может изолировать свои собственные зависимости от других зависимостей, в другом пространстве имен.
Диспетчер пакетов должен пройти несколько уровней для разрешения зависимостей.
У нас может быть несколько копий одной зависимости в такой схеме.
Но, как вы могли догадаться, это тоже приводит к нескольким проблемам. Что делать, если мы добавим другой пакет – пакет D – и зависит от версии 1.0 пакета A?
Так что с этой схемой мы можем оказаться Дублирование версии 1.0 пакета A. Это может вызвать путаницу и занимает ненужное дисковое пространство.
Одним из решений к вышеуказанной задаче состоит в том, чтобы иметь две версии пакета A, V1.0 и V2.0, но только одну копию V1.0, чтобы избежать ненужного дублирования. Это Подход, взятый NPM V3 , что уменьшает время, необходимое для прохождения дерева зависимости значительно.
Как Эшли Уильямс объясняет, NPM V2 устанавливает зависимости в гнездовой манере Отказ Вот почему NPM V3 значительно быстрее по сравнению.
Детерминизм против не детерминизм
Другая важная концепция в руководителях пакетов – это детерминизм. В контексте JavaScript Ecosystem детерминизм означает, что все компьютеры с данным Package.json Файл все будет иметь то же самое иное дерево зависимостей, установленных на них в их node_modules папка.
Но с нетерминированным менеджером пакета это не гарантируется. Даже если у вас точно такой же Package.json На двух разных компьютерах, макет вашего node_modules может отличаться между ними.
Детерминизм желательно. Это поможет вам избежать «Работал на моей машине, но это сломалось, когда мы развернули это» проблемы, которые возникают, когда у вас есть разные node_modules на разных компьютерах.
NPM V3, по умолчанию имеет не детерминированные установки и предлагает Функция Shrinkwrap сделать установки детерминированы. Это записывает все пакеты на диске в LockFile вместе с их соответствующими версиями.
Пряжа предлагает детерминированные усталы, поскольку он использует Lockfile для блокировки всех зависимостей рекурсивно на уровне приложения. Таким образом, если пакет A зависит от V1.0 пакета C, и пакет B зависит от V2.0 пакета A, оба из них будут записаны в ложноустройство отдельно.
Если вы знаете точные версии зависимостей, с которыми вы работаете, вы можете легко воспроизвести сборки, затем отслеживать и изолировать ошибки.
Итак, теперь мы можем вернуться к первоначальному вопросу, который начал меня на этом обучении Spree в первую очередь: Почему она считается хорошей практикой, чтобы иметь LockFiles для приложений, но не для библиотек?
Основная причина в том, что вы на самом деле развертываете приложения. Таким образом, вам необходимо иметь детерминистические зависимости, которые приводят к воспроизводимым сборкам в различных средах – тестирование, постановка и производство.
Но то же самое не верно для библиотек. Библиотеки не развернуты. Они используются для создания других библиотек или в самих приложении. Библиотеки должны быть гибкими, чтобы они могли максимизировать совместимость.
Если у нас был LockFile для каждой зависимости (библиотеки), которую мы использовали в приложении, и приложение было вынуждено уважать эти локоны, было бы невозможно добраться до ближайшей к плоской структуре зависимости, мы говорили о ранее, с семантическая версия Гибкость, которая является лучшим сценарием дела для разрешения зависимостей.
Вот почему: если ваша заявка должна рекурсивно почитать Lockfiles все ваши зависимости, повсюду было бы версию конфликтов – даже в относительно небольших проектах. Это вызвало бы большое количество неизбежного дупликации из-за семантическая версия Отказ
Это не значит, что библиотеки не могут иметь Lockfiles. Они, безусловно, могут. Но основным выносным положением является то, что управляющие пакетами, такие как пряжа и NPM – которые потребляют эти библиотеки – не уважают эти блокировки.
Спасибо за прочтение! Если вы считаете, что этот пост был полезен, пожалуйста, нажмите «︎❤», чтобы помочь продвинуть эту часть другим.