SEO з Ігорем Абрамовським
Що таке dependency та devDependency у JavaScript/Node.js-проєктах?
Розбираємо різницю між dependencies і devDependencies. Пояснюємо, як правильно розподіляти npm-пакети для оптимізації білду, деплою та безпеки проєкту.

1. Що таке dependency у програмуванні та навіщо вони потрібні?

Визначення: Залежність (dependency) — це зовнішній пакет, модуль або бібліотека коду, створена сторонніми розробниками, яку ваш проєкт використовує для виконання конкретних завдань без необхідності писати весь функціонал із нуля.

Навіщо потрібні зовнішні залежності: Сучасна веброзробка спирається на принцип повторного використання коду. Зовнішні залежності дозволяють підключати готові й перевірені спільнотою рішення — вебфреймворки, клієнти баз даних, інструменти маршрутизації, обробники форматування дат чи розрахунку математичних моделей. Це прискорює розробку та дозволяє команді зосередитися на бізнес-логіці власного продукту.


2. Що означає dependencies у файлі package.json і які пакети туди належать?

Визначення: Секція dependencies у файлі package.json містить список пакетів, які є критично необхідними для виконання та функціонування застосунку у живому продакшн-середовищі (runtime).

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

Типові приклади:

Вебфреймворки та UI-бібліотеки: express, react, react-dom, next.

HTTP-клієнти та ORM/ODM для роботи з базами даних: axios, mongoose, @mikro-orm/core, pg.

Валідатори та утиліти стану: zod, zustand, pino.


3. Що таке devDependencies і чому деякі інструменти потрібні лише для розробки?

Визначення: Секція devDependencies (development dependencies) містить пакети, які потрібні виключно під час розробки, локального запуску, тестування, лінтингу чи збірки (build) проєкту.

Чому вони не потрібні в продакшні: Інструменти для перевірки синтаксису, компіляції коду чи запуску автотестів виконують свою роботу до моменту розгортання застосунку. Коли користувач заходить на ваш сайт, йому потрібен лише готовий скомпільований код (наприклад, згенерований JavaScript чи CSS), а самі тестові фреймворки та компилятори на сервері не викликаються.


4. У чому головна різниця між dependencies та devDependencies?

Критерій

dependencies

devDependencies

Виконання (Runtime)

Необхідні під час роботи застосунку для користувачів.

Використовуються лише під час розробки, збірки та тестування.

Встановлення у Production

Завжди встановлюються на продакшн-сервері.

Повністю пропускаються під час продакшн-інсталяції (--production / --omit=dev).

Приклади пакетів

react, express, axios, zod.

jest, eslint, prettier, typescript, vitest.


5. Як визначити, куди правильно додати пакет?

Щоб швидко визначити правильну секцію, дайте відповідь на одне ключове запитання:
👉 «Чи виконується код цього пакета в момент, коли реальний користувач взаємодіє з працюючим застосунком?»

Так (dependencies): Якщо пакет безпосередньо імпортується в код, який обробляє HTTP-запити, будує UI-компоненти або звертається до бази даних (наприклад, react, axios, express).

Ні (devDependencies): Якщо пакет є інструментом, який лише допомагає написати, перевірити, відформатувати, протестувати або зкомпілювати ваш код (наприклад, eslint, prettier, vitest, @types/react).


6. Як встановлювати звичайні та dev-залежності в npm, pnpm і Yarn?

npm:

Production (dependencies): npm install <package> або npm install <package> --save-prod.

Development (devDependencies): npm install <package> --save-dev або скорочено npm install <package> -D.

pnpm:

Production (dependencies): pnpm add <package>.

Development (devDependencies): pnpm add -D <package> (або pnpm add --save-dev <package>).

Yarn:

Production (dependencies): yarn add <package>.

Development (devDependencies): yarn add <package> --dev (або yarn add <package> -D).


7. Що відбувається під час npm install, npm ci та продакшн-інсталяції?

npm install: Зчитує package.json і за замовчуванням встановлює і dependencies, і devDependencies. Використовується на локальній машині розробника.

npm ci (Clean Install): Встановлює пакети суворо за версіями, зафіксованими у файлі package-lock.json. Гарантує ідентичність node_modules на всіх серверах та запобігає виникненню помилок «на моєму комп'ютері все працювало».

Production-інсталяція (npm install --production або npm ci --omit=dev): Завантажує та встановлює виключно пакети з секції dependencies, ігноруючи весь блок devDependencies.


8. Чому TypeScript, ESLint та компилятори належать до devDependencies?

TypeScript та @types/*: Компілятор tsc перетворює TypeScript-код у звичайний JavaScript під час збірки. У продакшні виконується вже готовий JS, а типи @types/* є лише сіткою безпеки для розробника та повністю видаляються під час компіляції.

ESLint / Prettier: Перевіряють синтаксис та форматують код на ПК розробника чи в CI-скриптах, але не мають жодного стосунку до логіки роботи вебсайту.

Тестові фреймворки (Jest, Vitest, Cypress): Перевіряють працездатність модулів під час розробки, але не потрібні відвідувачам вашого сайту.

Runtime-бібліотеки (React, Express, Axios): Належать до dependencies, оскільки вебсервер чи браузер клієнта прямо викликає їхні функції щоразу при завантаженні сторінки або надсиланні форми.


9. Вплив на Build, Deployment, Docker, CI/CD та безпеку

Оптимізація Docker-образів (Multi-Stage Builds): Використання двох етапів збірки в Docker (Stage 1 — Builder з усіма devDependencies для компіляції проєкту; Stage 2 — Runner лише з dependencies через npm ci --omit=dev) дозволяє зменшити підсумковий розмір Docker-контейнера з 1.2 GB до 180 MB.

Прискорення CI/CD: Завдяки виключенню не потрібних у продакшні dev-інструментів сервери збірки витрачають значно менше часу та трафіку на завантаження пакетів.

Зменшення поверхні атак (Security): Кожен завантажений на продакшн-сервер пакет — це потенційна вразливість. Відсіювання devDependencies на сервері істотно знижує ризик атак на ланцюжок поставок коду (supply chain attacks).


10. Проблеми неправильного розподілу та перевірка у Next.js проєкті

Типові проблеми:

Runtime-пакет потрапив у devDependencies: Застосунок чудово працюватиме локально у розробника, але після деплою на Vercel чи в Docker контейнер під час запуску впаде з помилкою Cannot find module або 500 Internal Server Error, оскільки продакшн-інсталяція пропустила цей пакет.

Dev-інструмент потрапив у dependencies: Роздувається розмір підсумкового контейнера, зростають витрати на розгортання та сповільнюється старт сервера.

Як перевірити правильність розподілу у реальному Next.js проєкті:

Симуляція суворого продакшн-збирання:
Очистіть папку node_modules і запустіть команду встановлення лише продакшн-залежностей:

rm -rf node_modules
npm ci --omit=dev

Після цього спробуйте виконати запуск вже скомпільованого застосунку (npm start). Якщо виникає помилка відсутності модуля, значить, якийсь runtime-пакет помилково знаходиться в devDependencies.

Перевірка клієнтського бандлу:
Використовуйте плагін @next/bundle-analyzer для візуалізації того, які саме бібліотеки потрапляють у фінальні JS-файли, що відправляються в браузер користувача.


Продовжуйте навчання

Останні матеріали цього курсу

Обговорення та запитання (0)

Поки що тут немає запитань або коментарів. Будьте першим, хто розпочне обговорення.

Додати повідомлення

Тип повідомлення