Angular部署与构建

本章将详细介绍Angular应用的构建过程、生产环境配置、以及各种部署策略,帮助你顺利将应用发布到生产环境。

部署流程概览:开发 → 测试 → 构建 → 优化 → 部署 → 监控

1. 构建配置与优化

1

基本构建命令

# 开发环境构建
ng build

# 生产环境构建(推荐)
ng build --prod

# 带有详细配置的生产构建
ng build --configuration=production

# 监视模式构建
ng build --watch
2

Angular配置文件详解

// angular.json 关键配置
{
  "projects": {
    "my-app": {
      "architect": {
        "build": {
          "configurations": {
            "production": {
              "optimization": true,          // 启用优化
              "outputHashing": "all",        // 文件哈希命名
              "sourceMap": false,            // 关闭源映射
              "namedChunks": false,          // 关闭命名块
              "extractLicenses": true,       // 提取许可证
              "vendorChunk": false,          // 禁用供应商块
              "buildOptimizer": true,        // 构建优化器
              "budgets": [                   // 资源预算
                {
                  "type": "initial",
                  "maximumWarning": "2mb",
                  "maximumError": "5mb"
                },
                {
                  "type": "anyComponentStyle",
                  "maximumWarning": "6kb",
                  "maximumError": "10kb"
                }
              ],
              "serviceWorker": true,         // PWA支持
              "ngswConfigPath": "ngsw-config.json"
            },
            "development": {
              "optimization": false,
              "sourceMap": true,
              "namedChunks": true,
              "vendorChunk": true
            }
          },
          "defaultConfiguration": "production"
        }
      }
    }
  }
}
3

环境配置文件

// src/environments/environment.ts (开发环境)
export const environment = {
  production: false,
  apiUrl: 'http://localhost:3000/api',
  appVersion: '1.0.0-dev',
  enableDebug: true,
  sentryDsn: '', // 开发环境不启用Sentry
  googleAnalyticsId: ''
};
// src/environments/environment.prod.ts (生产环境)
export const environment = {
  production: true,
  apiUrl: 'https://api.yourdomain.com/api',
  appVersion: '1.0.0',
  enableDebug: false,
  sentryDsn: 'YOUR_SENTRY_DSN',
  googleAnalyticsId: 'UA-XXXXXXXXX-X'
};
// 在组件中使用环境变量
import { environment } from '../environments/environment';

@Injectable()
export class ApiService {
  private apiUrl = environment.apiUrl;

  getData() {
    return this.http.get(`${this.apiUrl}/data`);
  }
}

2. 构建优化策略

AOT编译 (Ahead-of-Time)

预编译模板,提高运行时性能

ng build --aot
Tree Shaking

移除未使用的代码

// Webpack会移除未使用的导出
export class UsedComponent {}  // 保留
export class UnusedComponent {} // 移除
代码分割

按需加载模块

// 路由懒加载
const routes: Routes = [
  {
    path: 'admin',
    loadChildren: () => import('./admin/admin.module')
      .then(m => m.AdminModule)
  }
];
资源优化
  • 图片压缩
  • CSS/JS压缩
  • Gzip/Brotli压缩
构建前
  • TypeScript源码
  • 未压缩资源
  • 开发依赖包含
  • 源映射完整
  • 体积:~100MB
构建后
  • 优化后的JavaScript
  • 压缩的CSS/JS
  • 仅生产依赖
  • 移除源映射
  • 体积:~5MB

3. 部署到Web服务器

Nginx

高性能Web服务器

Apache

传统Web服务器

Node.js

JavaScript运行时

AWS S3

静态文件托管

Nginx配置示例

# /etc/nginx/sites-available/angular-app
server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    root /var/www/angular-app/dist;
    index index.html;

    # Gzip压缩
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_types text/plain text/css application/json application/javascript;

    # 安全头
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;

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

    # 静态资源缓存
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg|eot)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # API代理
    location /api/ {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }

    # 错误页面
    error_page 404 /index.html;
    error_page 500 502 503 504 /50x.html;
}

Apache配置示例

<VirtualHost *:80>
    ServerName yourdomain.com
    DocumentRoot /var/www/angular-app/dist

    <Directory /var/www/angular-app/dist>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted

        RewriteEngine On
        RewriteBase /
        RewriteRule ^index\.html$ - [L]
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule . /index.html [L]
    </Directory>

    # 启用压缩
    AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript
    AddOutputFilterByType DEFLATE application/javascript application/json

    # 设置缓存头
    <FilesMatch "\.(html|htm)$">
        Header set Cache-Control "no-cache"
    </FilesMatch>

    <FilesMatch "\.(css|js|jpg|jpeg|png|gif|ico|woff|woff2|ttf|svg|eot)$">
        Header set Cache-Control "max-age=31536000, public"
    </FilesMatch>
</VirtualHost>

4. Docker容器化部署

Dockerfile配置

# 多阶段构建:构建阶段
FROM node:18-alpine AS builder

# 设置工作目录
WORKDIR /app

# 复制package文件
COPY package*.json ./

# 安装依赖(包括开发依赖)
RUN npm ci --only=production

# 复制源代码
COPY . .

# 构建应用
RUN npm run build -- --prod

# 运行阶段
FROM nginx:alpine

# 复制构建产物到nginx目录
COPY --from=builder /app/dist/angular-app /usr/share/nginx/html

# 复制自定义nginx配置
COPY nginx.conf /etc/nginx/conf.d/default.conf

# 暴露端口
EXPOSE 80

# 启动nginx
CMD ["nginx", "-g", "daemon off;"]

Docker Compose配置

# docker-compose.yml
version: '3.8'

