Архитектура
Общая архитектура
Yarn работает через ядро пакета (опубликовано как @yarnpkg/core), которое предоставляет различные базовые компоненты, составляющие проект. Некоторые из компонентов — это классы, которые вы можете узнать по API: Configuration, Project, Workspace, Cache, Manifest, и другие. Все они предоставляются ядром пакета.
Само ядро не делает много — оно просто содержит логику, необходимую для управления проектом. Для использования этой логики из командной строки Yarn предоставляет косвенный слой, называемый @yarnpkg/cli, который, что интересно, также не делает много. Однако у него две очень важные обязанности: он инициализирует экземпляр проекта на основе текущей директории (cwd) и вводит в среду предварительно собранные плагины Yarn.
Yarn построен модульным способом, что позволяет большую часть бизнес-логики, связанной с взаимодействием с третьими сторонами, вынести вовне в собственный пакет — например, разрешитель npm npm resolver является всего лишь одним плагином из многих других. Эта конструкция дает нам гораздо более простой код (следовательно, увеличение скорости разработки и стабильности продукта) и предоставляет авторам плагинов возможность писать собственную внешнюю логику, не изменяя при этом код самого Yarn.
Архитектура установки
Что происходит при выполнении yarn install можно резюмировать несколькими шагами:
-
Сначала мы входим в «шаг разрешения»:
Сначала мы загружаем записи, сохраненные в файле блокировки, затем, основываясь на этих данных и текущем состоянии проекта (которое определяется считыванием файлов манифеста, т.е.
package.json), ядро выполняет внутренний алгоритм, чтобы выяснить, какие записи отсутствуют.Для каждой из этих отсутствующих записей оно запрашивает у плагинов интерфейс
Resolverи спрашивает, знают ли они о пакете, который соответствовал бы данному описанию (supportsDescriptor), и его точной идентичности (getCandidates) и списке транзитивных зависимостей (resolve).Получив новый список метаданных пакетов, ядро запускает новый проход разрешения по транзитивным зависимостям вновь добавленных пакетов. Это будет повторяться до тех пор, пока оно не определит, что все пакеты из дерева зависимостей теперь имеют свои метаданные, сохраненные в файле блокировки.
Наконец, после того, как все диапазоны пакетов из дерева зависимостей были разрешены в метаданные, ядро строит дерево в памяти ещё раз, чтобы сгенерировать то, что мы называем «виртуальными пакетами». Короче говоря, эти виртуальные пакеты — это разделенные экземпляры одного и того же базового пакета — мы используем их для устранения неоднозначности всех пакетов, которые указывают на зависимости peers, чьи наборы зависимостей будут меняться в зависимости от их местоположения в дереве зависимостей (см. эту запись в лексиконе по этой записи в лексиконе для получения дополнительной информации).
-
После завершения разрешения мы переходим к «шагу извлечения»:
Теперь, когда у нас есть точный набор пакетов, составляющих наше дерево зависимостей, мы перебираем его и для каждого из них начинаем новый запрос в кэш, чтобы узнать, существует ли пакет где-либо. Если нет, мы делаем так же, как и в предыдущем шаге, и спрашиваем наших плагины (через интерфейс
Fetcher), знают ли они о пакете (supports), а если да, то извлечь его из любого его удаленного местоположения (fetch).Интересный момент относительно извлекателей: они взаимодействуют с ядром через абстракцию над
fs. Мы делаем это, чтобы наши пакеты могли поступать из различных источников — это может быть из архива zip для пакетов, загруженных из реестра, или из фактической директории на диске для зависимостейportal:.
-
И, наконец, после того, как все пакеты готовы к использованию, наступает «шаг связи»:
Для корректной работы пакеты, которые вы используете, должны быть установлены на диске каким-либо образом. Например, в случае приложения Node.js, ваши пакеты должны быть установлены в набор директорий
node_modulesдля их обнаружения интерпретатором. Именно об этом заботится компоновщик. Через интерфейсыLinkerиInstallerядро Yarn будет взаимодействовать с зарегистрированными плагинами, чтобы сообщить им о пакетах, указанных в дереве зависимостей, и описать их взаимосвязи (например, оно сообщит им, чтоtapableявляется зависимостьюwebpack). Затем плагины могут решить, что делать с этой информацией, как они сочтут нужным.Это означает, что новые компоновщики могут быть легко созданы для других языков программирования — вам просто нужно написать свою собственную логику относительно того, что должно произойти с пакетами, предоставленными Yarn. Хотите сгенерировать
__autoload.php? Делайте! Хотите настроить виртуальную среду Python? Без проблем!Ещё одна интересная особенность заключается в том, что пакеты внутри дерева зависимостей не обязательно должны быть одного типа. Наша конструкция плагинов позволяет одновременно инициализировать несколько компоновщиков. Ещё лучше — пакеты могут зависеть друг от друга через компоновщики! Вы можете иметь пакет JavaScript, зависящий от пакета Python (что технически имеет место в случае
node-gyp, например).
© 2016–present Yarn Contributors
Licensed under the BSD License.
https://v3.yarnpkg.com/advanced/architecture