Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Живое ревью с ИИ
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. Кейс: Frontend проект
case_frontend

Кейс: Frontend проект

CI/CD для React/Vue приложения: сборка, тесты, деплой на CDN.

Кейс: Frontend проект

CI/CD для React/Vue приложения: тесты, линтинг, сборка через Vite/Webpack, деплой на Vercel/Netlify или S3 + CloudFront.

#Введение

В этом кейсе мы настроим полный CI/CD пайплайн для frontend-приложения на React или Vue. Пайплайн будет включать:

  • Запуск unit-тестов (Jest/Vitest)
  • Линтинг (ESLint) и проверку типов (TypeScript)
  • Сборку через Vite или Webpack
  • Деплой на Vercel/Netlify или S3 + CloudFront

#Структура проекта

project/
├── .github/
│   └── workflows/
│       ├── ci.yml          # CI: тесты, линты, типизация
│       └── deploy.yml      # CD: сборка и деплой
├── src/
│   ├── App.tsx            # Главный компонент
│   ├── main.tsx           # Точка входа
│   ├── components/        # React/Vue компоненты
│   ├── hooks/             # Custom hooks
│   ├── utils/             # Утилиты
│   └── styles/            # Стили
├── tests/
│   ├── App.test.tsx       # Unit тесты
│   └── setup.ts           # Настройка тестового окружения
├── public/
│   └── index.html
├── .eslintrc.js
├── .prettierrc
├── tsconfig.json
├── vite.config.ts         # или webpack.config.js
├── package.json
├── package-lock.json
└── README.md

#Настройка CI: тесты и линтеры

#Конфигурация package.json

