Manual deployments are the enemy of scaling. Running npm run build locally, dragging files to a server via FTP, or manually merging branches leads to human error, downtime, and broken code in production. Continuous Integration and Continuous Deployment (CI/CD) is the practice of automating the entire lifecycle: every code push triggers an isolated virtual machine that lints the code, runs the test suite, builds the production bundle, and deploys it to a global CDN. This guarantees that your main branch is always stable and releasable.
Module 1: GitHub Actions Architecture
GitHub Actions is deeply integrated into GitHub repositories. A Workflow is defined in a YAML file inside the .github/workflows/ directory.
Core Concepts
- Workflow: The entire automated process (e.g., 'CI Pipeline').
- Event (on): What triggers the workflow. Common triggers:
push,pull_request, or a cron schedule. - Job: A set of steps. Jobs run in parallel by default on separate virtual machines (runners).
- Step: A sequential command (
run: npm test) or a pre-built community action (uses: actions/checkout).
Module 2: Building the Continuous Integration (CI) Pipeline
The CI pipeline acts as a gatekeeper. We configure repository settings to block Pull Requests from merging until this pipeline passes successfully.
name: Frontend Quality Gate
on:
pull_request:
branches: [ main, develop ]
jobs:
# Job 1: Static Analysis & Unit Tests
validate:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Setup Node.js Environment
uses: actions/setup-node@v3
with:
node-version: '18.x'
cache: 'npm' # Automatically caches ~/.npm to speed up future runs by minutes
# Always use 'npm ci' in pipelines. It strictly adheres to package-lock.json
# and deletes node_modules before installing, ensuring a clean slate.
- name: Install Dependencies
run: npm ci
- name: Run ESLint & Prettier
run: npm run lint
- name: Run Unit Tests (Jest/Vitest)
run: npm run test:unit
# Ensure the project actually compiles
- name: Verify Production Build
run: npm run buildModule 3: End-to-End (E2E) Testing in Pipelines
Unit tests ensure functions work. E2E tests (like Playwright or Cypress) spin up a real Chromium browser, navigate to your app, and simulate a user clicking buttons. Because they are slow, we run them in parallel with the validation job, or only after the validation job succeeds.
e2e-tests:
needs: validate # Wait for the 'validate' job to pass first
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- run: npm ci
# Playwright requires the actual browser binaries to be installed on the Linux runner
- name: Install Playwright Browsers
run: npx playwright install --with-deps
- name: Run Playwright Test Suite
run: npx playwright test
# Upload trace logs if a test fails so developers can debug the failure visually
- uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 7Module 4: Continuous Deployment (CD)
Once the PR is merged into main, the CD pipeline takes over to deploy the app to production. Here is an example of deploying a Next.js app to Vercel.
name: Deploy to Production
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Deploy to Vercel
uses: amondnet/vercel-action@v20
with:
# These secrets are securely stored in GitHub Repository Secrets
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
vercel-args: '--prod' # Forces a production deployment