SuperAPI AI Directory

build-deploy

Deployment & operations

View repository

Updated 10-16 09:30

About this skill

Build & Deploy

Reference sources: Vite / Turbopack / Webpack official, Vercel / Cloudflare deployment docs, Stripe / Linear deployment practices, 12-Factor App.

Applicable scenarios

  • Project initialization (Vite / Next.js / Nuxt)
  • Multi-environment configuration (dev / staging / prod)
  • Bundle optimization (splitting / tree-shake)
  • Static assets / CDN
  • Deployment platforms (Vercel / Cloudflare / self-hosted)
  • Docker containerization
  • CI/CD pipeline
  • Canary / rollback

Core principles

1. 一次构建多环境
   构建产物相同
   配置通过环境变量注入

2. 环境变量分级
   - 公开(VITE_PUBLIC_*):嵌入 bundle,不能放密钥
   - 服务端(DATABASE_URL):仅 SSR 用,不进 bundle

3. CDN 静态资源
   缓存策略:immutable + 哈希文件名

4. CI/CD 必备
   PR 预览 + 主分支自动部署 + 回滚

5. 监控部署
   - 构建产物大小
   - 部署成功率
   - 灰度阶段指标

6. 回滚 < 5 分钟
   一键回滚或快照恢复

7. 安全 Header
   CSP / HSTS / X-Frame-Options

Build tool quick reference

Tool Best for Speed Ecosystem
Vite Mainstream apps Fast Large
Turbopack Next.js 15+ Extremely fast (Rust) Follows Next
Rspack Webpack replacement Extremely fast (Rust) webpack compatible
Webpack 5 Traditional legacy projects Slow but stable Largest
Rollup Library bundling Medium Library-specific
esbuild Minimalist / libraries Extremely fast (Go) Medium
Bun Multi-purpose Fast Emerging
tsup TS libraries Fast Concise

Vite configuration

// vite.config.ts
import { defineConfig, loadEnv } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';
import { visualizer } from 'rollup-plugin-visualizer';
import compression from 'vite-plugin-compression';

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd(), '');
  
  return {
    plugins: [
      react(),
      compression({ algorithm: 'brotliCompress' }),
      mode === 'production' && visualizer({ filename: 'dist/stats.html' }),
    ].filter(Boolean),
    
    resolve: {
      alias: {
        '@': path.resolve(__dirname, './src'),
      },
    },
    
    server: {
      port: 3000,
      strictPort: true,
      proxy: {
        '/api': {
          target: env.VITE_API_URL,
          changeOrigin: true,
        },
      },
    },
    
    build: {
      target: 'es2022',
      sourcemap: mode === 'staging',           // 生产关闭
      cssCodeSplit: true,
      reportCompressedSize: false,             // 加速构建
      chunkSizeWarningLimit: 1000,
      rollupOptions: {
        output: {
          manualChunks: {
            // 拆分供应商
            'react-vendor': ['react', 'react-dom', 'react-router'],
            'ui-vendor': ['@radix-ui/react-dialog', '@radix-ui/react-tabs'],
            'data-vendor': ['@tanstack/react-query', 'axios'],
          },
          // 哈希文件名(缓存友好)
          entryFileNames: 'assets/[name]-[hash].js',
          chunkFileNames: 'assets/[name]-[hash].js',
          assetFileNames: 'assets/[name]-[hash].[ext]',
        },
      },
    },
    
    optimizeDeps: {
      include: ['react', 'react-dom'],
    },
  };
});

Next.js configuration

