Оптимизация Docker-сборки фронтенда: npm install → npm ci и .dockerignore

Оптимизация Docker-сборки фронтенда

Когда проект растёт, каждая секунда в CI/CD начинает иметь значение. В этом коммите я решил заняться оптимизацией Docker-сборки фронтенда проекта Legion. Казалось бы, мелочь — заменить одну команду и добавить файл, — но эффект оказался значительным.

Что было сделано

Коммит затрагивает два файла в директории hub/frontend/:

1. Добавлен .dockerignore (новый файл)

Раньше Docker-сборка копировала всё содержимое директории фронтенда в контекст сборки. Это означало, что node_modules (сотни мегабайт), предыдущие сборки в dist, служебные файлы .git и документация — всё это отправлялось демону Docker.

Файл .dockerignore решает эту проблему:

node_modules
dist
.git
.gitignore
README.md
Dockerfile
nginx.conf

Теперь Docker-демон получает только то, что действительно нужно для сборки: исходный код и манифесты пакетов. Это ускоряет передачу контекста сборки и уменьшает нагрузку на кеш слоёв.

2. npm installnpm ci в Dockerfile
# Было
RUN npm install

# Стало
RUN npm ci

На первый взгляд — просто замена трёх букв. Но разница кардинальная:

Характеристика npm install npm ci
Установка зависимостей Может менять package-lock.json Работает строго по lock-файлу
Скорость Медленнее (разрешает зависимости) Быстрее (просто распаковывает)
Детерминированность ❌ Не гарантирует точную версию ✅ Идеально воспроизводима
Предназначение Разработка CI/CD и продакшн

Почему это важно для Legion

Dockerfile находится в hub/frontend/ — значит, фронтенд собирается в отдельный образ. Оптимизация даёт три преимущества:

  1. Скорость сборки в CInpm ci работает в 2–3 раза быстрее, не тратя время на разрешение зависимостей.
  2. Надёжность — строгое соблюдение lock-файла означает, что каждый запуск CI даёт идентичный результат. Никаких сюрпризов «а у меня работает».
  3. Кеширование — меньший контекст сборки + детерминированные зависимости = лучшее использование Docker-кеша слоёв. Изменение только package.json пересоберёт только этот слой.

Архитектурный контекст

Legion — проект с серверной частью и фронтендом. Разделение на hub/ (бэкенд) и hub/frontend/ (клиентская часть) — типичная монорепозиторная структура. Сборка фронтенда в отдельный Docker-образ означает, что:

  • Фронтенд можно деплоить независимо от бэкенда
  • Каждая часть использует свой оптимальный стек инструментов
  • Легче масштабировать команду — фронтенд-разработчики работают со своим Dockerfile

Вывод

Этот коммит — отличный пример того, как небольшие изменения в инфраструктуре могут существенно улучшить Developer Experience и скорость CI/CD. Иногда достаточно одного файла (.dockerignore) и замены трёх букв (installci), чтобы сделать жизнь команды заметно лучше.