第六章:性能优化与部署 - 第四节 - Tailwind CSS 部署环境配置

发布于:2025-03-03 ⋅ 阅读:(15) ⋅ 点赞:(0)

在将 Tailwind CSS 项目部署到生产环境时,需要做好各项配置和优化工作。本节将详细介绍如何配置和优化部署环境。

环境配置

Docker 配置

# Dockerfile
# 构建阶段
FROM node:16-alpine as builder

WORKDIR /app

COPY package*.json ./
RUN npm ci

COPY . .
RUN npm run build

# 生产阶段
FROM nginx:alpine

# 复制构建产物
COPY --from=builder /app/dist /usr/share/nginx/html
# 复制 Nginx 配置
COPY nginx.conf /etc/nginx/conf.d/default.conf

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

Nginx 配置

# nginx.conf
server {
    listen 80;
    server_name localhost;
    root /usr/share/nginx/html;
    index index.html;

    # Gzip 压缩
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css text/xml application/json application/javascript application/xml+rss application/atom+xml image/svg+xml;

    # 缓存配置
    location ~* \.(?:css|js)$ {
        expires 1y;
        access_log off;
        add_header Cache-Control "public";
    }

    location / {
        try_files $uri $uri/ /index.html;
    }
}

构建配置

生产环境配置

// tailwind.config.js
module.exports = {
  mode: 'jit',
  purge: {
    enabled: process.env.NODE_ENV === 'production',
    content: [
      './src/**/*.{js,jsx,ts,tsx}',
      './public/index.html'
    ],
    options: {
      safelist: [
        /^bg-/,
        /^text-/,
        'prose',
        'prose-lg'
      ]
    }
  },
  theme: {
    extend: {
      // 生产环境特定配置
    }
  }
}

构建脚本

// scripts/build.js
const webpack = require('webpack');
const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

module.exports = {
  mode: 'production',
  optimization: {
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          compress: {
            drop_console: true,
          },
        },
      }),
      new CssMinimizerPlugin({
        minimizerOptions: {
          preset: [
            'default',
            {
              discardComments: { removeAll: true },
            },
          ],
        },
      }),
    ],
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('production'),
    }),
  ],
};

CI/CD 配置

GitHub Actions

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

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v2
      
      - name: Setup Node.js
        uses: actions/setup-node@v2
        with:
          node-version: '16'
          cache: 'npm'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Build
        run: npm run build
        env:
          NODE_ENV: production
      
      - name: Deploy to server
        uses: appleboy/scp-action@master
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.SSH_KEY }}
          source: "dist/"
          target: "/var/www/html"

部署脚本

#!/bin/bash
# deploy.sh

# 环境变量
ENV=$1
CONFIG_FILE="config.$ENV.json"

# 验证参数
if [ -z "$ENV" ]; then
    echo "Please specify environment (dev/staging/prod)"
    exit 1
fi

# 构建项目
echo "Building for $ENV environment..."
npm run build:$ENV

# 部署到服务器
echo "Deploying to $ENV server..."
rsync -avz --delete dist/ user@server:/path/to/$ENV/

# 清理缓存
echo "Clearing cache..."
curl -X POST https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache \
  -H "Authorization: Bearer $CF_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"purge_everything":true}'

echo "Deployment completed!"

性能优化

静态资源优化

// webpack.prod.js
const CompressionPlugin = require('compression-webpack-plugin');
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');

module.exports = {
  plugins: [
    new CompressionPlugin({
      test: /\.(js|css|html|svg)$/,
      algorithm: 'gzip',
    }),
    new ImageMinimizerPlugin({
      minimizer: {
        implementation: ImageMinimizerPlugin.imageminMinify,
        options: {
          plugins: [
            ['mozjpeg', { quality: 80 }],
            ['pngquant', { quality: [0.6, 0.8] }],
            ['svgo', {
              plugins: [
                { removeViewBox: false },
                { removeEmptyAttrs: false }
              ]
            }]
          ]
        }
      }
    })
  ]
};

缓存策略

// next.config.js
module.exports = {
  generateBuildId: async () => {
    // 使用 Git commit hash 作为构建 ID
    return require('child_process')
      .execSync('git rev-parse HEAD')
      .toString().trim()
  },
  
  // 静态资源缓存配置
  async headers() {
    return [
      {
        source: '/_next/static/:path*',
        headers: [
          {
            key: 'Cache-Control',
            value: 'public, max-age=31536000, immutable'
          }
        ]
      }
    ]
  }
}

监控配置

性能监控

// utils/monitoring.ts
export const setupPerformanceMonitoring = () => {
  // Web Vitals 监控
  import('web-vitals').then(({ getCLS, getFID, getLCP }) => {
    getCLS(console.log);
    getFID(console.log);
    getLCP(console.log);
  });

  // 错误监控
  window.addEventListener('error', (event) => {
    console.error('Global error:', event.error);
    // 发送到监控服务
  });

  // 性能标记
  performance.mark('app-start');
  
  return () => {
    performance.measure('app-load', 'app-start');
    const measurements = performance.getEntriesByType('measure');
    console.log('Performance measurements:', measurements);
  };
};

日志配置

// utils/logger.ts
type LogLevel = 'info' | 'warn' | 'error';

class Logger {
  private env: string;

  constructor() {
    this.env = process.env.NODE_ENV || 'development';
  }

  log(level: LogLevel, message: string, data?: any) {
    const timestamp = new Date().toISOString();
    const logData = {
      timestamp,
      level,
      message,
      data,
      env: this.env
    };

    if (this.env === 'production') {
      // 发送到日志服务
      fetch('/api/logs', {
        method: 'POST',
        body: JSON.stringify(logData)
      });
    } else {
      console.log(`[${timestamp}] ${level.toUpperCase()}: ${message}`, data);
    }
  }
}

export const logger = new Logger();

安全配置

内容安全策略

// next.config.js
const securityHeaders = [
  {
    key: 'Content-Security-Policy',
    value: `
      default-src 'self';
      style-src 'self' 'unsafe-inline';
      script-src 'self' 'unsafe-eval';
      img-src 'self' data: https:;
      font-src 'self';
    `.replace(/\s{2,}/g, ' ').trim()
  },
  {
    key: 'X-XSS-Protection',
    value: '1; mode=block'
  },
  {
    key: 'X-Frame-Options',
    value: 'SAMEORIGIN'
  },
  {
    key: 'X-Content-Type-Options',
    value: 'nosniff'
  }
];

module.exports = {
  async headers() {
    return [
      {
        source: '/:path*',
        headers: securityHeaders,
      },
    ]
  }
}

最佳实践

  1. 部署准备

    • 环境配置完整
    • 构建流程优化
    • 部署脚本准备
  2. 性能优化

    • 资源压缩
    • 缓存策略
    • 监控配置
  3. 安全考虑

    • 安全头部配置
    • 错误处理
    • 日志记录
  4. 维护策略

    • 自动化部署
    • 监控告警
    • 回滚机制