// next.config.ts
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  reactStrictMode: true,
  
  // Turbopack(默认)或 Webpack
  experimental: {
    turbo: {
      rules: { '*.svg': { loaders: ['@svgr/webpack'], as: '*.js' } },
    },
  },
  
  // 图片优化
  images: {
    formats: ['image/avif', 'image/webp'],
    remotePatterns: [
      { protocol: 'https', hostname: 'cdn.example.com' },
    ],
  },
  
  // 安全 Header
  async headers() {
    return [
      {
        source: '/:path*',
        headers: [
          { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubDomains' },
          { key: 'X-Content-Type-Options', value: 'nosniff' },
          { key: 'X-Frame-Options', value: 'DENY' },
          { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
          { key: 'Content-Security-Policy', value: "default-src 'self'; ..." },
        ],
      },
    ];
  },
  
  // 重定向
  async redirects() {
    return [
      { source: '/old', destination: '/new', permanent: true },
    ];
  },
  
  // 输出(如需 Docker / 静态)
  output: 'standalone',  // 'standalone' | 'export' | undefined
};

export default nextConfig;

Environment variable management

分级:
  .env                  共享(所有环境)
  .env.development      仅 dev
  .env.staging          staging
  .env.production       生产
  .env.local            本地(gitignore)

Vite 公开变量前缀:VITE_
Next.js 公开变量前缀:NEXT_PUBLIC_

服务端变量(不进 bundle):
  DATABASE_URL
  STRIPE_SECRET_KEY
  
公开变量(进 bundle,安全可暴露):
  VITE_API_URL
  NEXT_PUBLIC_GA_ID
# .env.production
VITE_API_URL=https://api.example.com
VITE_GA_ID=G-XXXXX
VITE_SENTRY_DSN=https://...

# 严格不放
# DATABASE_URL=...   ❌ 会泄露到前端

Deployment platform comparison

Vercel (first choice for Next.js)

特点:
  - Next.js 团队
  - 边缘网络(Edge Functions)
  - 自动 PR 预览
  - 即时回滚
  - 内置 Analytics

部署:
  - GitHub 连接,push 自动部署
  - 配置:vercel.json

适合:Next.js / 一切前端

Cloudflare Pages

特点:
  - Cloudflare 网络(全球 PoP)
  - Workers 集成
  - 免费额度大
  - 自定义域好用

部署:
  - GitHub 连接
  - 或 wrangler CLI
  - 配置:wrangler.toml

Netlify

特点:
  - 老牌
  - Forms / Identity 内置
  - Edge Functions

部署:netlify.toml

Self-hosted (Docker + Nginx)

# Dockerfile
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json pnpm-lock.yaml ./
RUN corepack enable && pnpm install --frozen-lockfile

FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ARG VITE_API_URL
ENV VITE_API_URL=${VITE_API_URL}
RUN corepack enable && pnpm run build

FROM nginx:alpine AS runner
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
# nginx.conf
server {
  listen 80;
  root /usr/share/nginx/html;
  index index.html;
  
  # 静态资源永久缓存(哈希文件名)
  location /assets/ {
    expires 1y;
    add_header Cache-Control "public, immutable";
    add_header Vary Accept-Encoding;
    
    # Brotli / Gzip
    gzip on;
    gzip_types text/css application/javascript application/json image/svg+xml;
  }
  
  # HTML 短缓存
  location / {
    try_files $uri $uri/ /index.html;
    expires 1h;
    add_header Cache-Control "public, must-revalidate";
  }
  
  # 安全 Header
  add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
  add_header X-Content-Type-Options "nosniff" always;
  add_header X-Frame-Options "DENY" always;
  add_header Referrer-Policy "strict-origin-when-cross-origin" always;
  add_header Content-Security-Policy "default-src 'self'; ..." always;
}

CI/CD pipeline

# .github/workflows/deploy.yml
name: Deploy

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

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20, cache: 'pnpm' }
      - uses: pnpm/action-setup@v3
      - run: pnpm install --frozen-lockfile
      - run: pnpm run lint
      - run: pnpm run typecheck
      - run: pnpm run test
      - run: pnpm run build
      - name: Bundle Size Check
        run: |
          MAX_SIZE=200000
          SIZE=$(stat -c%s dist/assets/*.js | sort -n | tail -1)
          if [ $SIZE -gt $MAX_SIZE ]; then
            echo "Bundle too large: $SIZE > $MAX_SIZE"
            exit 1
          fi
      - uses: actions/upload-artifact@v4
        with:
          name: dist
          path: dist/
  
  e2e:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
      - run: pnpm install
      - run: npx playwright install --with-deps
      - run: pnpm run build
      - run: pnpm run test:e2e
  
  lighthouse:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: treosh/lighthouse-ci-action@v11
        with:
          urls: |
            https://preview-${{ github.event.number }}.example.com
          uploadArtifacts: true
          temporaryPublicStorage: true
  
  deploy-preview:
    if: github.event_name == 'pull_request'
    needs: [test, e2e]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/download-artifact@v4
        with: { name: dist }
      - name: Deploy to Vercel Preview
        run: vercel --token=${{ secrets.VERCEL_TOKEN }}
  
  deploy-production:
    if: github.ref == 'refs/heads/main'
    needs: [test, e2e, lighthouse]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to Vercel Production
        run: vercel --prod --token=${{ secrets.VERCEL_TOKEN }}
      - name: Notify Slack
        run: curl -X POST ${{ secrets.SLACK_WEBHOOK }} ...

Bundle optimization

检查:
  □ Bundle Analyzer 看分布
  □ 单文件 < 200 KB(gzip)
  □ 总大小预算

优化:
  □ Code splitting(路由 / 组件)
  □ Tree shaking(命名导入)
  □ 动态导入(用时加载)
  □ 替换大库(moment → dayjs)
  □ 压缩(Terser / SWC)
  □ Brotli 压缩
  □ Polyfill 按需(targets)
// browserslist
"browserslist": {
  "production": [
    "> 0.5%",
    "not dead",
    "not op_mini all"
  ],
  "development": [
    "last 1 chrome version",
    "last 1 firefox version"
  ]
}

Canary release

方案 A:Vercel/Cloudflare 流量分配
  - 主域:50% old + 50% new
  - 监控错误率 / Web Vitals
  - OK → 100%

方案 B:Feature Flag
  - LaunchDarkly / Unleash / Flagsmith
  - 按用户 / 租户开关
  - 灰度 5% → 50% → 100%

方案 C:A/B 测试
  - Optimizely / GrowthBook
  - 长期对比

Rollback strategy

平台快照(推荐):
  Vercel:一键回滚到任意 deployment
  Cloudflare:回滚 production 别名
  Netlify:deploy rollback

Git 回滚:
  revert commit + push → 触发部署

CDN 缓存:
  强制清缓存(特殊情况)

数据库:不回滚(前端不影响 DB)

回滚时间:< 5 min

Monitoring

□ 部署成功率
□ 部署时长
□ Bundle 大小趋势
□ 真实用户性能(RUM)
□ 错误率(Sentry)
□ Lighthouse 分数变化
□ 灰度阶段指标

Security

□ Source Map 生产关闭或 hidden
□ 不暴露 .env / .git
□ CSP 配置
□ HSTS 强制 HTTPS
□ 依赖扫描(Snyk / Dependabot)
□ Subresource Integrity(CDN 资源)
□ 不在 bundle 放敏感

Workflow

1. 选构建工具
   - 应用 → Vite / Next.js
   - 库 → Rollup / tsup

2. 配置环境变量
   - 分级
   - 注意公开 vs 私密

3. 优化构建
   - Code splitting
   - Tree shaking
   - 压缩

4. 选部署平台
   - 框架推荐
   - 团队需求

5. CI/CD 流水线
   - Test → Build → E2E → Lighthouse → Deploy
   - PR 预览 + 主分支生产

6. 监控
   - 部署 / 性能 / 错误

7. 灰度 / 回滚机制

Supporting templates

  • templates/build-deploy-checklist.md — build configuration + CI/CD + canary + rollback + monitoring

Quality self-check

□ 一次构建多环境
□ 环境变量分级(公开 vs 私密)
□ Bundle 分析 + 预算
□ Code splitting
□ Tree shaking
□ 压缩 + Brotli
□ Source Map 生产隐藏
□ CDN 静态资源
□ 安全 Header(CSP / HSTS)
□ CI/CD 必跑 lint/test/build
□ PR 预览
□ Lighthouse CI
□ Bundle 大小 CI 阻塞
□ 一键回滚 < 5min
□ 监控接入

Common pitfalls

  1. Environment variables leak secrets——wrong prefix
  2. Source Map exposes source code in production——must be hidden
  3. No chunk splitting——1MB on first screen
  4. No filename hashing——CDN cache cannot be purged
  5. CSP misconfiguration——production goes down
  6. CORS misconfiguration——API calls fail
  7. No proxy configuration——dev environment unreachable
  8. Build output > budget——CI does not block
  9. Lighthouse regression unnoticed——CI not integrated
  10. Rollback process unclear——panic during incidents
  11. No deployment monitoring——failures go unnoticed
  12. Docker image too large——> 1GB
  13. Dependencies not version-locked——builds not reproducible
  14. Not using lockfile——each team member builds differently
  15. Production-exposed dev tools——React DevTools / Vue DevTools

Collaboration with other skills

上游:
  performance-optimization → 构建优化策略

下游:
  devops-engineer 工作流 → CI/CD 流水线深入
  sre-ops 工作流 → 监控告警
  security-engineer → 安全 Header / CSP

Related references

  • Project root references/frontend-tech-stack-guide.md — build tooling