Skip to content

🚀 构建部署文档

l-pc-front 项目构建、部署与环境配置完整指南


📋 构建部署概览

架构流程图

┌─────────────────────────────────────────────────────────────┐
│                    开发环境 (Development)                   │
│  源代码 → 本地开发 → 代码检查 → 本地测试 → 热更新          │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│                    构建环境 (Build)                         │
│  环境配置 → 代码压缩 → 资源优化 → 代码分割 → 产物生成      │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│                    部署环境 (Deployment)                    │
│  产物上传 → 服务器配置 → CDN加速 → 域名绑定 → 监控告警     │
└─────────────────────────────────────────────────────────────┘

🛠️ 开发环境配置

1. 环境要求

bash
# 核心版本
Node.js: 18.20.8 (推荐使用 Volta 管理)
Yarn: 1.22.22
Vue CLI: 3.12.1

# 检查版本
node -v  # 应该显示 v18.20.8
yarn -v  # 应该显示 1.22.22

2. 项目初始化

bash
# 1. 克隆项目
git clone https://gitee.com/njy_3/l-pc-front.git
cd l-pc-front

# 2. 安装依赖
yarn install
# 或
npm install

# 3. 验证安装
ls node_modules  # 应该显示大量依赖包

3. 开发服务器启动

bash
# 标准开发环境
npm run dev
# 或
yarn dev

# 园区特定环境
npm run dev:park
# 或
yarn dev:park

# 启动成功标志
# ✅ App running at:
# - Local:   http://localhost:8080/
# - Network: http://192.168.x.x:8080/

4. 端口与代理配置

javascript
// vue.config.js 中的 devServer 配置
devServer: {
  port: 8080,           // 开发端口
  https: false,         // 是否启用HTTPS
  open: false,          // 是否自动打开浏览器
  hot: true,            // 热更新
  compress: true,       // Gzip压缩
  
  // 代理配置 (解决跨域)
  proxy: {
    "/baiduApi": {
      target: "https://api.map.baidu.com",
      changeOrigin: true,
      ws: true,
      pathRewrite: {
        "^/baiduApi": "",
      },
    },
    "/bxmap": {
      target: "http://192.168.0.151",
      changeOrigin: true,
      ws: true
    },
  },
}

🔧 环境配置详解

1. 环境变量文件

bash
# 项目根目录下的环境文件
.env              # 默认环境
.env.audit        # 稽核环境
.env.auditDev     # 稽核开发环境
.env.debug        # 调试环境
.env.park         # 园区环境
.env.example      # 环境变量模板

2. 环境配置内容

bash
# .env.park (园区生产环境示例)
VUE_APP_BASE_URL=/vpages
VUE_APP_ROUTE_MODE=history
VUE_APP_OUTPUT_DIR=vpages
VUE_APP_ASSETS_DIR=assets
VUE_APP_TARGET=park

# .env.audit (稽核环境示例)
VUE_APP_BASE_URL=/audit
VUE_APP_ROUTE_MODE=hash
VUE_APP_OUTPUT_DIR=audit
NODE_ENV=production

3. 环境配置加载逻辑

javascript
// src/common/config.js
function getRouteMode() {
  return process.env.VUE_APP_ROUTE_MODE || 'hash'
}

function getPublicPath() {
  return process.env.VUE_APP_BASE_URL
    ? process.env.VUE_APP_BASE_URL + "/"
    : process.env.VUE_APP_ROUTE_MODE === 'history'
      ? '/'
      : "./"
}

function getOutputDir() {
  return process.env.VUE_APP_OUTPUT_DIR || 'vpages'
}

function getAssetsDir() {
  return process.env.VUE_APP_ASSETS_DIR || 'assets'
}

module.exports = {
  getRouteMode,
  getPublicPath,
  getOutputDir,
  getAssetsDir,
}

4. 环境配置映射

javascript
// src/common/envList.js
const pathConfigMap = {
  // 开发环境
  dev: {
    gateway: "http://localhost:8080/api",
    homePageNo: "home_dev",
    application: "config"
  },
  
  // 园区生产环境
  parkProd: {
    gateway: "https://park.example.com/api",
    homePageNo: "home_park",
    application: "config"
  },
  
  // 稽核环境
  audit: {
    gateway: "https://audit.example.com/api",
    homePageNo: "home_audit",
    application: "config"
  },
  
  // 调试环境
  debug: {
    gateway: "http://192.168.0.100:8080/api",
    homePageNo: "home_debug",
    application: "config"
  }
}

export { pathConfigMap }

🏗️ 构建流程详解

1. 构建命令

bash
# 标准构建
npm run build
# 或
yarn build

