亚洲see少妇裸体pics,欧美日产欧美日产免费一区,亚洲综合av一区二区三区不卡,一区二区中文字幕无码成人片,一区二区三区四区高清无码

部署配置

部署配置

環(huán)境配置

1. 多環(huán)境配置

// config/environment.js
const environments = {
    development: {
        API_BASE_URL: 'http://localhost:3000/api',
        LOG_LEVEL: 'debug',
        DEBUG: true,
        ENABLE_DEV_TOOLS: true
    },
    test: {
        API_BASE_URL: 'https://test-api.example.com',
        LOG_LEVEL: 'info',
        DEBUG: false,
        ENABLE_DEV_TOOLS: false
    },
    production: {
        API_BASE_URL: 'https://api.example.com',
        LOG_LEVEL: 'error',
        DEBUG: false,
        ENABLE_DEV_TOOLS: false
    }
};

// 根據環(huán)境變量獲取配置
export const getConfig = () => {
    const env = process.env.NODE_ENV || 'development';
    return environments[env];
};

// 環(huán)境變量驗證
export const validateEnvironment = () => {
    const requiredVars = [
        'REACT_APP_API_BASE_URL',
        'REACT_APP_VERSION'
    ];
    
    const missingVars = requiredVars.filter(varName => !process.env[varName]);
    
    if (missingVars.length > 0) {
        throw new Error(`缺少必需的環(huán)境變量: ${missingVars.join(', ')}`);
    }
};

2. 環(huán)境變量管理

# .env.development
REACT_APP_API_BASE_URL=http://localhost:3000/api
REACT_APP_VERSION=1.0.0-dev
REACT_APP_BUILD_DATE=2024-01-01
REACT_APP_ENABLE_MOCK=true
REACT_APP_LOG_LEVEL=debug

# .env.production
REACT_APP_API_BASE_URL=https://api.example.com
REACT_APP_VERSION=1.0.0
REACT_APP_BUILD_DATE=2024-01-01
REACT_APP_ENABLE_MOCK=false
REACT_APP_LOG_LEVEL=error

構建配置

1. Webpack配置優(yōu)化

// webpack.config.js
const path = require('path');
const webpack = require('webpack');
const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');

module.exports = (env, argv) => {
    const isProduction = argv.mode === 'production';
    
    return {
        mode: isProduction ? 'production' : 'development',
        entry: './src/index.js',
        
        output: {
            path: path.resolve(__dirname, 'build'),
            filename: isProduction ? 'static/js/[name].[contenthash:8].js' : 'static/js/[name].js',
            chunkFilename: isProduction ? 'static/js/[name].[contenthash:8].chunk.js' : 'static/js/[name].chunk.js',
            publicPath: '/',
            clean: true
        },
        
        optimization: {
            minimize: isProduction,
            minimizer: [
                new TerserPlugin({
                    terserOptions: {
                        compress: {
                            drop_console: isProduction // 生產(chǎn)環(huán)境移除console
                        }
                    }
                }),
                new CssMinimizerPlugin()
            ],
            
            splitChunks: {
                chunks: 'all',
                cacheGroups: {
                    vendor: {
                        test: /[\\/]node_modules[\\/]/,
                        name: 'vendors',
                        priority: 10,
                        chunks: 'all'
                    },
                    common: {
                        name: 'common',
                        minChunks: 2,
                        priority: 5,
                        reuseExistingChunk: true
                    }
                }
            },
            
            runtimeChunk: {
                name: entrypoint => `runtime-${entrypoint.name}`
            }
        },
        
        module: {
            rules: [
                {
                    test: /\.(js|jsx)$/,
                    exclude: /node_modules/,
                    use: {
                        loader: 'babel-loader',
                        options: {
                            cacheDirectory: true,
                            presets: [
                                ['@babel/preset-env', { targets: 'defaults' }],
                                ['@babel/preset-react', { runtime: 'automatic' }]
                            ]
                        }
                    }
                },
                {
                    test: /\.css$/,
                    use: ['style-loader', 'css-loader']
                },
                {
                    test: /\.less$/,
                    use: [
                        'style-loader',
                        'css-loader',
                        {
                            loader: 'less-loader',
                            options: {
                                lessOptions: {
                                    javascriptEnabled: true
                                }
                            }
                        }
                    ]
                },
                {
                    test: /\.(png|jpg|jpeg|gif|svg)$/,
                    type: 'asset',
                    parser: {
                        dataUrlCondition: {
                            maxSize: 10 * 1024 // 10KB
                        }
                    },
                    generator: {
                        filename: 'static/media/[name].[hash:8][ext]'
                    }
                }
            ]
        },
        
        plugins: [
            new webpack.DefinePlugin({
                'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
                'process.env.REACT_APP_VERSION': JSON.stringify(process.env.REACT_APP_VERSION)
            }),
            
            ...(isProduction ? [
                new BundleAnalyzerPlugin({
                    analyzerMode: 'static',
                    openAnalyzer: false
                })
            ] : [])
        ],
        
        resolve: {
            extensions: ['.js', '.jsx', '.json'],
            alias: {
                '@': path.resolve(__dirname, 'src'),
                '@components': path.resolve(__dirname, 'src/components'),
                '@utils': path.resolve(__dirname, 'src/utils'),
                '@services': path.resolve(__dirname, 'src/services')
            }
        },
        
        devServer: {
            port: 3000,
            hot: true,
            historyApiFallback: true,
            open: true,
            compress: true,
            proxy: {
                '/api': {
                    target: 'http://localhost:8080',
                    changeOrigin: true,
                    secure: false
                }
            }
        },
        
        devtool: isProduction ? 'source-map' : 'eval-source-map'
    };
};

