Одна з проблем, коли у вас фронтова монорепа — це контроль і управління версіями бібліотек. Саме з цією задачею ми зіткнулися на одному з наших проєктів.
Як я себе відчуваю, коли розумію, що буду оновлювати версії бібліотеки…
Трохи технічних деталей про проєкт
- монорепозиторій з оркестратором nx.
Тип монорепи — Package-Based Repository; - пакетний менеджер pnpm разом із функціональністю pnpm workspaces;
- структура стандартна:
/apps
- містить усі застосунки,/packages
- усі пакети; - усі застосунки на Nuxt 3;
- усі пакети на vue 3 або чистому typescript, білдимо все на vite;
- на поточний момент маємо 4 — застосунки, 22 — пакети;
- усі залежності пакетів екстерналізуються (externalize).
Якщо спростити, то у ваш білд не потрапляють бібліотеки з node_modules, вони там будуть підключені через import або require; (згадаю тут лібку vite-plugin-externalize-deps 👌)
А яка власне проблема?
Для прикладу, хочемо підняти версію Nuxt.
Для цього ми змінюємо її у всіх застосунках і деяких пакетах, які є nuxt модулями. Це оновлення тягне за собою оновлення версій деяких залежних бібліотек. І ось ви ходите по кожному застосунку і пакету, і перевіряєте чи все ок і при потребі піднімаєте версію.
Чи це дуже важка робота? — точно ні.
Чи це монотонна робота і є шанс десь помилитись? — точно так!
Ця проблема існує вже не перший рік і варіантів багато:
- якась автоматизація.
Скрипт, який пройде по всій системі і підніме версію; - ще автоматизація у вигляді різних ботів;
- кореневий package.json, або подібні до цього приколи;
- деякі з оркестраторів, беруть це на себе, якщо не помиляюсь rush якраз полегшив процес оновлення;
І всі ці варіанти — ок, якщо вони вирішують вашу проблему, але мене завжди не покидало відчуття, що це якийсь костиль і зайве ускладнення.
І саме тут на допомогу приходить pnpm catalogs.
PNPM Catalogs
Ідея дуже проста — давайте зберігати версії залежностей в одному місці, а в свою чергу усі package.json-и будуть посилатись на це місце.
Виглядає це наступним чином:
pnpm-workspace.yaml
packages:
- packages/*
- apps/*
# тут наші каталоги з ім'ям
catalogs:
# ми іменуємо по певному логічному доменному імені
domain1:
nuxt: 3.13.2
vue: 3.5.12
domain2:
nuxt: 3.13.1
vue: 3.5.12
# дефолтний каталог без імені
catalog:
nuxt: 3.12.5
vue: 3.4.1
package.json, якогось з пакетів чи застосунка
// посилаємось на версію з каталогу domain1
{
"name": "package1",
"dependencies": {
"vue": "catalog:domain1"
}
}
// посилаємось на версії з каталогу domain2
{
"name": "package2",
"dependencies": {
"vue": "catalog:domain2",
"nuxt": "catalog:domain2"
}
}
// посилаємось на версії з дефолтного каталогу
{
"name": "package3",
"dependencies": {
"vue": "catalog:",
"nuxt": "catalog:",
}
}
Тепер, щоб оновити версію:
- ідемо в
pnpm-workspace.yaml
; - змінюємо версію;
- запускаємо
pnpm i
;
Це не звільняє нас від необхідності перевірити чи всі версії коректно стали і не конфліктують одна з одною, але як мінімум частину рутини і ризик помилки ми знизили.
Що ще?
- щоб швидко переїхати на каталоги, запускаємо команду
pnpx codemod pnpm/catalog
; - маємо в планах подивитись і покрутити taze від Anthone Fu;
- враження від pnpm catalogs — все просто, вирішує нашу проблему і ми задоволені;
Перекладено з: pnpm catalogs + монорепозиторій