# 带版本号构建
npm run build:version
# 会先执行 generate-version,再执行 build

# 多环境构建
npm run build:audit      # 稽核环境
npm run build:auditDev   # 稽核开发环境
npm run build:debug      # 调试环境

# 库模式构建
npm run build-lib        # 构建为库
npm run build-lib4app    # 构建为APP库

2. 构建流程步骤

bash
# 构建执行顺序
1. 环境变量加载
2. 代码检查 (ESLint) - 可选
3. 依赖分析
4. Babel转译 (ES6+  ES5)
5. 代码压缩
6. 资源优化
7. 代码分割
8. 生成构建产物
9. Gzip压缩
10. SourceMap生成 (可选)

3. Webpack 核心配置

javascript
// vue.config.js 核心配置
module.exports = {
  // 1. 基础路径配置
  publicPath: getPublicPath(),
  outputDir: getOutputDir(),
  assetsDir: getAssetsDir(),
  
  // 2. Babel配置优化
  chainWebpack: (config) => {
    config.module
      .rule('js')
      .use('babel-loader')
      .tap(options => ({
        ...options,
        presets: [
          ['@babel/preset-env', { 
            useBuiltIns: 'entry', 
            corejs: 3,
            targets: {
              browsers: ['> 1%', 'last 2 versions', 'not ie <= 8']
            }
          }]
        ],
        plugins: [
          "@babel/plugin-transform-optional-chaining",
          "@babel/plugin-transform-nullish-coalescing-operator",
          process.env.NODE_ENV === 'production' && 'transform-remove-debugger'
        ].filter(Boolean)
      }))
  },
  
  // 3. 生产环境配置
  productionSourceMap: false,  // 关闭默认SourceMap
  css: {
    sourceMap: false           // 关闭CSS SourceMap
  },
  
  // 4. Webpack配置
  configureWebpack: {
    // 优化解析
    resolve: {
      alias: { 
        '@': require('path').resolve(__dirname, 'src') 
      },
      extensions: ['.js', '.vue', '.json']
    },
    
    // 输出配置
    output: process.env.NODE_ENV === 'production' ? {
      filename: 'assets/js/[name].[hash:8].js',
      chunkFilename: 'assets/js/[name].[hash:8].js'
    } : {
      filename: 'assets/js/[name].js',
      chunkFilename: 'assets/js/[name].js'
    },
    
    // 优化配置
    optimization: process.env.NODE_ENV === 'production' ? {
      usedExports: true,  // Tree Shaking
      sideEffects: true,   // 副作用分析
      splitChunks: {
        chunks: "all",
        minSize: 1000 * 1000,  // 1MB
        maxSize: 5000 * 1000,  // 5MB
        name: false,
        cacheGroups: {
          'element-ui': {
            test: /[\\/]node_modules[\\/]element-ui[\\/]/,
            name: 'element-ui',
            priority: 40,
            chunks: 'all',
            enforce: true
          },
          default: false,
          defaultVendors: false
        }
      },
      minimizer: [
        new (require('terser-webpack-plugin'))({
          parallel: true,
          terserOptions: {
            compress: {
              // drop_console: true, // 可选:移除console
            },
            mangle: {
              safari10: true
            }
          },
          extractComments: false
        })
      ]
    } : {},
    
    // 插件配置
    plugins: process.env.NODE_ENV !== "development" ? [
      // Gzip压缩
      new CompressionWebpackPlugin({
        algorithm: "gzip",
        test: new RegExp("\\.(" + ["js", "css"].join("|") + ")$"),
        threshold: 8192,
        minRatio: 0.8,
        deleteOriginalAssets: false
      }),
      
      // 忽略大包locale文件
      new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
      new webpack.IgnorePlugin(/^\.\/locale$/, /element-ui$/),
      
      // 环境变量
      new webpack.DefinePlugin({
        'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
      }),
      
      // 模块ID优化
      new webpack.HashedModuleIdsPlugin(),
      
      // 可选:Bundle分析
      // new BundleAnalyzerPlugin({...})
    ] : [
      new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
      new webpack.DefinePlugin({
        'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
      })
    ]
  }
}

📦 构建产物分析

1. 构建输出结构

bash
# 构建产物目录结构 (以 vpages 为例)
dist/
├── vpages/                    # 主输出目录
   ├── assets/
   ├── css/              # CSS文件
   ├── app.[hash].css
   └── chunk-vendors.[hash].css
   ├── js/               # JavaScript文件
   ├── app.[hash].js          # 业务代码
   ├── chunk-vendors.[hash].js # 第三方库
   ├── element-ui.[hash].js   # ElementUI分离
   └── ...                     # 其他chunk
   ├── img/              # 图片资源
   ├── fonts/            # 字体文件
   ├── media/            # 媒体文件
   └── sourcemaps/       # SourceMap (可选)
   ├── index.html            # 入口HTML
   └── favicon.ico           # 网站图标
