🚀 构建部署文档
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.222. 项目初始化
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=production3. 环境配置加载逻辑
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.5MB | 1.3MB | 48% ↓ |
| Gzip后 | 800KB | 400KB | 50% ↓ |
| 加载时间(3G) | 4.2s | 1.8s | 57% ↓ |
| 首次可交互 | 3.8s | 1.5s | 61% ↓ |
🚀 部署方案
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: bridge3. 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.html2. 运行时性能监控
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