CI/CD для JavaScript проектов: GitHub Actions — полное руководство

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

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

Начать курс

Введение: Почему CI/CD необходим для JavaScript проектов

Разработка современного JavaScript-приложения на Node.js — это сложный процесс, который включает написание кода, тестирование, сборку и развертывание. Без автоматизации эти этапы выполняются вручную, что приводит к ошибкам, задержкам и снижению качества продукта. CI/CD (Continuous Integration / Continuous Delivery) — это практика DevOps, которая автоматизирует сборку, тестирование и развертывание кода.

GitHub Actions — это встроенный инструмент GitHub, который позволяет создавать рабочие процессы (workflows) для автоматизации задач. Он идеально подходит для JavaScript-проектов, так как поддерживает Node.js, npm, Yarn и множество популярных сервисов. В этой статье мы разберем, как настроить полноценный CI/CD пайплайн для вашего JavaScript-проекта с использованием GitHub Actions.

Вы узнаете: как запускать тесты, как собирать приложение, как деплоить на сервер или облачную платформу, и как избежать типичных ошибок.

Основы GitHub Actions для JavaScript

Что такое GitHub Actions?

GitHub Actions — это платформа для автоматизации рабочих процессов. Вы описываете последовательность шагов в YAML-файле, который помещается в репозиторий (обычно .github/workflows/main.yml). Каждый раз при наступлении события (например, push, pull request) запускается workflow.

Workflow состоит из jobs (задач), которые выполняются на runner (виртуальной машине). Для JavaScript-проектов обычно используется Ubuntu runner, предустановленный с Node.js.

Базовый workflow для Node.js

Начнем с простого workflow, который запускает тесты при каждом push или pull request. Создайте файл .github/workflows/ci.yml:

name: CI для JavaScript

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

jobs:
  test:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [16.x, 18.x, 20.x]

    steps:
    - uses: actions/checkout@v4
    - name: Использовать Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v4
      with:
        node-version: ${{ matrix.node-version }}
        cache: 'npm'
    - run: npm ci
    - run: npm test
    - run: npm run build --if-present

Этот workflow делает следующее:

  • Триггеры: запускается при push в main/develop или при pull request в main.
  • Матрица версий: тестирует на Node.js 16, 18, 20 — это гарантирует совместимость.
  • Кэширование: cache: 'npm' ускоряет установку зависимостей.
  • Команды: npm ci (чистая установка), npm test (тесты), npm run build (сборка, если есть).

Настройка полноценного CI/CD пайплайна

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

Шаг 1: Линтинг и форматирование

Добавим job для ESLint и Prettier. Это гарантирует единый стиль кода:

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-node@v4
      with:
        node-version: '18.x'
        cache: 'npm'
    - run: npm ci
    - run: npm run lint
    - run: npx prettier --check .

В package.json должны быть скрипты "lint" и "format". Пример:

{
  "scripts": {
    "lint": "eslint src/",
    "format": "prettier --write ."
  }
}

Шаг 2: Безопасность зависимостей

Используйте npm audit для проверки уязвимостей:

  security:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - run: npm audit --audit-level=high

Если аудит найдет критические уязвимости, job завершится ошибкой, и пайплайн остановится.

Шаг 3: Сборка и публикация артефактов

После успешных тестов и линтинга соберем приложение и сохраним артефакты для деплоя:

  build:
    needs: [test, lint, security]
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-node@v4
      with:
        node-version: '18.x'
        cache: 'npm'
    - run: npm ci
    - run: npm run build
    - uses: actions/upload-artifact@v4
      with:
        name: build-artifacts
        path: dist/

Здесь needs означает, что сборка запустится только после успешного выполнения предыдущих job.

Шаг 4: Деплой на сервер

Для деплоя на VPS или облако (например, DigitalOcean, AWS) используем SSH-действия. Пример деплоя через rsync:

  deploy:
    needs: [build]
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
    - uses: actions/download-artifact@v4
      with:
        name: build-artifacts
        path: dist/
    - name: Деплой на сервер
      uses: easingthemes/ssh-deploy@main
      env:
        SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
        ARGS: "-rlgoDzvc -i"
        SOURCE: "dist/"
        REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
        REMOTE_USER: ${{ secrets.REMOTE_USER }}
        TARGET: ${{ secrets.REMOTE_TARGET }}

Важно: Все секреты (SSH-ключи, пароли) храните в Settings → Secrets and variables → Actions. Никогда не пишите их в коде!

Оптимизация и лучшие практики

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

Без кэширования каждая сборка скачивает npm-пакеты заново, что занимает 1-3 минуты. Используйте actions/setup-node с параметром cache, как мы сделали выше. Альтернативно — отдельное кэширование ~/.npm:

    - uses: actions/cache                

Блоги

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