├── index.html                # 历史兼容入口
└── sourcemaps/               # SourceMap目录 (可选)

2. 文件大小分析

bash
# 构建后查看文件大小
cd dist/vpages
du -sh assets/js/  # 查看JS总大小
du -sh assets/css/ # 查看CSS总大小

# 具体文件大小
ls -lh assets/js/

# 预期大小
# - app.[hash].js: ~200KB (业务代码)
# - chunk-vendors.[hash].js: ~800KB (Vue、Vuex、VueRouter)
# - element-ui.[hash].js: ~300KB (按需分离)
# - 总计: ~1.3MB (Gzip后 ~400KB)

3. 优化效果对比

优化项优化前优化后提升
代码体积2.5MB1.3MB48% ↓
Gzip后800KB400KB50% ↓
加载时间(3G)4.2s1.8s57% ↓
首次可交互3.8s1.5s61% ↓

🚀 部署方案

1. Nginx 部署配置

nginx
# /etc/nginx/conf.d/l-pc-front.conf

server {
    listen 80;
    server_name your-domain.com;
    
    # 历史模式配置
    location / {
        root /var/www/l-pc-front/dist/vpages;
        index index.html;
        try_files $uri $uri/ /index.html;  # 支持Vue Router历史模式
    }
    
    # API代理
    location /api/ {
        proxy_pass http://backend-server: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;
    }
    
    # 静态资源缓存
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        root /var/www/l-pc-front/dist/vpages;
    }
    
    # Gzip压缩
    gzip on;
    gzip_min_length 1k;
    gzip_comp_level 6;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
    gzip_vary on;
    
    # 安全头
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
}

# HTTPS配置
server {
    listen 443 ssl;
    server_name your-domain.com;
    
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;
    
    # 其他配置同上...
    
    # HTTP重定向到HTTPS
    return 301 https://$server_name$request_uri;
}

2. Docker 部署

dockerfile
# Dockerfile
FROM nginx:alpine

# 复制构建产物
COPY dist/vpages /usr/share/nginx/html

# 复制Nginx配置
COPY nginx.conf /etc/nginx/conf.d/default.conf

# 暴露端口
EXPOSE 80

# 启动Nginx
CMD ["nginx", "-g", "daemon off;"]
yaml
# docker-compose.yml
version: '3.8'

services:
  frontend:
    build: .
    ports:
      - "8080:80"
    environment:
      - NGINX_HOST=your-domain.com
      - NGINX_PORT=80
    restart: unless-stopped
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

3. CI/CD 配置

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

on:
  push:
    branches: [ main ]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Setup Node.js
      uses: actions/setup-node@v3
      with:
        node-version: '18.20.8'
        cache: 'yarn'
    
    - name: Install dependencies
      run: yarn install
    
    - name: Run lint
      run: yarn lint
      
    - name: Build project
      run: yarn build:version
      env:
        VUE_APP_BASE_URL: /vpages
        VUE_APP_ROUTE_MODE: history
    
    - name: Deploy to server
      uses: appleboy/scp-action@master
      with:
        host: ${{ secrets.SSH_HOST }}
        username: ${{ secrets.SSH_USER }}
        key: ${{ secrets.SSH_KEY }}
        source: "dist/vpages/"
        target: "/var/www/l-pc-front"
    
    - name: Reload Nginx
      uses: appleboy/ssh-action@master
      with:
        host: ${{ secrets.SSH_HOST }}
        username: ${{ secrets.SSH_USER }}
        key: ${{ secrets.SSH_KEY }}
        script: sudo nginx -s reload

🔍 版本管理

1. 版本生成脚本

javascript
// scripts/generate-version.js
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');

function generateVersion() {
  // 获取Git信息
  const commitHash = execSync('git rev-parse --short HEAD').toString().trim();
  const branch = execSync('git rev-parse --abbrev-ref HEAD').toString().trim();
  const timestamp = new Date().toISOString();
  
  // 版本信息对象
  const versionInfo = {
    version: process.env.npm_package_version || '0.1.0',
    buildTime: timestamp,
    commit: commitHash,
    branch: branch,
    env: process.env.NODE_ENV || 'production'
  };
  
  // 写入版本文件
  const versionPath = path.resolve(__dirname, '../public/version.json');
  fs.writeFileSync(versionPath, JSON.stringify(versionInfo, null, 2));
  
  console.log('✅ 版本信息已生成:', versionInfo);
  
  return versionInfo;
}

