CI/CD pipeline для JavaScript: настройка с нуля за 10 шагов

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Как перестать деплоить вручную и не бояться коммитов

Вы когда-нибудь сидели в пятницу вечером, смотрели на продакшен и думали: "Ну, вроде всё работает, а если я сейчас запущу сборку — ничего не сломается?" Знакомо? Ручной деплой — это как прыжок с парашютом без инструктора: вроде бы и адреналин, но слишком часто заканчивается больно.

CI/CD pipeline — это ваш автоматический страховочный трос. Он сам соберёт проект, прогонит тесты, проверит код и, если всё ок — выкатит обновление на сервер. Никаких "ой, я забыл запустить сборку" или "а почему упали тесты, ведь локально работало?".

В этой статье мы с нуля настроим полноценный CI/CD пайплайн для JavaScript проекта. Без воды, с реальными примерами кода и готовыми конфигами. Поехали!

Что такое CI/CD pipeline и зачем он нужен JavaScript-разработчику

Давайте сразу разберёмся с терминами, чтобы не путаться.

Continuous Integration (CI) — непрерывная интеграция. Это когда каждый ваш коммит автоматически проверяется: код проходит линтеры, тесты, сборку. Если что-то сломалось — вы узнаёте об этом через 2 минуты, а не через неделю.

Continuous Delivery (CD) — непрерывная доставка. Автоматическое развёртывание готового кода на сервер после того, как все проверки CI прошли успешно.

Для JavaScript-проектов CI/CD особенно важен. Почему? Потому что экосистема JS — это тысячи зависимостей, которые могут в любой момент обновиться и сломать ваш код. Автоматизация спасает от таких сюрпризов.

Что мы будем настраивать

  • GitHub Actions — бесплатный инструмент для CI/CD (хватит на большинство проектов)
  • Линтер — проверка стиля кода (ESLint)
  • Тесты — автоматический запуск Jest
  • Сборка — билд проекта (Webpack или Vite)
  • Деплой — автоматическая выгрузка на сервер или хостинг

Шаг 1: Готовим проект

Предположим, у вас уже есть JavaScript проект (React, Vue, Node.js — неважно). Если нет — создайте простой проект для теста:

mkdir my-ci-cd-project
cd my-ci-cd-project
npm init -y
npm install --save-dev jest eslint

Добавим базовый скрипт в package.json:

{
  "scripts": {
    "test": "jest",
    "lint": "eslint src/",
    "build": "webpack --mode production",
    "deploy": "rsync -avz dist/ user@server:/var/www"
  }
}

Теперь у нас есть локальные команды, которые CI/CD будет выполнять автоматически.

Шаг 2: Создаём GitHub Actions workflow

GitHub Actions — это мозг нашего пайплайна. Всё управляется YAML-файлами в папке .github/workflows/.

Создайте файл .github/workflows/ci-cd.yml:

name: CI/CD Pipeline

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  build-and-test:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Setup Node.js
      uses: actions/setup-node@v3
      with:
        node-version: '18'
        
    - name: Install dependencies
      run: npm ci
      
    - name: Run linter
      run: npm run lint
      
    - name: Run tests
      run: npm test
      
    - name: Build project
      run: npm run build

Что здесь происходит? При каждом пуше в main или develop GitHub запускает виртуальную машину с Ubuntu, ставит Node.js 18, устанавливает зависимости (чистая установка через npm ci — быстрее и надёжнее, чем npm install), проверяет код линтером, запускает тесты и собирает проект.

Если хоть один шаг упадёт — пайплайн остановится, и вы получите уведомление.

Шаг 3: Добавляем линтер и тесты

ESLint и Jest — стандарт для JavaScript. Настроим их так, чтобы CI не пропускал "грязный" код.

ESLint:

// .eslintrc.json
{
  "env": {
    "browser": true,
    "es2021": true,
    "node": true
  },
  "extends": ["eslint:recommended"],
  "rules": {
    "no-unused-vars": "error",
    "no-console": "warn"
  }
}

Jest:

// sum.js
function sum(a, b) {
  return a + b;
}
module.exports = sum;

// sum.test.js
const sum = require('./sum');
test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});

Теперь npm run lint и npm test будут работать в CI.

Шаг 4: Оптимизируем пайплайн

Базовый пайплайн работает, но давайте сделаем его быстрее и умнее.

Кэширование зависимостей

Установка npm-пакетов каждый раз — долго. Добавим кэш:

- name: Cache node_modules
  uses: actions/cache@v3
  with:
    path: ~/.npm
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-node-

- name: Install dependencies
  run: npm ci

Параллельные джобы

Линтер, тесты и сборку можно запустить одновременно, чтобы сэкономить время:

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
      - run: npm ci
      - run: npm run lint

  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
      - run: npm ci
      - run: npm test

  build:
    needs: [lint, test]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
      - run: npm ci
      - run: npm run build

Теперь линтер и тесты бегут одновременно. Сборка запускается только после их успешного завершения.

Шаг 5: Настраиваем деплой (CD)

Самое интересное — автоматический деплой. Рассмотрим два популярных варианта.

Вариант 1: Деплой на сервер через SSH

Добавим джобу для деплоя:

deploy:
  needs: [build]
  runs-on: ubuntu-latest
  if: github.ref == '                

Блоги

Рекомендаций по книгам