大家好,我是前端大鱼。本文将提供一个完整的解决方案,从环境变量配置到Nginx部署,确保你的Vue项目可以灵活部署在任何路径下。
一、环境变量统一配置
1. 环境变量配置文件
我们首先在项目根目录创建以下环境文件:
env
# .env.development
VUE_APP_BASE_URL=/
VUE_APP_PUBLIC_PATH=/
VUE_APP_API_BASE_URL=/api/
env
# .env.production
VUE_APP_BASE_URL=/department/project/
VUE_APP_PUBLIC_PATH=/department/project/
VUE_APP_API_BASE_URL=/department/project/api/
关键点说明:
VUE_APP_BASE_URL
: 路由基础路径VUE_APP_PUBLIC_PATH
: 静态资源基础路径VUE_APP_API_BASE_URL
: API请求基础路径
二、Vue项目核心配置
1. vue.config.js 完整配置
javascript
const path = require('path')
module.exports = {
// 静态资源路径
publicPath: process.env.VUE_APP_PUBLIC_PATH || '/',
// 输出目录
outputDir: 'dist',
// 静态资源目录
assetsDir: 'static',
// 文件名哈希
filenameHashing: true,
// webpack配置
chainWebpack: config => {
// 设置publicPath
config.output
.publicPath(process.env.VUE_APP_PUBLIC_PATH || '/')
// 图片处理
config.module
.rule('images')
.use('url-loader')
.loader('url-loader')
.tap(options => {
options.limit = 8192
options.fallback = {
loader: 'file-loader',
options: {
name: 'static/img/[name].[hash:8].[ext]',
publicPath: process.env.VUE_APP_PUBLIC_PATH || '/'
}
}
return options
})
},
// 开发服务器配置
devServer: {
// 支持history模式
historyApiFallback: {
disableDotRule: true,
rewrites: [
{
from: new RegExp('^.*'),
to: path.posix.join(process.env.VUE_APP_PUBLIC_PATH || '/', 'index.html')
}
]
},
// 代理配置
proxy: {
[process.env.VUE_APP_API_BASE_URL]: {
target: 'http://your-api-server.com',
changeOrigin: true,
pathRewrite: {
[`^${process.env.VUE_APP_API_BASE_URL}`]: ''
}
}
}
},
// 生产环境关闭sourcemap
productionSourceMap: false
}
三、路由配置最佳实践
1. 路由配置文件 (src/router/index.js)
javascript
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
// 获取基础路径,确保不以斜杠结尾
const BASE_PATH = (process.env.VUE_APP_BASE_URL || '/').replace(/\/$/, '')
const routes = [
{
// 根路径重定向
path: '',
redirect: 'home'
},
{
// 注意:不要以斜杠开头
path: 'home',
component: () => import('@/views/Home.vue'),
name: 'home',
meta: { title: '首页' }
},
{
path: 'about',
component: () => import('@/views/About.vue'),
name: 'about',
meta: { title: '关于我们' }
},
{
path: '*',
component: () => import('@/views/NotFound.vue'),
name: 'not-found',
meta: { title: '页面不存在' }
}
]
const router = new VueRouter({
mode: 'history',
base: BASE_PATH,
routes,
// 滚动行为
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
return { x: 0, y: 0 }
}
}
})
router.beforeEach((to, from, next) => {
document.title = to.meta.title || '默认标题'
next()
})
export default router
四、资源加载与API请求规范
1. 资源加载工具类 (src/utils/resource.js)
javascript
/**
* 获取静态资源完整URL
* @param {string} relativePath 相对路径
* @returns {string} 完整URL
*/
export const getAssetUrl = (relativePath) => {
const baseUrl = process.env.VUE_APP_PUBLIC_PATH || '/'
return `${baseUrl.replace(/\/$/, '')}/${relativePath.replace(/^\//, '')}`
}
/**
* 获取API完整URL
* @param {string} endpoint API端点
* @returns {string} 完整API URL
*/
export const getApiUrl = (endpoint) => {
const baseUrl = process.env.VUE_APP_API_BASE_URL || '/api/'
return `${baseUrl.replace(/\/$/, '')}/${endpoint.replace(/^\//, '')}`
}
2. Axios实例配置 (src/utils/request.js)
javascript
import axios from 'axios'
import { getApiUrl } from './resource'
// 创建axios实例
const service = axios.create({
baseURL: process.env.VUE_APP_API_BASE_URL,
timeout: 10000
})
// 请求拦截器
service.interceptors.request.use(
config => {
// 可以在这里添加token等
// config.headers['Authorization'] = getToken()
return config
},
error => {
return Promise.reject(error)
}
)
// 响应拦截器
service.interceptors.response.use(
response => {
return response.data
},
error => {
return Promise.reject(error)
}
)
export default service
五、Nginx服务器配置
1. 基础Nginx配置
nginx
server {
listen 80;
server_name example.com;
# 静态资源缓存设置
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, no-transform";
}
# 项目部署路径 - 使用环境变量中的路径
location /department/project/ {
alias /var/www/html/department/project/dist/;
try_files $uri $uri/ /department/project/index.html;
# 开启gzip压缩
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml;
# 安全头设置
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
add_header X-XSS-Protection "1; mode=block";
}
# API代理
location /department/project/api/ {
proxy_pass http://api-server/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
2. HTTPS增强配置
nginx
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/ssl/certs/example.com.crt;
ssl_certificate_key /etc/ssl/private/example.com.key;
# SSL优化配置
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers on;
location /department/project/ {
alias /var/www/html/department/project/dist/;
try_files $uri $uri/ /department/project/index.html;
# 安全头
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header Content-Security-Policy "default-src 'self'";
}
}
六、完整部署流程
1. 构建与部署脚本
bash
#!/bin/bash
# 设置环境
ENV="production"
DEPLOY_PATH="/var/www/html/department/project"
# 安装依赖
npm install
# 构建项目
npm run build:${ENV}
# 同步文件到服务器
rsync -avz --delete dist/ user@server:${DEPLOY_PATH}/dist/
# 重启Nginx
ssh user@server "sudo systemctl restart nginx"
echo "Deployment completed!"
2. 多环境构建脚本 (package.json)
json
{
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"build:dev": "vue-cli-service build --mode development",
"build:test": "vue-cli-service build --mode test",
"build:production": "vue-cli-service build --mode production",
"lint": "vue-cli-service lint"
}
}
七、常见问题解决方案
1. 页面刷新404问题
解决方案:
- 确保Nginx配置中包含正确的try_files指令
- 检查Vue路由的base配置是否与环境变量一致
- 验证publicPath配置是否正确
2. 静态资源加载失败
排查步骤:
- 检查浏览器开发者工具中的网络请求
- 确认请求路径是否包含正确的基础路径
- 验证Nginx的alias路径是否正确
- 检查文件权限:
chmod -R 755 /var/www/html
3. API请求路径错误
最佳实践:
- 使用axios实例配置baseURL
- 确保API路径与VUE_APP_API_BASE_URL一致
- 开发环境使用代理,生产环境使用绝对路径
八、性能优化建议
-
资源压缩:
- 开启Nginx gzip压缩
- 使用Brotli压缩(需要Nginx支持)
- 压缩图片资源
-
缓存策略:
nginxlocation ~* \.(js|css)$ { expires 365d; add_header Cache-Control "public"; } location ~* \.(jpg|jpeg|png|gif|ico)$ { expires 30d; add_header Cache-Control "public"; }
-
代码分割:
javascript// 使用动态导入实现路由懒加载 component: () => import('@/views/Home.vue')
总结
这种方案在多个大型项目中得到验证,能够满足企业级应用的部署需求。希望本指南能帮助你解决Vue项目在多级路径下的部署问题!
关注微信公众号" 大前端历险记",掌握更多前端开发干货姿势!