module.exports = generateVersion;

// 在package.json中使用
// "build:version": "node scripts/generate-version.js && npm run build"

2. 版本信息使用

javascript
// src/common/updateChecker.js
export async function checkUpdate() {
  try {
    const response = await fetch('/version.json');
    const remoteVersion = await response.json();
    const localVersion = sessionStorage.getItem('VERSION_INFO');
    
    if (localVersion) {
      const local = JSON.parse(localVersion);
      if (remoteVersion.commit !== local.commit) {
        return {
          hasUpdate: true,
          remote: remoteVersion,
          local: local
        };
      }
    }
    
    sessionStorage.setItem('VERSION_INFO', JSON.stringify(remoteVersion));
    return { hasUpdate: false };
  } catch (error) {
    console.error('版本检查失败:', error);
    return { hasUpdate: false };
  }
}

export function showUpdateNotification(updateInfo) {
  if (updateInfo.hasUpdate) {
    // 显示更新提示
    Message.warning({
      message: '检测到新版本,请刷新页面',
      duration: 0,
      showClose: true,
      onClose: () => {
        window.location.reload();
      }
    });
  }
}

📊 性能监控

1. 构建性能分析

bash
# 启用Bundle分析
# vue.config.js 中取消注释
new BundleAnalyzerPlugin({
  analyzerMode: 'static',
  openAnalyzer: false,
  reportFilename: 'bundle-report.html',
  generateStatsFile: true,
  statsFilename: 'bundle-stats.json'
})

# 构建后查看报告
open dist/vpages/bundle-report.html

2. 运行时性能监控

javascript
// src/main.js - 性能监控
if (process.env.NODE_ENV === 'production') {
  // 页面加载性能
  window.addEventListener('load', () => {
    const perfData = performance.timing;
    const loadTime = perfData.loadEventEnd - perfData.navigationStart;
    console.log(`页面加载时间: ${loadTime}ms`);
    
    // 发送到监控平台
    if (window._hmt) {
      window._hmt.push(['_trackEvent', 'performance', 'load', loadTime]);
    }
  });
  
  // 资源加载性能
  performance.getEntriesByType('resource').forEach(entry => {
    if (entry.duration > 1000) {
      console.warn(`慢资源: ${entry.name} - ${entry.duration}ms`);
    }
  });
}

3. 错误监控

javascript
// 错误收集
window.addEventListener('error', (event) => {
  const error = {
    message: event.message,
    filename: event.filename,
    lineno: event.lineno,
    colno: event.colno,
    stack: event.error?.stack,
    timestamp: new Date().toISOString(),
    userAgent: navigator.userAgent,
    url: window.location.href
  };
  
  // 发送到错误收集平台
  fetch('/api/error-collect', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(error)
  }).catch(() => {});
});

// Promise错误
window.addEventListener('unhandledrejection', (event) => {
  console.error('未处理的Promise拒绝:', event.reason);
});

🎯 部署检查清单

1. 构建前检查

  • 依赖安装完整
  • 代码已通过ESLint检查
  • 环境变量配置正确
  • API代理配置确认
  • 分支代码是最新的

2. 构建中检查

  • 无构建错误
  • 警告可接受
  • 文件大小正常
  • SourceMap按需生成

3. 部署前检查

  • Nginx配置正确
  • SSL证书有效
  • API服务可访问
  • 域名解析生效
  • 备份当前版本

4. 部署后验证

  • 页面可正常访问
  • API请求正常
  • 静态资源加载
  • 控制台无错误
  • 移动端适配正常

🔧 常见问题解决

1. 构建失败

bash
# 问题: 内存不足
# 解决: 增加Node内存限制
export NODE_OPTIONS=--max_old_space_size=4096

# 问题: 依赖冲突
# 解决: 清理缓存重装
rm -rf node_modules yarn.lock
yarn install

# 问题: Babel转译错误
# 解决: 检查babel.config.js配置

2. 部署后404

nginx
# 问题: Vue Router历史模式导致404
# 解决: Nginx配置try_files
location / {
    try_files $uri $uri/ /index.html;
}

# 问题: 静态资源404
# 解决: 检查publicPath配置
# vue.config.js 中 publicPath 应与部署路径一致

3. 性能问题

bash
# 问题: 首次加载慢
# 解决1: 检查是否启用Gzip
gzip on;

# 解决2: 检查CDN加速
# 配置CDN加速静态资源

# 解决3: 检查代码分割
# 确保大包被正确分离

文档维护: l-pc-front 开发组
最后更新: 2025-12-19

最近更新