Package manifest (package.json, package.json5, package.yaml)
Файл маніфесту пакунка. Він містить усі метадані пакунка, включно із залежностями, назвою, автором тощо. Це стандарт, який зберігається у всіх основних менеджерах пакунків Node.js, включаючи pnpm.
In addition to the traditional package.json
format, pnpm also supports package.json5
(via json5) and package.yaml
(via js-yaml).
engines
Ви можете вказати версію Node і pnpm, на якій працює ваше програмне забезпечення:
{
"engines": {
"node": ">=10",
"pnpm": ">=3"
}
}
Під час локальної розробки pnpm завжди завершить роботу з повідомленням про помилку, якщо його версія не збігається з версією, вказаною у полі engines
.
Якщо користувач не встановив прапорець конфігурації engine-stric
(див. .npmrc), це поле є лише рекомендаційним і показуватиме попередження лише тоді, коли ваш пакунок встановлено як залежність.
dependenciesMeta
Додаткова метаінформація, що використовується для залежностей, оголошених всередині dependencies
, optionDependencies
та devDependencies
.
dependenciesMeta.*.injected
Якщо для залежності, яка є пакунком локального робочого простору, встановлено значення true
, цей пакунок буде встановлено шляхом створення копії з жорстким посиланням у віртуальному сховищі (node_modules/.pnpm
).
Якщо цей параметр встановлено у false
або не встановлено, залежність буде встановлено шляхом створення символічного посилання node_modules
, яке вказуватиме на теку з кодом пакунка у робочій області. Це стандартний спосіб, оскільки він швидший і гарантує, що будь-які зміни в залежності будуть негайно помітні її споживачам.
Наприклад, припустимо, що наступний package.json
є пакунком локального робочого простору:
{
"name": "card",
"dependencies": {
"button": "workspace:1.0.0"
}
}
Залежність button
зазвичай встановлюється шляхом створення символічного посилання у теці node_modules
теки card
, яке вказує на теку розробки для button
.
Але що, якщо button
вказує react у своїх peerDependencies
? Якщо всі проєкти в монорепо використовують однакову версію react
, то проблеми немає. Але що робити, якщо button
вимагає card
, який використовує react@16
і form
, який використовує react@17
? Зазвичай вам потрібно вибрати одну версію react
і вказати її за допомогою devDependencies
з button
. Створення символічних посилань не дає можливості задовольнити залежність react різними споживачами, такими як card
та form
, по-різному.
Поле injected
розвʼязує цю проблему, встановлюючи копії button
у віртуальному сховищі з жорсткими посиланнями. Щоб досягти цього, package.json
для card можна сконфігурувати наступним чином:
{
"name": "card",
"dependencies": {
"button": "workspace:1.0.0",
"react": "16"
},
"dependenciesMeta": {
"button": {
"injected": true
}
}
}
Тоді як package.json
для form можна було б налаштувати наступним чином:
{
"name": "form",
"dependencies": {
"button": "workspace:1.0.0",
"react": "17"
},
"dependenciesMeta": {
"button": {
"injected": true
}
}
}
З цими змінами ми говоримо, що button
є "injected dependency" від card
і form
. Коли button
імпортує react
, він перетвориться на react@16
в контексті card
, але перетвориться на react@17
в контексті form
.
Оскільки інʼєкційні залежності створюють копії теки з вихідним кодом своєї робочої області, ці копії необхідно якось оновлювати щоразу, коли код модифікується; інакше новий стан не буде відображено для споживачів. Якщо ви збираєте декілька проєктів за допомогою команди типу pnpm --recursive run build
, це оновлення має відбуватися після того, як буде зібрано кожен пакунок, але до того, як буде зібрано його споживачів. У простих випадках це можна зробити повторним викликом pnpm install
, можливо, за допомогою сценарію життєвого циклу package.json
, наприклад, "prepare": "pnpm run build"
для перезбірки цього проєкту. Сторонні інструменти, такі як pnpm-sync та pnpm-sync-dependencies-meta-injected надають більш надійне та ефективне рішення для оновлення інʼєкційних залежностей, а також підтримку режиму спостереження.
peerDependenciesMeta
У цьому полі перелічено деяку додаткову інформацію, повʼязану із залежностями, переліченими у полі peerDependencies
.
peerDependenciesMeta.*.optional
Якщо цей параметр встановлено у true, вибрану пряму залежність буде позначено менеджером пакунків як необовʼязкову. Таким чином, якщо споживач пропустить її, це більше не буде вважатися помилкою.
Наприклад:
{
"peerDependencies": {
"foo": "1"
},
"peerDependenciesMeta": {
"foo": {
"optional": true
},
"bar": {
"optional": true
}
}
}
Зауважте, що навіть якщо bar
не було вказано у peerDependencies
, він позначений як необовʼязковий. Таким чином, pnpm буде вважати, що будь-яка версія bar є прийнятною.
Втім, foo
є необовʼязковим, але лише для необхідної специфікації версії.
publishConfig
Можна перевизначити деякі поля в маніфесті до того, як пакунок буде запаковано. Наступні поля можуть бути перевизначені:
Щоб перевизначити поле, додайте версію для публікації до publishConfig
.
Наприклад, наступний package.json
:
{
"name": "foo",
"version": "1.0.0",
"main": "src/index.ts",
"publishConfig": {
"main": "lib/index.js",
"typings": "lib/index.d.ts"
}
}
Буде опубліковано як:
{
"name": "foo",
"version": "1.0.0",
"main": "lib/index.js",
"typings": "lib/index.d.ts"
}
publishConfig.executableFiles
Стандартно, з міркувань переносимості, жодні файли, окрім тих, що перелічено у полі bin, не буде позначено як виконувані у результуючому архіві пакунків. Поле executableFiles
дозволяє вам оголошувати додаткові поля, які повинні мати прапорець виконуваності (+x), навіть якщо вони не доступні безпосередньо через поле bin.
{
"publishConfig": {
"executableFiles": [
"./dist/shim.js"
]
}
}
publishConfig.directory
Ви також можете використовувати поле publishConfig.directory
для налаштування опублікованої підтеки відносно поточного package.json
.
Очікується, що у зазначеній теці міститиметься модифікована версія поточного пакунка (зазвичай за допомогою сторонніх засобів збирання).
У цьому прикладі тека
"dist"
повинна міститиpackage.json
{
"name": "foo",
"version": "1.0.0",
"publishConfig": {
"directory": "dist"
}
}
publishConfig.linkDirectory
- Стандартно: true
- Тип: Boolean
Якщо встановлено значення true
, під час локальної розробки проєкт буде зʼєднано з текою publishConfig.directory
.
Наприклад:
{
"name": "foo",
"version": "1.0.0",
"publishConfig": {
"directory": "dist",
"linkDirectory": true
}
}
pnpm.overrides
У цьому полі ви можете вказати pnpm перевизначити будь-яку залежність у графі залежностей. Це корисно для того, щоб змусити всі ваші пакунки використовувати одну версію залежності, перенести виправлення, замінити залежність форком або видалити невикористовувану залежність.
Зверніть увагу, що поле перевизначень можна встановити лише у корені проєкту.
Пр иклад поля "pnpm"."overrides"
:
{
"pnpm": {
"overrides": {
"foo": "^1.0.0",
"quux": "npm:@myorg/quux@^1.0.0",
"bar@^2.1.0": "3.0.0",
"qar@1>zoo": "2"
}
}
}
Ви можете вказати пакунок, до якого належить перевизначена залежність, відокремивши селектор пакунка від селектора залежності символом ">", наприклад, qar@1>zoo
перевизначить лише залежність zoo
пакунка qar@1
, а не будь-які інші залежності.
Перевизначення можна визначити як посилання на специфікацію прямої залежності.
Це досягається шляхом додавання до імені залежності префікса $
:
{
"dependencies": {
"foo": "^1.0.0"
},
"pnpm": {
"overrides": {
"foo": "$foo"
}
}
}
Пакунок, на який посилаються, не обовʼязково повинен збігатися з пакунком, на який посилається перевизначений:
{
"dependencies": {
"foo": "^1.0.0"
},
"pnpm": {
"overrides": {
"bar": "$foo"
}
}
}
Якщо ви вважаєте, що використання певного пакунка не потребує однієї з його залежностей, ви можете вилучити її за допомогою -
. Наприклад, якщо пакунок foo@1.0.0
потребує великого пакунка з назвою bar
для функції, яку ви не використовуєте, вилучення цього пакунка може скоротити час встановлення:
{
"pnpm": {
"overrides": {
"foo@1.0.0>bar": "-"
}
}
}
Ця можливість особливо корисна для optionalDependencies
, де більшість необовʼязкових пакунків можна безпечно пропустити.
pnpm.packageExtensions
Поля packageExtensions
надають можливість розширити наявні визначення пакунків додатковою інформацією. Наприклад, якщо react-redux
повинен мати react-dom
у своїх peerDependencies
, але не має, можна виправити react-redux
за допомогою packageExtensions
:
{
"pnpm": {
"packageExtensions": {
"react-redux": {
"peerDependencies": {
"react-dom": "*"
}
}
}
}
}
Ключами у packageExtensions
є назви пакунків або назви пакунків і діапазони semver, тому можна виправити лише деякі версії пакунків:
{
"pnpm": {
"packageExtensions": {
"react-redux@1": {
"peerDependencies": {
"react-dom": "*"
}
}
}
}
}
Наступні поля можна розширити за допомогою packageExtensions
: dependencies
, optionalDependencies
, peerDependencies
і peerDependenciesMeta
.
Більший приклад:
{
"pnpm": {
"packageExtensions": {
"express@1": {
"optionalDependencies": {
"typescript": "2"
}
},
"fork-ts-checker-webpack-plugin": {
"dependencies": {
"@babel/core": "1"
},
"peerDependencies": {
"eslint": ">= 6"
},
"peerDependenciesMeta": {
"eslint": {
"optional": true
}
}
}
}
}
}
Разом з Yarn ми підтримуємо базу даних packageExtensions
для виправлення несправних пакунків в екосистемі.
Якщо ви використовуєте packageExtensions
, подумайте про те, щоб надіслати PR і внести ваше розширення до бази даних @yarnpkg/extensions
.