【vue3】10 - vue3项目打包部署
文章目录
客户端 → Nginx (前端) → 网关层 → 后端服务集群
↑
├── 静态资源 (Vue3)
└── API 代理
一:打包前的准备
确保你的项目可以正常运行:
# 如果是vue cli
npm run serve
# 如果是vite
npm run dev
1:vite.config.ts (核心构建配置)
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { fileURLToPath, URL } from 'node:url'
import { visualizer } from 'rollup-plugin-visualizer'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
visualizer({
open: true,
filename: 'dist/stats.html'
})
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
// 注意这里
build: {
outDir: 'dist',
assetsDir: 'assets',
emptyOutDir: true,
minify: 'terser',
sourcemap: false,
chunkSizeWarningLimit: 1500,
rollupOptions: {
output: {
manualChunks(id) {
if (id.includes('node_modules')) {
return id.toString().split('node_modules/')[1].split('/')[0].toString()
}
},
chunkFileNames: 'assets/js/[name]-[hash].js',
entryFileNames: 'assets/js/[name]-[hash].js',
assetFileNames: 'assets/[ext]/[name]-[hash].[ext]'
}
}
},
// 注意这里
server: {
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
}
})
2:tsconfig.json (TS配置)
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "node",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"useDefineForClassFields": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
},
"types": ["vite/client"],
"lib": ["ESNext", "DOM", "DOM.Iterable"]
},
"include": [
"src/**/*.ts",
"src/**/*.d.ts",
"src/**/*.tsx",
"src/**/*.vue"
],
"exclude": ["node_modules"]
}
3:地址信息配置
在.env.production
文件中
# 基础API地址 (会被Nginx代理)
VITE_API_BASE_URL=/api
# 应用标题
VITE_APP_TITLE=My Production App
# 是否启用分析工具
VITE_ANALYZE=false
4:配置env.d.ts
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_API_BASE_URL: string
readonly VITE_APP_TITLE: string
readonly VITE_ANALYZE: string
}
interface ImportMeta {
readonly env: ImportMetaEnv
}
二:vue3项目打包
1:执行打包操作
npm run build
打包完成后会在项目根目录下生成 dist
文件夹,包含:
index.html
- 应用入口文件static/
- 静态资源目录(JS、CSS、图片等)
2:dist发送到服务器的指定位置
# 方式一:scp
scp -r dist/* username@your-server-ip:/path/to/your/webroot
# 方式二:rsync
rsync -avz --delete dist/ username@your-server-ip:/path/to/your/webroot
# 例如
ssh user@203.0.113.45
sudo mkdir -p /var/www/html/vue-app
sudo chown -R user:www-data /var/www/html/vue-app
# -a:归档模式(保留权限、时间戳等)
# -v:显示详细传输信息
# -z:压缩传输数据
# --delete:删除目标目录中不存在于源目录的文件
# dist/:本地打包目录(注意结尾的 / 表示同步目录内容)
# user@203.0.113.45:服务器用户名和IP
# /var/www/html/vue-app/:服务器目标路径
rsync -avz --delete dist/ user@203.0.113.45:/var/www/html/vue-app/
当然也可以提前创建和配置好存储路径文件夹,然后使用 FTP/SFTP 工具,如 FileZilla、WinSCP 等图形化工具
三:nginx配置
1:配置前的确认
一般确定三个内容
-
假设前端已经成功打包并且前端存放路径是/var/www/html/vue-app
-
假设后端网关服务器的地址是192.0.0.1.9000,192.0.0.1.9001,192.0.0.1.9002
-
假设前端生产环境和开发环境使用/api进行代理
// 最简单且最常用的方式,直接使用相对路径/api,依靠Nginx代理转发:
// src/utils/request.js (或你的axios封装文件)
const service = axios.create({
baseURL: '/api', // 生产环境直接使用相对路径
timeout: 15000
})
在没有接入nginx之前,可以通过vite.config.ts中代理的配置访问后端的开发环境
// vite.config.ts
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueDevTools from 'vite-plugin-vue-devtools'
import VueSetupExtend from 'vite-plugin-vue-setup-extend'
// https://vite.dev/config/
export default defineConfig({
// 配置插件
plugins: [
vue(),
vueDevTools(), // 允许在script setup中使用console.log()
VueSetupExtend(), // 允许在script setup中使用name
],
// 配置别名
resolve: {
alias: {
// @ -> src
// @/utils -> src/utils
'@': fileURLToPath(new URL('./src', import.meta.url)) // @ -> src
},
},
// 配置代理
server: {
proxy: {
// 例如: /api/user -> http://localhost:3000/user
'/api': { // 代理路径, 匹配的请求路径的前缀,对应的是.env.development中的VITE_BASE_API
target: 'http://localhost:8081', // 代理目标地址(实际的开发环境的服务端地址)
changeOrigin: true, // 允许跨域
// 重写路径 -> 去掉/api前缀
rewrite: (path) => path.replace(/^\/api/, '')
}
}
}
})
2:nginx配置示例
# 定义上游服务器组(后端服务负载均衡)
upstream backend_servers {
server 192.0.0.1:9000; # 后端服务器1
server 192.0.0.1:9001; # 后端服务器2
server 192.0.0.1:9002; # 后端服务器3
# 负载均衡策略(默认是轮询)
# least_conn; # 最少连接策略
# ip_hash; # 基于客户端IP的哈希策略(会话保持)
}
server {
listen 80; # 监听80端口(HTTP)
server_name yourdomain.com; # 替换为你的域名或IP
# 前端Vue应用配置
location / {
root /var/www/html/vue-app; # Vue应用的存放路径
index index.html; # 默认入口文件
# 尝试按顺序查找文件,如果找不到则返回index.html(Vue路由需要)
try_files $uri $uri/ /index.html;
}
# 后端API代理配置
location /api/ {
# 反向代理到上游服务器组
proxy_pass http://backend_servers;
# 以下是一些常用的代理设置
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;
# 连接超时设置
proxy_connect_timeout 60s;
proxy_read_timeout 60s;
proxy_send_timeout 60s;
# 启用HTTP/1.1 keepalive
proxy_http_version 1.1;
proxy_set_header Connection "";
}
# 静态资源缓存设置
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
root /var/www/html/vue-app;
expires 30d; # 缓存30天
add_header Cache-Control "public, no-transform";
}
# 错误页面配置
error_page 404 /index.html; # Vue应用处理404
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}