From frontend-developer
Frontend CI/CD build pipeline — lint, type-check, test, build, preview deployment, and release stages with GitHub Actions.
How this skill is triggered — by the user, by Claude, or both
Slash command
/frontend-developer:build-pipelineThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
A good frontend pipeline is:
A good frontend pipeline is:
Push → Lint+Type-check (parallel, fast)
↓
Unit Tests
↓
Build
↓
E2E Tests + Preview Deploy (parallel)
↓
Release (on main only)
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true # cancel previous runs on new push
env:
NODE_VERSION: '22'
PNPM_VERSION: '9'
jobs:
# ─────────────────────────────────────────────
# Fast checks — run in parallel
# ─────────────────────────────────────────────
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with: { version: '${{ env.PNPM_VERSION }}' }
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm turbo lint
type-check:
name: Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with: { version: '${{ env.PNPM_VERSION }}' }
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm turbo type-check
# ─────────────────────────────────────────────
# Unit tests
# ─────────────────────────────────────────────
test:
name: Unit Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with: { version: '${{ env.PNPM_VERSION }}' }
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm turbo test
- name: Upload coverage
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./apps/web/coverage/lcov.info
# ─────────────────────────────────────────────
# Build (depends on checks passing)
# ─────────────────────────────────────────────
build:
name: Build
runs-on: ubuntu-latest
needs: [lint, type-check, test]
outputs:
artifact-id: ${{ steps.upload.outputs.artifact-id }}
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with: { version: '${{ env.PNPM_VERSION }}' }
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: pnpm
# Restore Turbo cache
- uses: actions/cache@v4
with:
path: .turbo
key: ${{ runner.os }}-turbo-${{ github.sha }}
restore-keys: ${{ runner.os }}-turbo-
- run: pnpm install --frozen-lockfile
- run: pnpm turbo build
env:
VITE_API_URL: ${{ vars.VITE_API_URL }}
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
- name: Upload build artifact
id: upload
uses: actions/upload-artifact@v4
with:
name: build-${{ github.sha }}
path: apps/web/dist
retention-days: 3
# ─────────────────────────────────────────────
# E2E tests + Preview deploy (parallel, after build)
# ─────────────────────────────────────────────
e2e:
name: E2E Tests
runs-on: ubuntu-latest
needs: [build]
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with: { version: '${{ env.PNPM_VERSION }}' }
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: pnpm
- run: pnpm install --frozen-lockfile
- name: Install Playwright browsers
run: pnpm exec playwright install --with-deps chromium
- name: Download build
uses: actions/download-artifact@v4
with:
name: build-${{ github.sha }}
path: apps/web/dist
- run: pnpm turbo test:e2e
env:
BASE_URL: ${{ vars.E2E_BASE_URL }}
TEST_USER_EMAIL: ${{ secrets.TEST_USER_EMAIL }}
TEST_USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}
- name: Upload Playwright report
uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report-${{ github.sha }}
path: apps/web/playwright-report
retention-days: 7
preview:
name: Preview Deploy
runs-on: ubuntu-latest
needs: [build]
if: github.event_name == 'pull_request'
environment:
name: preview
url: ${{ steps.deploy.outputs.url }}
steps:
- uses: actions/checkout@v4
- name: Download build
uses: actions/download-artifact@v4
with:
name: build-${{ github.sha }}
path: dist
- name: Deploy to Vercel
id: deploy
uses: amondnet/vercel-action@v25
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
working-directory: .
# ─────────────────────────────────────────────
# Release (main branch only)
# ─────────────────────────────────────────────
release:
name: Release
runs-on: ubuntu-latest
needs: [build, e2e]
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: pnpm/action-setup@v4
with: { version: '${{ env.PNPM_VERSION }}' }
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: pnpm
- run: pnpm install --frozen-lockfile
- name: Create Release
run: pnpm changeset publish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm # caches pnpm store, not node_modules
- name: Get pnpm store path
id: pnpm-cache
run: echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
- uses: actions/cache@v4
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: ${{ runner.os }}-pnpm-
- name: Cache Playwright browsers
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ hashFiles('**/package.json') }}
- run: pnpm exec playwright install --with-deps chromium
# Repository variables (not secret, shown in UI) — github.com/.../settings/variables
VITE_API_URL: https://api.example.com
TURBO_TEAM: my-team
# Repository secrets (encrypted) — github.com/.../settings/secrets
VERCEL_TOKEN: ...
TURBO_TOKEN: ...
TEST_USER_PASSWORD: ...
NPM_TOKEN: ...
Rule: build-time public config → variables. Credentials and tokens → secrets.
# Recommended required status checks on main:
Required checks:
- Lint
- Type Check
- Unit Tests
- Build
- E2E Tests
Settings:
- Require branches to be up to date before merging
- Require linear history (no merge commits)
- Dismiss stale reviews on new push
- Require review from code owners
# .github/workflows/lighthouse.yml
- name: Lighthouse CI
uses: treosh/lighthouse-ci-action@v12
with:
urls: |
${{ steps.deploy.outputs.url }}
${{ steps.deploy.outputs.url }}/about
uploadArtifacts: true
temporaryPublicStorage: true
budgetPath: .lighthouse-budget.json
// .lighthouse-budget.json
[
{
"path": "/*",
"timings": [
{ "metric": "interactive", "budget": 3000 },
{ "metric": "first-contentful-paint", "budget": 1500 }
],
"resourceSizes": [
{ "resourceType": "script", "budget": 300 },
{ "resourceType": "total", "budget": 600 }
]
}
]
# Dependency vulnerability scanning
- name: Audit dependencies
run: pnpm audit --audit-level=high
# Secrets scanning
- name: Scan for secrets
uses: trufflesecurity/trufflehog@main
with:
path: ./
base: ${{ github.event.repository.default_branch }}
head: HEAD
concurrency group on PRs — multiple pushes to the same PR queue up jobs; outdated jobs run even after newer push; add concurrency with cancel-in-progressenv variables in non-secret jobs — GITHUB_TOKEN and other secrets leaked into logs via echo or error output; use ${{ secrets.X }} directly in steps, never echo themretention-days on all artifact uploadsbuild job completion and only run when neededpnpm install without --frozen-lockfile — CI silently resolves to different versions than what's in the lockfile; install can succeed while production breaks${{ github.sha }} as cache key means cache is never hit; use hashFiles('**/pnpm-lock.yaml') for stable cache keysVITE_API_URL not passed to build step; app silently uses undefined/fallback values in CI buildnpx claudepluginhub messeb/skills --plugin frontend-developerDesigns multi-stage CI/CD pipelines with GitHub Actions, including matrix builds, caching, artifact management, and secret handling. Useful for new projects or migrating from Jenkins/CircleCI.
Provides GitHub Actions CI pipeline templates with standard stages (lint, type-check, test, build), environment management, secrets handling, and deployment strategies. Activates when creating or editing CI workflows.
Automates CI/CD pipeline setup with quality gates for linting, type checking, testing, building, security audits, and deployments using GitHub Actions. Use for new projects, modifying pipelines, or debugging failures.