{ "name": "my-frontend-app", "version": "1.0.0", "scripts": { "dev": "vite", "build": "tsc && vite build", "preview": "vite preview", "test": "vitest run", "test:coverage": "vitest run --coverage", "lint": "eslint src --ext .ts,.tsx", "lint:fix": "eslint src --ext .ts,.tsx --fix", "typecheck": "tsc --noEmit" }, "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0" }, "devDependencies": { "@testing-library/react": "^14.0.0", "@types/react": "^18.2.0", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", "@vitejs/plugin-react": "^4.0.0", "eslint": "^8.45.0", "eslint-config-prettier": "^9.0.0", "eslint-plugin-react": "^7.33.0", "eslint-plugin-react-hooks": "^4.6.0", "prettier": "^3.0.0", "typescript": "^5.1.0", "vite": "^5.0.0", "vitest": "^1.0.0" } }

#GitHub Actions workflow

# .github/workflows/ci.yml name: CI on: push: branches: [main, develop] pull_request: branches: [main] jobs: quality: 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: Install dependencies run: npm ci - name: Run ESLint run: npm run lint - name: Run TypeScript check run: npm run typecheck - name: Run Prettier check run: npx prettier --check src/ test: 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: Install dependencies run: npm ci - name: Run tests with coverage run: npm run test:coverage - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 with: files: ./coverage/lcov.info fail_ci_if_error: false build: runs-on: ubuntu-latest needs: [quality, test] steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' - name: Install dependencies run: npm ci - name: Build run: npm run build - name: Upload build artifacts uses: actions/upload-artifact@v4 with: name: dist path: dist/ retention-days: 7

#Кэширование node_modules

- name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' # Автоматическое кэширование по package-lock.json

GitHub Actions автоматически кэширует node_modules на основе хэша package-lock.json. Это ускоряет установку зависимостей с 2-3 минут до 20-30 секунд.

#Почему npm ci вместо npm install?

# npm install — может обновить lock файл npm install # npm ci — чистая установка по lock файлу (быстрее, детерминировано) npm ci

npm ci:

  • Удаляет node_modules перед установкой
  • Устанавливает точные версии из package-lock.json
  • Завершается с ошибкой если lock файл не соответствует package.json
  • Быстрее чем npm install на 20-30%

#Конфигурация линтеров

#ESLint для React + TypeScript

// .eslintrc.js module.exports = { root: true, env: { browser: true, es2021: true, node: true, }, extends: [ 'eslint:recommended', 'plugin:react/recommended', 'plugin:react-hooks/recommended', 'plugin:@typescript-eslint/recommended', 'prettier', ], parser: '@typescript-eslint/parser', parserOptions: { ecmaFeatures: { jsx: true, }, ecmaVersion: 'latest', sourceType: 'module', }, plugins: ['react', 'react-hooks', '@typescript-eslint'], rules: { 'react/react-in-jsx-scope': 'off', 'react/prop-types': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off', 'no-unused-vars': 'off', '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], }, settings: { react: { version: 'detect', }, }, };

#Prettier для форматирования

// .prettierrc { "semi": true, "trailingComma": "es5", "singleQuote": true, "printWidth": 100, "tabWidth": 2, "useTabs": false, "bracketSpacing": true, "arrowParens": "always" }
// .prettierignore node_modules dist build coverage *.min.js

#Сборка через Vite

#vite.config.ts

import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import { resolve } from 'path'; export default defineConfig({ plugins: [react()], resolve: { alias: { '@': resolve(__dirname, 'src'), }, }, build: { outDir: 'dist', sourcemap: true, minify: 'terser', rollupOptions: { output: { manualChunks: { vendor: ['react', 'react-dom'], utils: ['lodash', 'axios'], }, }, }, terserOptions: { compress: { drop_console: true, drop_debugger: true, }, }, }, server: { port: 3000, open: true, }, });

#Code splitting

Vite автоматически разделяет код на чанки:

dist/
├── index.html
├── assets/
│   ├── index-abc123.js      # Main bundle
│   ├── index-def456.css     # Main styles
│   ├── vendor-xyz789.js     # React, React-DOM
│   └── utils-uvw012.js      # lodash, axios

#Деплой на Vercel

#Автоматический деплой через интеграцию

Vercel автоматически деплоит при push в репозиторий:

  1. Подключите репозиторий в Vercel Dashboard
  2. Настройте проект (framework, build command, output directory)
  3. Vercel создаёт preview для каждого PR

#Настройка vercel.json

{ "buildCommand": "npm run build", "outputDirectory": "dist", "devCommand": "npm run dev", "installCommand": "npm install", "framework": "vite", "rewrites": [ { "source": "/api/(.*)", "destination": "https://api.example.com/$1" } ], "headers": [ { "source": "/assets/(.*)", "headers": [ { "key": "Cache-Control", "value": "public, max-age=31536000, immutable" } ] } ] }

#Environment variables в Vercel

Настройте в Vercel Dashboard:

VariableDevelopmentPreviewProduction
API_URLhttp://localhost:8000https://staging-api.example.comhttps://api.example.com
SENTRY_DSN-https://...@sentry.io/123https://...@sentry.io/456

#GitHub Actions для Vercel (опционально)

# .github/workflows/deploy-vercel.yml name: Deploy to Vercel on: push: branches: [main] pull_request: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Vercel CLI run: npm install --global vercel@latest - name: Pull Vercel Environment Information run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} - name: Build Project Artifacts run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }} - name: Deploy Project Artifacts run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }}

#Деплой на Netlify

#netlify.toml

[build] command = "npm run build" publish = "dist" [build.environment] NODE_VERSION = "20" [[redirects]] from = "/api/*" to = "https://api.example.com/:splat" status = 200 [[redirects]] from = "/*" to = "/index.html" status = 200 [[headers]] for = "/assets/*" [headers.values] Cache-Control = "public, max-age=31536000, immutable"

#Preview деплой для PR

Netlify автоматически создаёт preview для каждого PR:

https://deploy-preview-42--myapp.netlify.app

#Деплой на S3 + CloudFront

#Подготовка AWS ресурсов

  1. Создайте S3 bucket для статического хостинга
  2. Создайте CloudFront distribution с S3 origin
  3. Настройте SSL сертификат в ACM

#Workflow для деплоя на S3

# .github/workflows/deploy-s3.yml name: Deploy to S3 on: push: branches: [main] jobs: deploy: 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: Install dependencies run: npm ci - name: Build run: npm run build - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v4 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: us-east-1 - name: Deploy to S3 run: | aws s3 sync dist/ s3://myapp-bucket \ --delete \ --cache-control "public, max-age=300" \ --exclude "*" \ --include "*.js" \ --include "*.css" \ --cache-control "public, max-age=31536000, immutable" - name: Invalidate CloudFront cache run: | aws cloudfront create-invalidation \ --distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} \ --paths "/*"

#Оптимизация cache invalidation

Вместо полной инвалидации используйте хэши в именах файлов:

- name: Deploy to S3 with selective invalidation run: | # Инвалидировать только index.html (остальные файлы имеют хэши) aws cloudfront create-invalidation \ --distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} \ --paths "/index.html"

Vite автоматически добавляет хэши к именам файлов:

  • index.abc123.js — не требует инвалидации
  • index.html — требует инвалидации при каждом деплое

#Environment-specific конфигурация

#.env файлы

# .env.development VITE_API_URL=http://localhost:8000 VITE_SENTRY_DSN= VITE_ENVIRONMENT=development # .env.staging VITE_API_URL=https://staging-api.example.com VITE_SENTRY_DSN=https://...@sentry.io/123 VITE_ENVIRONMENT=staging # .env.production VITE_API_URL=https://api.example.com VITE_SENTRY_DSN=https://...@sentry.io/456 VITE_ENVIRONMENT=production

#Использование в коде

// src/config.ts export const config = { apiUrl: import.meta.env.VITE_API_URL, sentryDsn: import.meta.env.VITE_SENTRY_DSN, environment: import.meta.env.VITE_ENVIRONMENT, };

#Выбор окружения в пайплайне

- name: Build for production run: | cp .env.production .env npm run build

#Performance оптимизация

#Lighthouse CI

- name: Run Lighthouse uses: treosh/lighthouse-ci-action@v11 with: urls: | http://localhost:3000/ http://localhost:3000/about uploadArtifacts: true temporaryPublicStorage: true

#Bundle analysis

- name: Bundle size check uses: preactjs/compressed-size-action@v2 with: repo-token: ${{ secrets.GITHUB_TOKEN }} pattern: './dist/**/*.js'

#Оптимизации в Vite

// vite.config.ts export default defineConfig({ build: { // Minification minify: 'terser', terserOptions: { compress: { drop_console: true, drop_debugger: true, }, }, // Source maps sourcemap: false, // Отключить для production // Chunk size warning rollupOptions: { output: { manualChunks: { vendor: ['react', 'react-dom'], }, }, }, }, // CSS options css: { modules: { localsConvention: 'camelCase', }, }, });

#Preview окружения для Pull Request

#Vercel Preview

Vercel автоматически создаёт preview для каждого PR:

https://pr-42-myapp.vercel.app

#Netlify Deploy Preview

Netlify также создаёт preview:

https://deploy-preview-42--myapp.netlify.app

#GitHub Pages Preview

# .github/workflows/preview.yml name: Deploy Preview on: pull_request: branches: [main] jobs: preview: 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: Install dependencies run: npm ci - name: Build run: npm run build - name: Deploy to GitHub Pages uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./dist destination_dir: pr-${{ github.event.number }}

#Резюме

Полный CI/CD пайплайн для frontend включает:

  1. CI (Continuous Integration)

    • ESLint для проверки стиля кода
    • TypeScript type checking
    • Unit тесты через Jest/Vitest
    • Кэширование node_modules
  2. Сборка

    • Vite или Webpack с code splitting
    • Минификация и tree-shaking
    • Source maps для отладки
  3. CD (Continuous Deployment)

    • Vercel/Netlify — managed платформа с preview для PR
    • S3 + CloudFront — полный контроль, ручная настройка CDN
    • Environment-specific переменные
  4. Производительность

    • Lighthouse CI для мониторинга метрик
    • Bundle analysis для контроля размера
    • Cache headers для CDN
  5. Preview окружения

    • Автоматические preview для каждого PR
    • Тестирование изменений до мержа

Далее: Кейс: Микросервисы