2. Babel配置

// .babelrc
{
    "presets": [
        [
            "@babel/preset-env",
            {
                "targets": {
                    "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
                },
                "useBuiltIns": "usage",
                "corejs": 3
            }
        ],
        [
            "@babel/preset-react",
            {
                "runtime": "automatic"
            }
        ]
    ],
    "plugins": [
        "@babel/plugin-proposal-class-properties",
        "@babel/plugin-syntax-dynamic-import",
        "babel-plugin-lodash"
    ],
    "env": {
        "production": {
            "plugins": [
                "transform-react-remove-prop-types"
            ]
        }
    }
}

容器化部署

1. Docker配置

# Dockerfile
FROM node:16-alpine as builder

# 設置工作目錄
WORKDIR /app

# 復制package文件
COPY package*.json ./
COPY yarn.lock ./

# 安裝依賴(lài)
RUN yarn install --frozen-lockfile --production=false

# 復制源代碼
COPY . .

# 構建應用
RUN yarn build

# 生產(chǎn)階段
FROM nginx:alpine

# 復制構建結果到nginx
COPY --from=builder /app/build /usr/share/nginx/html

# 復制nginx配置
COPY nginx.conf /etc/nginx/nginx.conf

# 暴露端口
EXPOSE 80

# 啟動(dòng)nginx
CMD ["nginx", "-g", "daemon off;"]

2. Nginx配置

# nginx.conf
worker_processes auto;

events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    # 日志格式
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

    access_log /var/log/nginx/access.log main;
    error_log /var/log/nginx/error.log warn;

    # 性能優(yōu)化
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;

    # Gzip壓縮
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_types
        text/plain
        text/css
        text/xml
        text/javascript
        application/javascript
        application/xml+rss
        application/json;

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

        # 安全頭
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header X-XSS-Protection "1; mode=block" always;
        add_header Referrer-Policy "strict-origin-when-cross-origin" always;

        # 靜態(tài)資源緩存
        location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
            expires 1y;
            add_header Cache-Control "public, immutable";
        }

        # HTML文件不緩存
        location ~* \.html$ {
            expires -1;
            add_header Cache-Control "no-store, no-cache, must-revalidate";
        }

        # SPA路由支持
        location / {
            try_files $uri $uri/ /index.html;
        }

        # API代理
        location /api/ {
            proxy_pass http://backend:8080;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }

        # 健康檢查
        location /health {
            access_log off;
            return 200 "healthy\n";
            add_header Content-Type text/plain;
        }
    }
}

3. Docker Compose配置

# docker-compose.yml
version: '3.8'

services:
  frontend:
    build: 
      context: .
      dockerfile: Dockerfile
    ports:
      - "80:80"
    environment:
      - NODE_ENV=production
    depends_on:
      - backend
    networks:
      - app-network

  backend:
    image: backend:latest
    ports:
      - "8080:8080"
    environment:
      - DB_HOST=database
      - DB_PORT=5432
    networks:
      - app-network

  database:
    image: postgres:13
    environment:
      - POSTGRES_DB=invoicing
      - POSTGRES_USER=admin
      - POSTGRES_PASSWORD=secret
    volumes:
      - db_data:/var/lib/postgresql/data
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

volumes:
  db_data:

CI/CD配置

1. GitHub Actions配置

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

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

