-
Notifications
You must be signed in to change notification settings - Fork 0
Что такое peerDependencies
Чтобы понять что тут написано настоятельно рекомендуется ознакомиться (если не знакомы) с:
- Реакт контекстами
- Как работают dev и обычные зависимости
- Yarn workspaces
Абстрактное определение peerDependencies которое можно встретить на просторах интернета никак не поможет понять что это такое и зачем оно надо, так что начать с ними знакомиться следует с проблемы, которую они решают
У нас есть 3 воркспейса: @dashboard/app
, @dashboard/index
, @dashboard/history
У нас есть пакет react-intl
. Из этого пакета нас интересует функционал основанный на работе реакт контекстов:
- Есть
IntlProvider
(Context.Provider) - Есть хук
useIntl
(useContext)
Наш проект работает следующим образом:
@dashboard/app
"собирает" остальные 2 фрагмента воедино. Так как оба из них используют react-intl
И им необходим одинаковый объект intl
, то IntlProvider
инициализируется именно там. Т.е. абстрактно это выглядит как-то так:
@dashboard/app:
<IntlProvider>
{route === '/' && <IndexPage />}
{route === '/history' && <HistoryPage />}
</IntlProvider>
@dashboard/index:
const IndexPage = () => {
const intl = useIntl()
return (
<Text>
{intl.formatMessage(messages.indexPage)}
</Text>
)
}
@dashboard/history:
const HistoryPage = () => {
const intl = useIntl()
return (
<Text>
{intl.formatMessage(messages.historyPage)}
</Text>
)
}
Сначала обратим внимание на то, как выглядят package.json
у всех воркспейсов:
@dashboard/app:
{
"name": "@dashboard/app",
"version": "0.0.0",
"license": "BSD-3-Clause",
"main": "src/index.ts",
"dependencies": {
"react-intl": "5.20.10"
}
}
@dashboard/index:
{
"name": "@dashboard/index",
"version": "0.0.0",
"license": "BSD-3-Clause",
"main": "src/index.ts",
"dependencies": {
"react-intl": "5.20.10"
}
}
@dashboard/history:
{
"name": "@dashboard/history",
"version": "0.0.0",
"license": "BSD-3-Clause",
"main": "src/index.ts",
"dependencies": {
"react-intl": "5.20.10"
}
}
В общем, идентичные. А теперь попробуем визуализировать древо зависимостей для такого проекта:
@dashboard/app
|_ react-intl
@dashboard/index
|_ react-intl
@dashboard/history
|_ react-intl
Пояснение: у каждого воркспейса свой инстанс(он же экземпляр) пакета react-intl
. Чем это чревато:
- У каждого воркспейса будет свой собственный "мир", в котором существует свой
IntlProvider
и не существуетIntlProvider
который мы уже инициализировали в@dashboard/app
-
useIntl
будет знать о существовании только своегоIntlProvider
, который, как известно, нигде не используется
А если поконкретнее и с логами то такой косяк выглядит примерно так:
Invariant Violation: [React Intl] Could not find required intl object. <IntlProvider> needs to exist in the component ancestry
Если упрощать до одного предложения: useIntl
стучится в IntlProvider
которого не существует. Но почему? Потому что он не знает о существовании IntlProvider
в @dashboard/app
Получается наша проблема свелась к тому, что нам нужно сообщить воркспейсам @dashboard/index
, @dashboard/history
о том, что существует react-intl
в @dashboard/app
, и uesIntl
нужно брать именно оттуда, чтобы получать тот самый объект intl
, а не создавать свой
Для этого воспользуемся peerDependencies, и пекеджи у воркспейсов выглядят теперь так:
@dashboard/app:
{
"name": "@dashboard/app",
"version": "0.0.0",
"license": "BSD-3-Clause",
"main": "src/index.ts",
"dependencies": {
"react-intl": "5.20.10"
}
}
@dashboard/index:
{
"name": "@dashboard/index",
"version": "0.0.0",
"license": "BSD-3-Clause",
"main": "src/index.ts",
"peerDependencies": {
"react-intl": "*"
}
}
@dashboard/history:
{
"name": "@dashboard/history",
"version": "0.0.0",
"license": "BSD-3-Clause",
"main": "src/index.ts",
"peerDependencies": {
"react-intl": "*"
}
}
Теперь дерево по факту выглядит так:
@dashboard/app
|_ react-intl
@dashboard/index
@dashboard/history
Да, react-intl
просто отсутствует как инстанс в index и history, а peerDependencies говорит, что нужно использовать родительский инстанс react-intl
(в нашем случае это тот, что в @dashboard/app
)
И...все, в целом это вся суть peerDependencies.
Еще их можно использовать как регламент для вашей либы. То есть если ваша либа совместима с реактом версии 16, в peerDependencies это можно указать так:
"peerDependencies" :
"react": "16"
И теперь при попытке установить вашу либу в проект где используется 14 версия реакта будет ошибка