package.json

Файл маніфесту пакунка. Він містить усі метадані пакунка, включно із залежностями, назвою, автором тощо. Це стандарт, який зберігається у всіх основних менеджерах пакунків Node.js, включаючи pnpm.

Окрім традиційного формату package.json, pnpm також підтримує package.json5 (з допомогою json5) та package.yaml (з допомогою js-yaml).

engines#

Ви можете вказати версію Node і pnpm, на якій працює ваше програмне забезпечення:

{
    "engines": {
        "node": ">=10",
        "pnpm": ">=3"
    }
}

Під час локальної розробки pnpm завжди завершить роботу з повідомленням про помилку, якщо його версія не збігається з версією, вказаною у полі engines.

Якщо користувач не встановив прапорець конфігурації engineStrict (див. параметри), це поле є лише рекомендаційним і видаватиме попередження лише тоді, коли ваш пакунок буде встановлено як залежність.

engines.runtime#

Додано у: v10.21.0

Визначає середовище виконання Node.js, необхідне для залежності. Після оголошення, pnpm автоматично встановить зазначену версію Node.js.

{
  "engines": {
    "runtime": {
      "name": "node",
      "version": "^24.11.0",
      "onFail": "download"
    }
  }
}

Коли пакунок оголошує середовище виконання:

  1. Для програм CLI: pnpm прив’язує CLI до потрібної версії Node.js, гарантуючи використання правильного середовища виконання незалежно від глобально встановленого екземпляра Node.js.
  2. **Для пакунків зі скриптами postinstall: Скрипт виконується з використанням зазначеної версії Node.js.

Це особливо корисно для залежностей, які потребують певних версій Node.js для коректної роботи.

devEngines.runtime#

Додано у: v10.14

Дозволяє вказати один або декілька рушіїв виконання JavaScript, які використовуються в проєкті. Підтримуються рушії Node.js, Deno та Bun.

Наприклад, ось як додати node@^24.4.0 до ваших залежностей:

{
  "devEngines": {
    "runtime": {
      "name": "node",
      "version": "^24.4.0",
      "onFail": "download"
    }
  }
}

Ви також можете додати кілька середовищ виконання до одного package.json:

{
  "devEngines": {
    "runtime": [
      {
        "name": "node",
        "version": "^24.4.0",
        "onFail": "download"
      },
      {
        "name": "deno",
        "version": "^2.4.3",
        "onFail": "download"
      }
    ]
  }
}

Як це працює:

  1. pnpm install обробляє вказаний вами діапазон для отримання останньої відповідної версії середовища виконання.
  2. Точна версія (та контрольна сума) зберігається у файлі блокування.
  3. Скрипти використовують локальне середовище виконання, забезпечуючи узгодженість між середовищами.

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
  }
}