jobs:
  test:
    runs-on: ubuntu-latest
    
    strategy:
      matrix:
        node-version: [16.x, 18.x]
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v3
      with:
        node-version: ${{ matrix.node-version }}
        cache: 'yarn'
    
    - name: Install dependencies
      run: yarn install --frozen-lockfile
    
    - name: Run tests
      run: yarn test --coverage --watchAll=false
    
    - name: Upload coverage to Codecov
      uses: codecov/codecov-action@v3
      with:
        file: ./coverage/lcov.info

  build:
    needs: test
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Use Node.js 16
      uses: actions/setup-node@v3
      with:
        node-version: 16.x
        cache: 'yarn'
    
    - name: Install dependencies
      run: yarn install --frozen-lockfile
    
    - name: Build application
      run: yarn build
      env:
        CI: false
        REACT_APP_VERSION: ${{ github.sha }}
        REACT_APP_BUILD_DATE: ${{ github.event.head_commit.timestamp }}
    
    - name: Upload build artifacts
      uses: actions/upload-artifact@v3
      with:
        name: build
        path: build/

  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Download build artifacts
      uses: actions/download-artifact@v3
      with:
        name: build
        path: build/
    
    - name: Deploy to production
      uses: appleboy/scp-action@v0.1.3
      with:
        host: ${{ secrets.DEPLOY_HOST }}
        username: ${{ secrets.DEPLOY_USER }}
        key: ${{ secrets.DEPLOY_KEY }}
        source: "build/*"
        target: "/var/www/invoicing"
    
    - name: Restart nginx
      uses: appleboy/ssh-action@v0.1.7
      with:
        host: ${{ secrets.DEPLOY_HOST }}
        username: ${{ secrets.DEPLOY_USER }}
        key: ${{ secrets.DEPLOY_KEY }}
        script: |
          sudo systemctl restart nginx

2. 部署腳本

#!/bin/bash
# deploy.sh

set -e

# 顏色輸出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

# 日志函數
log() {
    echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] $1${NC}"
}

warn() {
    echo -e "${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARNING: $1${NC}"
}

error() {
    echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: $1${NC}"
    exit 1
}

# 檢查環(huán)境
check_environment() {
    log "檢查部署環(huán)境..."
    
    # 檢查Node.js版本
    if ! command -v node &> /dev/null; then
        error "Node.js未安裝"
    fi
    
    local node_version=$(node -v | cut -d'v' -f2)
    local required_version="16.0.0"
    
    if [ "$(printf '%s\n' "$required_version" "$node_version" | sort -V | head -n1)" != "$required_version" ]; then
        error "Node.js版本過(guò)低,需要 >= $required_version"
    fi
    
    log "環(huán)境檢查通過(guò)"
}

# 安裝依賴(lài)
install_dependencies() {
    log "安裝依賴(lài)..."
    
    if [ -f "yarn.lock" ]; then
        yarn install --frozen-lockfile --production=false
    else
        npm install
    fi
    
    if [ $? -ne 0 ]; then
        error "依賴(lài)安裝失敗"
    fi
    
    log "依賴(lài)安裝完成"
}

# 運行測試
run_tests() {
    log "運行測試..."
    
    if [ -f "package.json" ]; then
        if grep -q "\"test\"" package.json; then
            npm test -- --coverage --watchAll=false
        else
            warn "未找到測試腳本,跳過(guò)測試"
        fi
    else
        warn "未找到package.json,跳過(guò)測試"
    fi
    
    log "測試完成"
}

# 構建應用
build_app() {
    log "構建應用..."
    
    # 設置構建環(huán)境變量
    export NODE_ENV=production
    export REACT_APP_VERSION=$(git rev-parse --short HEAD)
    export REACT_APP_BUILD_DATE=$(date -Iseconds)
    
    if [ -f "package.json" ]; then
        if grep -q "\"build\"" package.json; then
            npm run build
        else
            error "未找到構建腳本"
        fi
    else
        error "未找到package.json"
    fi
    
    if [ $? -ne 0 ]; then
        error "構建失敗"
    fi
    
    log "構建完成"
}

# 部署到服務(wù)器
deploy_to_server() {
    local server_host=$1
    local deploy_path=$2
    
    log "部署到服務(wù)器: $server_host:$deploy_path"
    
    # 使用rsync同步文件
    rsync -avz --delete \
        --exclude='.git' \
        --exclude='node_modules' \
        --exclude='*.log' \
        ./build/ $server_host:$deploy_path/
    
    if [ $? -ne 0 ]; then
        error "文件同步失敗"
    fi
    
    log "文件同步完成"
}

