CI/CD для TypeScript проектов: GitHub Actions продвинутый уровень

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

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

Начать курс

Введение: Зачем нужен продвинутый CI/CD для TypeScript?

Базовый пайплайн CI/CD, который просто запускает npm test и npm build, перестаёт быть эффективным, как только проект TypeScript начинает расти. Время сборки увеличивается, тесты занимают часы, а ручное управление версиями приводит к ошибкам. Продвинутый уровень настройки GitHub Actions позволяет решить эти проблемы: ускорить пайплайн за счёт кэширования, выполнять тесты параллельно для разных версий Node.js и ОС, а также автоматизировать деплой на продакшен.

В этой статье мы разберём три ключевых приёма для TypeScript проектов: умное кэширование node_modules, матричные сборки для проверки совместимости, и автоматический деплой с использованием actions/upload-pages-artifact. Все примеры написаны на TypeScript и готовы к интеграции в ваш репозиторий.

1. Умное кэширование зависимостей и компиляции

Первая проблема больших TypeScript проектов — долгая установка зависимостей и компиляция. GitHub Actions предоставляет механизм кэширования, но его нужно настроить правильно. Вместо того чтобы кэшировать всю папку node_modules (что может привести к устаревшим версиям), лучше кэшировать package-lock.json и папку .cache компилятора.

Пример продвинутого кэширования для TypeScript:

name: TypeScript CI (Advanced)
on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      
      - name: Cache TypeScript cache
        uses: actions/cache@v4
        with:
          path: |
            **/node_modules
            **/.tsbuildinfo
          key: ${{ runner.os }}-ts-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-ts-
      
      - run: npm ci
      - run: npm run build --if-present
      - run: npm test

Ключевая оптимизация здесь — использование hashFiles('**/package-lock.json') для генерации уникального ключа кэша. Если package-lock.json не менялся, кэш восстанавливается за секунды. Флаг --if-present позволяет пропустить скрипт сборки, если он не определён.

2. Матричные сборки: тестирование на разных версиях Node.js и ОС

TypeScript компилируется в JavaScript, но поведение кода может отличаться в разных средах исполнения. Матричная стратегия GitHub Actions позволяет запускать один и тот же пайплайн на нескольких комбинациях ОС и версий Node.js. Это критично для библиотек и серверных приложений.

Пример настройки матрицы для TypeScript проекта:

jobs:
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        node-version: [18, 20, 22]
        exclude:
          - os: windows-latest
            node-version: 22
      fail-fast: false

    steps:
      - uses: actions/checkout@v4
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'
      
      - run: npm ci
      - run: npx tsc --noEmit
      - run: npm test
      - name: Upload coverage
        uses: actions/upload-artifact@v4
        with:
          name: coverage-${{ matrix.os }}-${{ matrix.node-version }}
          path: coverage/

Ключевые моменты:

  • fail-fast: false — не останавливает остальные джобы при ошибке в одной из них. Позволяет увидеть все проблемы сразу.
  • exclude — позволяет исключить заведомо нерабочие комбинации (например, Node 22 на Windows, если есть известная проблема).
  • Параллельный запуск — все 8 комбинаций (3 ОС × 3 версии минус 1 исключение) выполняются одновременно, что экономит время.
  • npx tsc --noEmit — проверка типов без генерации JS-файлов. Быстрее полной сборки.

3. Автоматический деплой с условными триггерами

Продвинутый CI/CD подразумевает не только тестирование, но и деплой. Для TypeScript проектов часто нужно собрать статику (если это фронтенд) или скомпилировать серверный код. Используем условные триггеры на основе веток и тегов.

Пример деплоя на GitHub Pages с проверкой типа ветки:

deploy:
  if: github.ref == 'refs/heads/main' && github.event_name == 'push'
  needs: test
  runs-on: ubuntu-latest
  permissions:
    contents: read
    pages: write
    id-token: write

  steps:
    - uses: actions/checkout@v4
    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: '20'
        cache: 'npm'
    
    - run: npm ci
    - run: npm run build
    - name: Upload artifact
      uses: actions/upload-pages-artifact@v3
      with:
        path: './dist'
    - name: Deploy to GitHub Pages
      id: deployment
      uses: actions/deploy-pages@v4

Почему это продвинутый уровень?

  • needs: test — деплой запускается только после успешного прохождения всех матричных тестов.
  • if: github.ref == 'refs/heads/main' — защита от случайного деплоя из других веток.
  • permissions — явное указание прав на запись в Pages и получение токена. Без этого деплой не сработает.
  • upload-pages-artifact — оптимизированный артефакт для Pages, который автоматически сжимает и загружает файлы.

4. Оптимизация времени: параллельные джобы и кэширование артефактов

Финальный приём — разделение пайплайна на независимые джобы, которые могут выполняться параллельно. Например, линтинг, проверка типов и юнит-тесты не зависят друг от друга и могут идти одновременно.

Пример струк

Блоги

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