services:
  angular-app:
    build: .
    ports:
      - "8080:80"
    environment:
      - NODE_ENV=production
      - API_URL=https://api.example.com
    networks:
      - app-network
    restart: unless-stopped

  nginx:
    image: nginx:alpine
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
      - ./dist:/usr/share/nginx/html
    ports:
      - "80:80"
    depends_on:
      - angular-app
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

5. CI/CD自动化部署

GitHub Actions配置

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

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

jobs:
  build-and-test:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3

    - name: Setup Node.js
      uses: actions/setup-node@v3
      with:
        node-version: '18'
        cache: 'npm'

    - name: Install dependencies
      run: npm ci

    - name: Run tests
      run: npm test -- --watch=false --browsers=ChromeHeadless

    - name: Build application
      run: npm run build -- --prod

    - name: Upload build artifacts
      uses: actions/upload-artifact@v3
      with:
        name: dist
        path: dist/

  deploy-production:
    needs: build-and-test
    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: dist

    - name: Deploy to AWS S3
      uses: jakejarvis/s3-sync-action@v0.5.1
      with:
        args: --acl public-read --follow-symlinks --delete
      env:
        AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        AWS_REGION: 'us-east-1'
        SOURCE_DIR: 'dist'

    - name: Invalidate CloudFront cache
      uses: chetan/invalidate-cloudfront-action@v2
      env:
        DISTRIBUTION: ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }}
        PATHS: '/*'
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        AWS_REGION: 'us-east-1'

GitLab CI配置

# .gitlab-ci.yml
image: node:18-alpine

stages:
  - test
  - build
  - deploy

cache:
  paths:
    - node_modules/

before_script:
  - npm ci

test:
  stage: test
  script:
    - npm run lint
    - npm test -- --watch=false --browsers=ChromeHeadless

build:
  stage: build
  script:
    - npm run build -- --prod
  artifacts:
    paths:
      - dist/
    expire_in: 1 week
  only:
    - main
    - tags

deploy:
  stage: deploy
  script:
    - apt-get update -qy
    - apt-get install -y rsync
    - rsync -avz --delete dist/ user@server:/var/www/angular-app/
    - ssh user@server "systemctl reload nginx"
  only:
    - main

6. 云平台部署

AWS部署
  • S3 + CloudFront
  • Amplify托管
  • Elastic Beanstalk
  • EC2实例
Google Cloud
  • Firebase Hosting
  • App Engine
  • Compute Engine
  • Cloud Storage
Microsoft Azure
  • Azure Static Web Apps
  • App Service
  • Storage静态网站
  • Azure DevOps

Firebase Hosting部署

# 安装Firebase CLI
npm install -g firebase-tools

# 登录Firebase
firebase login

# 初始化项目
firebase init hosting

# 构建应用
ng build --prod

# 部署到Firebase
firebase deploy --only hosting
// firebase.json 配置
{
  "hosting": {
    "public": "dist/angular-app",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ],
    "headers": [
      {
        "source": "**/*.@(js|css)",
        "headers": [
          {
            "key": "Cache-Control",
            "value": "max-age=31536000"
          }
        ]
      },
      {
        "source": "**/*.@(jpg|jpeg|png|gif|ico)",
        "headers": [
          {
            "key": "Cache-Control",
            "value": "max-age=2592000"
          }
        ]
      }
    ]
  }
}

7. 部署后监控与维护

性能监控工具

  • Google Analytics: 用户行为分析
  • Sentry: 错误追踪
  • New Relic: 应用性能监控
  • Lighthouse: 性能评分
  • Web Vitals: 核心Web指标

安全配置

// 安全HTTP头设置
// nginx配置中添加
add_header Content-Security-Policy "default-src 'self';";
add_header X-Content-Type-Options "nosniff";
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header Referrer-Policy "strict-origin-when-cross-origin";
部署检查清单
  • ✅ 生产环境构建完成
  • ✅ 环境变量正确配置
  • ✅ 静态资源压缩优化
  • ✅ HTTPS证书已安装
  • ✅ 域名解析正确
  • ✅ 监控工具配置完成
  • ✅ 备份机制已建立
  • ✅ 回滚方案已准备
常见部署问题
  • 路由404错误:确保服务器配置了SPA回退
  • API跨域问题:配置正确的CORS头或使用代理
  • 资源加载失败:检查路径配置和base-href
  • 内存不足:增加构建内存限制
  • 版本缓存问题:使用文件哈希和缓存清除策略

8. 高级部署策略

蓝绿部署

同时运行两个生产环境,切换流量实现零停机部署

# 示例:使用Nginx实现蓝绿部署
# 绿色环境已运行,部署蓝色环境
cp -r dist/ /var/www/angular-app-blue/

# 切换Nginx配置
ln -sf /etc/nginx/sites-available/angular-app-blue \
       /etc/nginx/sites-enabled/angular-app

# 重载Nginx
nginx -s reload

# 验证新版本,然后下线绿色环境

金丝雀发布

逐步向小部分用户发布新版本

# Nginx按IP分流配置
geo $canary {
    default 0;
    10.0.0.0/8 1;  # 内部用户使用新版本
}

server {
    location / {
        if ($canary) {
            proxy_pass http://canary-backend;
        }
        proxy_pass http://production-backend;
    }
}
!

最佳实践总结

  1. 自动化一切:使用CI/CD自动化构建和部署
  2. 环境隔离:保持开发、测试、生产环境分离
  3. 版本控制:所有配置纳入版本控制
  4. 监控告警:建立完善的监控体系
  5. 文档化:详细记录部署流程和故障处理
  6. 定期演练:定期进行部署演练和故障恢复测试