Перейти до основного змісту
Версія: 10.x

Часті питання

Чому моя тека node_modules використовує місце на диску, якщо пакунки зберігаються у глобальному сховищі?

pnpm створює жорсткі посилання з глобального сховища на теки node_modules проєкту. Жорсткі посилання вказують на те саме місце на диску, де знаходяться оригінальні файли. Так, наприклад, якщо у вашому проєкті є залежність foo і вона займає 1 Мб місця, то це виглядатиме так, ніби вона займає 1 Мб місця у теці проєкту node_modules і стільки ж місця у глобальному сховищі. Однак цей 1 Мб — це той самий простір на диску, до якого звертаються з двох різних місць. Отже, загалом foo займає 1 Мб, а не 2 Мб.

Більше на цю тему:

Чи підтримується Windows?

Коротка відповідь: Так. Довга відповідь: використання символьних посилань у Windows, м'яко кажучи, проблематичне, однак pnpm має обхідний шлях. Для Windows ми натомість використовуємо junctions.

Але підхід вкладення node_modules несумісний із Windows?

Ранні версії npm мали проблеми через вкладеність усіх node_modules (див. цей тікет). Однак pnpm не створює глибоких тек, він зберігає всі пакунки безперервно та використовує символьні посилання для створення структури дерева залежностей.

А як щодо циклічних символічних посилань?

Хоча pnpm використовує звʼязування, щоб додати залежності в теки node_modules, циклічних символічних посилань вдається уникати, тому що батьківські пакунки розміщуються в тій же теці node_modules, в яких є їх залежності. Тож залежності foo не знаходяться в foo/node_modules, але foo є у node_modules разом зі своїми власними залежностями.

Навіщо взагалі жорсткі посилання? Чому б не створити символічне посилання безпосередньо на глобальне сховище?

Один пакунок може мати різні набори залежностей на одній машині.

У проєкті A foo@1.0.0 може мати залежність, що розпізнається як bar@1.0.0, але у проєкті B та сама залежність foo може розпізнаватися як bar@1.1.0; отже, pnpm жорстко повʼязує foo@1.0.0 з кожним проєктом, де він використовується, щоб створити для нього різні набори залежностей.

Пряме символьне посилання на глобальне сховище працювало б з прапорцем Node --preserve-symlinks, однак, цей підхід має безліч власних проблем, тому ми вирішили дотримуватися жорстких посилань. Щоб дізнатися більше про те, чому було прийнято це рішення, перегляньте цей тікет.

Чи працює pnpm у різних підтомах в одному розділі Btrfs?

Хоча Btrfs не дозволяє створювати міжпристрійні жорсткі посилання між різними підтомами одного розділу, він дозволяє створювати reflink. Як наслідок, pnpm використовує посилання для обміну даними між цими підтомами.

Чи працює pnpm на кількох дисках або файлових системах?

Сховище пакунків повинно знаходитися на тому ж диску і у тій же файловій системі, що й встановлення, інакше пакунки буде скопійовано, а не звʼязано. Це повʼязано з обмеженням того, як працює жорстке звʼязування, оскільки файл в одній файловій системі не може адресувати розташування в іншій. Дивіться тікет #712, щоб отримати більше деталей.

pnpm функціонує по-різному у 2 випадках нижче:

Вказано шлях до сховища

Якщо шлях до сховища вказано через конфігурацію сховища, то копіювання відбувається між сховищем і будь-якими проєктами, які знаходяться на іншому диску.

Якщо ви запускаєте pnpm install на диску A, тоді сховище pnpm має бути на диску A. Якщо сховище pnpm розташоване на диску B, тоді всі необхідні пакунки будуть безпосередньо скопійовані в розташування проєкту замість зв’язування. Це суттєво зменшує переваги зберігання та продуктивності, які надає pnpm.

НЕ вказано шлях до сховища

Якщо шлях до сховища не встановлено, буде створено кілька сховищ (по одному на диск або файлову систему).

Якщо інсталяція виконується на диску A, сховище буде створено на A в .pnpm-store у корені файлової системи. Якщо пізніше інсталяція буде запущена на диску B, незалежне сховище буде створено на B в .pnpm-store. Проєкти все одно збережуть переваги pnpm, але кожен диск може мати надлишкові пакунки.

Що означає pnpm?

pnpm означає продуктивний (performant) npm. Назву придумав @rstacruz.

pnpm не працює з <НАЗВА-ВАШОГО-ПРОЄКТУ>?

У більшості випадків це означає що, для однієї з залежностей, потрібні пакунки не вказані в package.json. Це типова помилка, спричинена пласкою структурою node_modules. Якщо це станеться, це помилка в залежності, і залежність слід виправити. Однак це може зайняти час, тому pnpm підтримує обхідні шляхи, щоб змусити пакунки з помилками працювати.

Рішення 1

У разі виникнення проблем ви можете скористатися параметром node-linker=hoisted. Це створить пласку структуру node_modules, подібну до структури npm.

Рішення 2

У наступному прикладі залежність не має модуля iterall у власному списку залежностей.

Найпростішим рішенням для усунення відсутніх залежностей дефектних пакунків є додавання iterall як залежності до package.json нашого проєкту.

Ви можете зробити це, встановивши його через pnpm add iterall, і його буде автоматично додано до package.json вашого проєкту.

  "dependencies": {
...
"iterall": "^1.2.2",
...
}

Рішення 3

Одним із рішень є використання хуків для додавання відсутніх залежностей до файлу пакунка package.json.

Прикладом була Інформаційна панель Webpack, яка не працювала з pnpm. Згодом проблему було виправлено, і тепер вона працює з pnpm.

Раніше це видавало помилку:

Error: Cannot find module 'babel-traverse'
at /node_modules/inspectpack@2.2.3/node_modules/inspectpack/lib/actions/parse

Проблема полягала в тому, що babel-traverse використовувався у inspectpack який використовувався у webpack-dashboard, але babel-traverse не був наявним в inspectpack package.json. Це все ще працювало з npm і yarn, оскільки вони створюють пласкі node_modules.

Рішенням було створити файл .pnpmfile.cjs із таким вмістом:

module.exports = {
hooks: {
readPackage: (pkg) => {
if (pkg.name === "inspectpack") {
pkg.dependencies['babel-traverse'] = '^6.26.0';
}
return pkg;
}
}
};

Після створення .pnpmfile.cjs видаліть лише pnpm-lock.yaml — нема потреби видаляти node_modules, оскільки хуки pnpm впливають лише на дозвіл модуля. Потім перебудуйте залежності і це повинно працювати.