Робочий простір
pnpm має вбудовану підтримку монорепозиторіїв (також відомих як репозиторії з декількома пакунками, репозиторії з декількома проєктами або монолітні репозиторії). Ви можете створити робочий простір, щоб обʼєднати кілька проєктів в одному репозиторії.
Робоча область повинна мати файл pnpm-workspace.yaml у корені.
Якщо ви розглядаєте управління монорепозиторіями, ви також можете розглянути Bit.
Bit використовує pnpm під капотом, але автоматизує багато речей, які зараз виконуються вручну в традиційному робочому просторі, керованому pnpm/npm/Yarn. Є стаття про bit install, яка розповідає про це: Безболісне керування залежностями Monorepo за допомогою Bit.
Протокол робочого простору (workspace:)
Якщо linkWorkspacePackages встановлено у true, pnpm буде лінкувати пакунки з робочого простору, якщо доступні пакунки відповідають оголошеним діапазонам. Наприклад, foo@1.0.0 повʼязано з bar, якщо bar має "foo": "^1.0.0" у своїх залежностях і foo@1.0.0 знаходиться у робочому просторі. Однак, якщо bar має "foo": "2.0.0" у залежностях і foo@2.0.0 відсутній у робочому просторі, foo@2.0.0 буде встановлено з реєстру. Така поведінка вносить певну невизначеність.
На щастя, pnpm підтримує протокол workspace:. При використанні цього протоколу pnpm відмовлятиметься виконувати перетворення на будь-що, окрім пакунків локального робочого простору. Отже, якщо ви задасте "foo": "workspace:2.0.0", цього разу встановлення не вдасться, оскільки "foo@2.0.0" у робочому просторі відсутній.
Цей протокол особливо корисний, коли параметр linkWorkspacePackages має значення false. У цьому випадку pnpm буде компонувати пакунки з робочого простору лише за умови використання протоколу workspace:.
Посилання на пакунки робочого простору через псевдоніми
Припустимо, у робочому просторі у вас є пакунок з назвою foo. Зазвичай, ви посилаєтесь на нього як "foo": "workspace:*".
Якщо ви хочете використовувати інший псевдонім, наступний синтаксис також буде працювати: "bar": "workspace:foo@*".
Перед публікацією псевдоніми перетворюються на звичайні залежності від псевдонімів. Вищенаведений приклад стане: "bar": "npm:foo@1.0.0".
Посилання на пакунки робочого простору через їхній відносний шлях
У робочому просторі з 2 пакунками:
+ packages
+ foo
+ bar
bar може мати foo у своїх залежностях, оголошених як "foo": "workspace:../foo". Перед публікацією ці специфікації перетворюються у звичайні специфікації версій, які підтримуються усіма менеджерами пакунків.
Публікація пакунків робочого простору
Коли пакунок робочого простору запаковано до архіву (за допомогою pnpm pack або однієї з команд публікації, наприклад pnpm publish), ми динамічно замінюємо будь-яку залежність workspace: на:
- Відповідну версію у цільовому робочому просторі (якщо ви використовуєте
workspace:*,workspace:~абоworkspace:^) - Асоційований діапазон Semver (для будь-якого іншого типу діапазону)
Наприклад, якщо у робочому просторі є foo, bar, qar, zoo і всі вони мають версію 1.5.0, то наступне:
{
"dependencies": {
"foo": "workspace:*",
"bar": "workspace:~",
"qar": "workspace:^",
"zoo": "workspace:^1.5.0"
}
}
Буде перетворено на:
{
"dependencies": {
"foo": "1.5.0",
"bar": "~1.5.0",
"qar": "^1.5.0",
"zoo": "^1.5.0"
}
}
Ця функція дозволяє вам покладатися на ваші локальні пакунки робочих просторів і водночас публікувати отримані пакунки у віддаленому реєстрі без проміжних кроків публікації — ваші користувачі зможуть використовувати ваші опубліковані робочі простори як будь-які інші пакунки, отримуючи вигоду від гарантій, що їх пропонує Semver.
Процес релізу
Керування версіями пакунків у робочому просторі є складним завданням, і наразі pnpm не надає вбудованого рішення для цього. Однак є 2 добре протестовані інструменти, які працюють з версіями і підтримують pnpm:
Щоб дізнатися, як налаштувати сховище за допомогою Rush, прочитайте цю сторінку.
Про використання Changesets з pnpm читайте в цьому посібнику.
Усунення несправностей
pnpm не може гарантувати виконання скриптів у топологічному порядку, якщо між залежностями робочого простору є цикли. Якщо pnpm виявить циклічні залежності під час встановлення, він видасть попередження. Якщо pnpm зможе зʼясувати, які залежності спричиняють цикли, він також покаже їх.
Якщо ви бачите повідомлення Існують циклічні залежності робочого простору (There are cyclic workspace dependencies), перевірте залежності робочого простору, оголошені у dependencies, optionDependencies та devDependencies.
Приклад використання
Ось декілька найпопулярніших відкритих проєктів, які використовують функцію робочого простору pnpm:
Налаштування
linkWorkspacePackages
- Стандартно: false
- Type: true, false, deep
If this is enabled, locally available packages are linked to node_modules
instead of being downloaded from the registry. This is very convenient in a
monorepo. If you need local packages to also be linked to subdependencies, you
can use the deep setting.
Else, packages are downloaded and installed from the registry. However,
workspace packages can still be linked by using the workspace: range protocol.
Пакунки звʼязуються, лише якщо їхні версії задовольняють діапазони залежностей.
injectWorkspacePackages
- Стандартно: false
- Тип: Boolean
Вмикає жорстке звʼязування всіх локальних залежностей робочого простору замість їхнього звʼязування у вигляді символічних посилань. Крім того, цього можна досягти за допомогою dependenciesMeta[].injected, що дозволяє вибірково вмикати жорстке зв’язування для певних залежностей.
Навіть якщо цей параметр увімкнено, pnpm надаватиме перевагу дедуплікації введених залежностей за допомогою символічних посилань — якщо тільки не потрібно створювати декілька графів залежностей через невідповідність однорангових залежностей. This behaviour is controlled by the dedupeInjectedDeps setting.
dedupeInjectedDeps
- Default: true
- Тип: Boolean
When this setting is enabled, dependencies that are injected will be symlinked from the workspace whenever possible. If the dependent project and the injected dependency reference the same peer dependencies, then it is not necessary to physically copy the injected dependency into the dependent's node_modules; a symlink is sufficient.
syncInjectedDepsAfterScripts
Додано у: v10.5.0
- Default: undefined
- Тип: String[]
Інʼєкції залежності робочого простору — це колекції жорстких посилань, які не додають і не видаляють файли при зміні їхніх джерел. Це спричиняє проблеми у пакунках, які потрібно зібрати (наприклад, у проєктах на TypeScript).
Цей параметр являє собою список назв скриптів. Коли будь-який з цих скриптів виконується у пакунку робочої області, інʼєкції залежностей всередині node_modules також буде синхронізовано.
preferWorkspacePackages
- Стандартно: false
- Тип: Boolean
If this is enabled, local packages from the workspace are preferred over packages from the registry, even if there is a newer version of the package in the registry.
This setting is only useful if the workspace doesn't use
saveWorkspaceProtocol.
sharedWorkspaceLockfile
- Default: true
- Тип: Boolean
If this is enabled, pnpm creates a single pnpm-lock.yaml file in the root of
the workspace. This also means that all dependencies of workspace packages will
be in a single node_modules (and get symlinked to their package node_modules
folder for Node's module resolution).
Advantages of this option:
- кожна залежність є одиночною
- швидші установки в монорепо
- менше змін у перевірках коду, оскільки всі вони містяться в одному файлі
Even though all the dependencies will be hard linked into the root
node_modules, packages will have access only to those dependencies
that are declared in their package.json, so pnpm's strictness is preserved.
This is a result of the aforementioned symbolic linking.
saveWorkspaceProtocol
- Default: rolling
- Type: true, false, rolling
This setting controls how dependencies that are linked from the workspace are added to package.json.
If foo@1.0.0 is in the workspace and you run pnpm add foo in another project of the workspace, below is how foo will be added to the dependencies field. The savePrefix setting also influences how the spec is created.
| saveWorkspaceProtocol | savePrefix | spec |
|---|---|---|
| false | '' | 1.0.0 |
| false | '~' | ~1.0.0 |
| false | '^' | ^1.0.0 |
| true | '' | workspace:1.0.0 |
| true | '~' | workspace:~1.0.0 |
| true | '^' | workspace:^1.0.0 |
| rolling | '' | workspace:* |
| rolling | '~' | workspace:~ |
| rolling | '^' | workspace:^ |
includeWorkspaceRoot
- Стандартно: false
- Тип: Boolean
При рекурсивному виконанні команд у робочій області, виконуйте їх також у кореневому проєкті робочої області.
ignoreWorkspaceCycles
- Стандартно: false
- Тип: Boolean
When set to true, no workspace cycle warnings will be printed.
disallowWorkspaceCycles
- Стандартно: false
- Тип: Boolean
When set to true, installation will fail if the workspace has cycles.
failIfNoMatch
- Стандартно: false
- Тип: Boolean
When set to true, the CLI will exit with a non-zero code if no packages match the provided filters.
For example, the following command will exit with a non-zero code because bad-pkg-name is not present in the workspace:
pnpm --filter=bad-pkg-name test