# 重啟服務(wù)
restart_service() {
    local server_host=$1
    local service_name=$2
    
    log "重啟服務(wù): $service_name"
    
    ssh $server_host "sudo systemctl restart $service_name"
    
    if [ $? -ne 0 ]; then
        error "服務(wù)重啟失敗"
    fi
    
    log "服務(wù)重啟完成"
}

# 健康檢查
health_check() {
    local url=$1
    local max_attempts=30
    local attempt=1
    
    log "進(jìn)行健康檢查: $url"
    
    while [ $attempt -le $max_attempts ]; do
        if curl -f -s $url > /dev/null; then
            log "健康檢查通過(guò)"
            return 0
        fi
        
        warn "健康檢查失敗 (嘗試 $attempt/$max_attempts)"
        sleep 5
        attempt=$((attempt + 1))
    done
    
    error "健康檢查超時(shí)"
}

# 主函數
main() {
    local server_host=${1:-$DEPLOY_HOST}
    local deploy_path=${2:-$DEPLOY_PATH}
    local service_name=${3:-"nginx"}
    local health_check_url=${4:-"http://localhost"}
    
    if [ -z "$server_host" ]; then
        error "請提供服務(wù)器地址"
    fi
    
    check_environment
    install_dependencies
    run_tests
    build_app
    deploy_to_server $server_host $deploy_path
    restart_service $server_host $service_name
    health_check $health_check_url
    
    log "部署完成!"
}

# 執行主函數
main "$@"

監控和日志

1. 應用監控配置

// src/utils/monitoring.js
export class ApplicationMonitor {
    static init() {
        // 性能監控
        this.setupPerformanceMonitoring();
        
        // 錯誤監控
        this.setupErrorMonitoring();
        
        // 用戶(hù)行為監控
        this.setupUserBehaviorMonitoring();
    }
    
    static setupPerformanceMonitoring() {
        // 監控關(guān)鍵性能指標
        if ('PerformanceObserver' in window) {
            const observer = new PerformanceObserver((list) => {
                for (const entry of list.getEntries()) {
                    this.logPerformanceMetric(entry);
                }
            });
            
            observer.observe({ entryTypes: ['navigation', 'resource', 'paint'] });
        }
        
        // 監控長(cháng)任務(wù)
        if ('PerformanceObserver' in window) {
            const longTaskObserver = new PerformanceObserver((list) => {
                for (const entry of list.getEntries()) {
                    if (entry.duration > 50) {
                        this.logLongTask(entry);
                    }
                }
            });
            
            longTaskObserver.observe({ entryTypes: ['longtask'] });
        }
    }
    
    static setupErrorMonitoring() {
        window.addEventListener('error', (event) => {
            this.logError({
                type: 'UNHANDLED_ERROR',
                message: event.error?.message,
                stack: event.error?.stack,
                filename: event.filename,
                lineno: event.lineno,
                colno: event.colno
            });
        });
        
        window.addEventListener('unhandledrejection', (event) => {
            this.logError({
                type: 'UNHANDLED_PROMISE_REJECTION',
                reason: event.reason?.message || event.reason
            });
        });
    }
    
    static logPerformanceMetric(metric) {
        const data = {
            type: 'PERFORMANCE_METRIC',
            name: metric.name,
            value: metric.duration,
            timestamp: Date.now()
        };
        
        this.sendToMonitoringService(data);
    }
    
    static logError(errorData) {
        const data = {
            ...errorData,
            timestamp: Date.now(),
            userAgent: navigator.userAgent,
            url: window.location.href
        };
        
        this.sendToMonitoringService(data);
    }
    
    static sendToMonitoringService(data) {
        // 發(fā)送到監控服務(wù)
        if (navigator.sendBeacon) {
            const blob = new Blob([JSON.stringify(data)], { type: 'application/json' });
            navigator.sendBeacon('/api/monitoring', blob);
        } else {
            fetch('/api/monitoring', {
                method: 'POST',
                body: JSON.stringify(data),
                headers: { 'Content-Type': 'application/json' }
            }).catch(() => {
                // 靜默失敗
            });
        }
    }
}

這些部署配置為應用提供了完整的構建、部署和監控解決方案。

文章目錄

    亚洲see少妇裸体pics,欧美日产欧美日产免费一区,亚洲综合av一区二区三区不卡,一区二区中文字幕无码成人片,一区二区三区四区高清无码