H5 部署
介绍
H5 部署是将 UniApp 项目构建为标准的 Web 应用,通过浏览器访问。RuoYi-Plus-UniApp 的 H5 部署支持多种部署方式,包括传统服务器部署、CDN 部署、Docker 容器化部署等,适应不同的业务场景和技术栈需求。
核心特性:
- 跨平台访问 - 支持所有现代浏览器,包括移动端和桌面端
- 快速构建 - Vite 构建,速度快,优化好
- 灵活部署 - 支持多种部署方式和环境
- SPA 架构 - 单页应用,路由由前端控制
- 资源优化 - 代码分割、懒加载、Gzip 压缩
- SEO 支持 - 可配合预渲染或 SSR 优化 SEO
- HTTPS 支持 - 安全的数据传输
- CDN 加速 - 静态资源 CDN 分发
构建准备
环境检查
# 检查 Node.js 版本(需要 >=18)
node -v
# v18.x.x 或更高
# 检查 pnpm 版本(需要 >=7.30)
pnpm -v
# 7.30.0 或更高
# 检查项目依赖
cd plus-app
pnpm install环境配置
生产环境变量
编辑 env/.env.production:
# 环境标识
VITE_APP_ENV = 'production'
# API 基础路径(生产服务器)
VITE_APP_BASE_API = 'https://api.example.com'
# 公共资源基础路径
VITE_APP_PUBLIC_BASE = '/'
# 移除 console
VITE_DELETE_CONSOLE = true
# 关闭 SourceMap
VITE_SHOW_SOURCEMAP = false
# CDN 地址(可选)
VITE_APP_CDN = 'https://cdn.example.com'重要配置说明:
VITE_APP_BASE_API: API 服务器地址
- 必须是完整的 URL
- 生产环境建议使用 HTTPS
- 需要配置 CORS
VITE_APP_PUBLIC_BASE: 应用部署路径
- 根目录部署:
/ - 子目录部署:
/app/ - 必须与 Nginx 配置一致
- 根目录部署:
VITE_DELETE_CONSOLE: 移除 console
- 生产环境必须设为
true - 减小包体积,防止信息泄露
- 生产环境必须设为
VITE_SHOW_SOURCEMAP: SourceMap
- 生产环境必须设为
false - 防止源码泄露
- 生产环境必须设为
构建命令
# 进入项目目录
cd plus-app
# 安装依赖(如果还没安装)
pnpm install
# 构建 H5 生产版本
pnpm build:h5
# 构建完成后,产物在 dist/build/h5 目录构建产物
构建成功后的目录结构:
dist/
└── build/
└── h5/
├── index.html # 入口 HTML 文件
├── assets/ # 资源目录
│ ├── css/
│ │ ├── index.[hash].css
│ │ └── vendor.[hash].css
│ └── js/
│ ├── index.[hash].js
│ ├── vendor.[hash].js
│ └── chunk.[hash].js
├── static/ # 静态资源
│ ├── images/
│ ├── fonts/
│ └── ...
└── favicon.ico # 网站图标产物说明:
- index.html: 应用入口,SPA 单页面
- assets/: 打包后的 CSS 和 JS 文件
- static/: 原始静态资源(图片、字体等)
- [hash]: 文件哈希,用于缓存控制
部署方式
1. Nginx 部署(推荐)
安装 Nginx
# Ubuntu/Debian
sudo apt update
sudo apt install nginx
# CentOS/RHEL
sudo yum install nginx
# macOS
brew install nginx上传构建产物
# 方式1: SCP 上传
scp -r dist/build/h5/* user@server:/var/www/html/app
# 方式2: rsync 同步
rsync -avz dist/build/h5/ user@server:/var/www/html/app
# 方式3: FTP 工具上传(FileZilla 等)Nginx 配置
根目录部署:
# /etc/nginx/sites-available/app.conf
server {
listen 80;
server_name app.example.com;
# 网站根目录
root /var/www/html/app;
index index.html;
# Gzip 压缩
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
gzip_min_length 1000;
# SPA 路由支持
location / {
try_files $uri $uri/ /index.html;
}
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# API 代理(可选)
location /api/ {
proxy_pass https://api.example.com/;
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;
}
}子目录部署:
# 应用部署在 /app/ 子目录
server {
listen 80;
server_name example.com;
# 子目录部署
location /app/ {
alias /var/www/html/app/;
index index.html;
try_files $uri $uri/ /app/index.html;
}
# 静态资源
location ~* ^/app/.*\.(js|css|png|jpg|jpeg|gif|ico)$ {
alias /var/www/html/app/;
expires 1y;
add_header Cache-Control "public, immutable";
}
}注意事项:
- 子目录部署时,
VITE_APP_PUBLIC_BASE必须设为/app/ alias路径必须以/结尾try_files的 fallback 路径必须与子目录一致
HTTPS 配置
server {
listen 443 ssl http2;
server_name app.example.com;
# SSL 证书
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
# SSL 配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
root /var/www/html/app;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}
# HTTP 自动跳转 HTTPS
server {
listen 80;
server_name app.example.com;
return 301 https://$server_name$request_uri;
}启用配置
# 创建软链接
sudo ln -s /etc/nginx/sites-available/app.conf /etc/nginx/sites-enabled/
# 测试配置
sudo nginx -t
# 重载配置
sudo nginx -s reload
# 或重启 Nginx
sudo systemctl restart nginx2. Apache 部署
安装 Apache
# Ubuntu/Debian
sudo apt install apache2
# CentOS/RHEL
sudo yum install httpdApache 配置
创建 /etc/apache2/sites-available/app.conf:
<VirtualHost *:80>
ServerName app.example.com
DocumentRoot /var/www/html/app
<Directory /var/www/html/app>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
# SPA 路由支持
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</Directory>
# Gzip 压缩
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript application/json
</IfModule>
# 静态资源缓存
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access plus 1 year"
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/gif "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType text/css "access plus 1 year"
ExpiresByType application/javascript "access plus 1 year"
</IfModule>
</VirtualHost>启用配置
# 启用 rewrite 模块
sudo a2enmod rewrite
sudo a2enmod deflate
sudo a2enmod expires
# 启用站点配置
sudo a2ensite app.conf
# 重启 Apache
sudo systemctl restart apache23. Docker 部署
Dockerfile
创建 Dockerfile:
# 构建阶段
FROM node:18-alpine AS builder
# 设置工作目录
WORKDIR /app
# 安装 pnpm
RUN npm install -g pnpm
# 复制依赖文件
COPY package.json pnpm-lock.yaml ./
# 安装依赖
RUN pnpm install --frozen-lockfile
# 复制源代码
COPY . .
# 构建 H5
RUN pnpm build:h5
# 运行阶段
FROM nginx:alpine
# 复制构建产物
COPY --from=builder /app/dist/build/h5 /usr/share/nginx/html
# 复制 Nginx 配置
COPY nginx.conf /etc/nginx/conf.d/default.conf
# 暴露端口
EXPOSE 80
# 启动 Nginx
CMD ["nginx", "-g", "daemon off;"]Nginx 配置文件
创建 nginx.conf:
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
location / {
try_files $uri $uri/ /index.html;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "80:80"
restart: unless-stopped
environment:
- TZ=Asia/Shanghai构建和运行
# 构建镜像
docker build -t ryplus-uni-h5 .
# 运行容器
docker run -d -p 80:80 --name app ryplus-uni-h5
# 或使用 docker-compose
docker-compose up -d4. CDN 部署
静态资源 CDN
方式1: 第三方 CDN(阿里云 OSS、腾讯云 COS 等)
# 1. 构建项目
pnpm build:h5
# 2. 上传静态资源到 OSS
# 使用 ossutil 工具
ossutil cp -r dist/build/h5/assets/ oss://bucket-name/app/assets/ --update
# 3. 更新 HTML 中的资源路径
# 修改 index.html,将 /assets/ 替换为 CDN 地址
# https://cdn.example.com/app/assets/方式2: 构建时配置 CDN
修改 vite.config.ts:
export default defineConfig({
build: {
rollupOptions: {
output: {
// 自定义资源路径
assetFileNames: (assetInfo) => {
const cdn = 'https://cdn.example.com'
return `${cdn}/assets/[name]-[hash][extname]`
},
},
},
},
})Cloudflare Pages 部署
# 1. 安装 Wrangler CLI
npm install -g wrangler
# 2. 登录
wrangler login
# 3. 创建项目
wrangler pages project create ryplus-uni
# 4. 部署
wrangler pages publish dist/build/h5 --project-name=ryplus-uniVercel 部署
# 1. 安装 Vercel CLI
npm install -g vercel
# 2. 登录
vercel login
# 3. 部署
cd dist/build/h5
vercel --prod5. 对象存储部署
阿里云 OSS
安装 ossutil:
# 下载并安装 ossutil
wget https://gosspublic.alicdn.com/ossutil/1.7.15/ossutil64
chmod 755 ossutil64
# 配置
./ossutil64 config上传文件:
# 上传整个目录
./ossutil64 cp -r dist/build/h5/ oss://bucket-name/app/ --update
# 设置静态网站托管
./ossutil64 website --method put oss://bucket-name --index index.html --error index.html腾讯云 COS
安装 COSCMD:
pip install coscmd
# 配置
coscmd config -a <SecretId> -s <SecretKey> -b <BucketName> -r <Region>上传文件:
# 上传目录
coscmd upload -r dist/build/h5/ /app/
# 设置静态网站
coscmd putbucketwebsite --index index.html --error index.html自动化部署
GitHub Actions
创建 .github/workflows/deploy.yml:
name: Deploy H5
on:
push:
branches: [ main, master ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install pnpm
run: npm install -g pnpm
- name: Install dependencies
run: pnpm install
- name: Build
run: pnpm build:h5
- name: Deploy to Server
uses: easingthemes/ssh-deploy@v2
with:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
REMOTE_USER: ${{ secrets.REMOTE_USER }}
SOURCE: "dist/build/h5/"
TARGET: "/var/www/html/app"GitLab CI/CD
创建 .gitlab-ci.yml:
stages:
- build
- deploy
build:
stage: build
image: node:18
script:
- npm install -g pnpm
- pnpm install
- pnpm build:h5
artifacts:
paths:
- dist/build/h5
expire_in: 1 hour
deploy:
stage: deploy
image: alpine:latest
before_script:
- apk add --no-cache rsync openssh
- mkdir -p ~/.ssh
- echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
- chmod 600 ~/.ssh/id_rsa
- ssh-keyscan -H $REMOTE_HOST >> ~/.ssh/known_hosts
script:
- rsync -avz --delete dist/build/h5/ $REMOTE_USER@$REMOTE_HOST:/var/www/html/app
only:
- main
- masterJenkins Pipeline
创建 Jenkinsfile:
pipeline {
agent any
environment {
NODEJS_HOME = tool name: 'NodeJS 18'
PATH = "${env.NODEJS_HOME}/bin:${env.PATH}"
}
stages {
stage('Checkout') {
steps {
git branch: 'main',
url: 'https://github.com/your/repo.git'
}
}
stage('Install') {
steps {
sh 'npm install -g pnpm'
sh 'pnpm install'
}
}
stage('Build') {
steps {
sh 'pnpm build:h5'
}
}
stage('Deploy') {
steps {
sshagent(['server-credentials']) {
sh '''
rsync -avz --delete dist/build/h5/ \
user@server:/var/www/html/app
'''
}
}
}
}
post {
success {
echo 'Deployment successful!'
}
failure {
echo 'Deployment failed!'
}
}
}性能优化
1. 资源压缩
Gzip 压缩
Nginx 配置:
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_comp_level 6;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml+rss
application/rss+xml
font/truetype
font/opentype
application/vnd.ms-fontobject
image/svg+xml;Brotli 压缩
# 安装 brotli 模块
# Ubuntu: sudo apt install nginx-module-brotli
# 启用 brotli
brotli on;
brotli_comp_level 6;
brotli_types
text/plain
text/css
application/json
application/javascript
text/xml
application/xml
application/xml+rss
text/javascript;2. 缓存策略
HTTP 缓存头:
# index.html - 不缓存(始终检查更新)
location = /index.html {
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
add_header Expires 0;
}
# 带 hash 的资源 - 长期缓存
location ~* \.[0-9a-f]{8}\.(js|css)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# 图片等静态资源 - 中期缓存
location ~* \.(png|jpg|jpeg|gif|ico|svg)$ {
expires 30d;
add_header Cache-Control "public";
}3. HTTP/2 支持
server {
listen 443 ssl http2; # 启用 HTTP/2
server_name app.example.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
# HTTP/2 推送(可选)
location = /index.html {
http2_push /assets/index.js;
http2_push /assets/index.css;
}
}4. 预加载和预连接
在 index.html 中添加:
<!DOCTYPE html>
<html>
<head>
<!-- 预连接 API 服务器 -->
<link rel="preconnect" href="https://api.example.com">
<link rel="dns-prefetch" href="https://api.example.com">
<!-- 预连接 CDN -->
<link rel="preconnect" href="https://cdn.example.com">
<!-- 预加载关键资源 -->
<link rel="preload" as="script" href="/assets/index.js">
<link rel="preload" as="style" href="/assets/index.css">
</head>
</html>域名和 SSL
域名配置
1. 购买域名
- 阿里云: https://wanwang.aliyun.com
- 腾讯云: https://dnspod.cloud.tencent.com
- GoDaddy: https://www.godaddy.com
2. DNS 解析
添加 A 记录:
类型: A
主机记录: app (或 @)
记录值: 服务器IP
TTL: 600添加 CNAME 记录(如果使用 CDN):
类型: CNAME
主机记录: app
记录值: xxx.cdn.com
TTL: 600SSL 证书
Let's Encrypt 免费证书
# 安装 certbot
sudo apt install certbot python3-certbot-nginx
# 获取证书(Nginx)
sudo certbot --nginx -d app.example.com
# 自动续期
sudo certbot renew --dry-run
# 设置自动续期 cron
0 0 * * * certbot renew --quiet手动配置 SSL
# 上传证书文件
scp cert.pem key.pem user@server:/etc/nginx/ssl/
# Nginx 配置
server {
listen 443 ssl http2;
server_name app.example.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
# SSL 优化
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
}监控和维护
访问日志
Nginx 日志配置:
# 访问日志
access_log /var/log/nginx/app-access.log combined;
# 错误日志
error_log /var/log/nginx/app-error.log warn;
# 自定义日志格式
log_format app_log '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_time';
access_log /var/log/nginx/app.log app_log;查看日志:
# 实时查看访问日志
tail -f /var/log/nginx/app-access.log
# 查看错误日志
tail -f /var/log/nginx/app-error.log
# 统计访问量
cat /var/log/nginx/app-access.log | wc -l
# 统计 IP 访问次数
awk '{print $1}' /var/log/nginx/app-access.log | sort | uniq -c | sort -rn | head -10性能监控
安装监控工具:
# 安装 GoAccess(日志分析)
sudo apt install goaccess
# 分析日志
goaccess /var/log/nginx/app-access.log -o /var/www/html/report.html --log-format=COMBINED备份策略
自动备份脚本:
#!/bin/bash
# backup.sh
# 配置
APP_DIR="/var/www/html/app"
BACKUP_DIR="/backup/app"
DATE=$(date +%Y%m%d_%H%M%S)
# 创建备份
tar -czf $BACKUP_DIR/app_$DATE.tar.gz $APP_DIR
# 只保留最近7天的备份
find $BACKUP_DIR -name "app_*.tar.gz" -mtime +7 -delete
echo "Backup completed: app_$DATE.tar.gz"设置定时备份:
# 添加到 crontab
crontab -e
# 每天凌晨2点备份
0 2 * * * /path/to/backup.sh常见问题
1. 页面刷新 404
问题原因:
- SPA 路由未配置
- Nginx 缺少
try_files配置
解决方案:
location / {
try_files $uri $uri/ /index.html;
}2. API 跨域问题
问题原因:
- CORS 未配置
- API 服务器不允许跨域请求
解决方案:
方式1: 后端配置 CORS
方式2: Nginx 代理
location /api/ {
proxy_pass https://api.example.com/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# CORS 配置
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
if ($request_method = 'OPTIONS') {
return 204;
}
}3. 静态资源 404
问题原因:
VITE_APP_PUBLIC_BASE配置错误- 资源路径不匹配
解决方案:
# 检查环境变量
# .env.production
VITE_APP_PUBLIC_BASE = '/' # 根目录部署
# 或
VITE_APP_PUBLIC_BASE = '/app/' # 子目录部署
# 重新构建
pnpm build:h54. HTTPS 混合内容警告
问题原因:
- HTTPS 页面加载 HTTP 资源
解决方案:
# 确保所有资源使用 HTTPS
# .env.production
VITE_APP_BASE_API = 'https://api.example.com' # ✅
# 不要使用
VITE_APP_BASE_API = 'http://api.example.com' # ❌5. 构建后文件过大
问题原因:
- 未开启代码压缩
- SourceMap 未关闭
- 未进行代码分割
解决方案:
# 检查环境变量
# .env.production
VITE_DELETE_CONSOLE = true
VITE_SHOW_SOURCEMAP = false
VITE_MINIFY = true
# 分析包体积
pnpm build:h5 --report部署检查清单
部署前检查:
- [ ] 环境变量配置正确
- [ ] API 地址正确
- [ ]
VITE_APP_PUBLIC_BASE与部署路径一致 - [ ] SourceMap 已关闭
- [ ] console 已移除
- [ ] 构建成功无错误
部署后检查:
- [ ] 首页可以正常访问
- [ ] 路由跳转正常
- [ ] API 请求正常
- [ ] 静态资源加载正常
- [ ] HTTPS 证书有效
- [ ] 移动端适配正常
- [ ] 性能指标达标
总结
RuoYi-Plus-UniApp 的 H5 部署提供了:
核心优势:
- 多种部署方式 - Nginx、Apache、Docker、CDN 等
- 自动化部署 - CI/CD 集成,一键部署
- 性能优化 - Gzip、Brotli、HTTP/2、缓存策略
- 安全保障 - HTTPS、证书管理、访问控制
- 运维友好 - 日志监控、备份恢复、问题排查
最佳实践:
- 生产环境必须使用 HTTPS
- 配置合理的缓存策略
- 启用 Gzip/Brotli 压缩
- 使用 CDN 加速静态资源
- 定期备份和监控
- 配置自动化部署流程
通过合理的部署配置和优化,可以获得高性能、安全可靠的 H5 应用。
