openEuler 24.03 部署 JeecgBoot 3.9.5 前端:pnpm 编译 + Nginx 反向代理实战
一、本篇目标
前六篇完成了后端和基础环境:
- 第 1 篇:升级决策
- 第 2 篇:环境准备与数据盘
- 第 3 篇:Redis 7.4 源码编译
- 第 4 篇:Nginx 1.28 源码编译
- 第 5 篇:PostgreSQL 17 源码编译 + pgvector + SQL 转换
- 第 6 篇:JeecgBoot 3.9.5 后端编译部署
后端已经跑在 8080 端口,本篇处理前端:
- Node.js 22 环境搭建
- pnpm 10 安装与前端编译
- Nginx 部署 Vue3 静态资源
- 反向代理后端接口
- SPA history 路由回落
- WebSocket 代理
最终目标:
浏览器打开 http://你的IP -> 看到 JeecgBoot 登录页
登录 admin/123456 -> 进入主界面
刷新任意子路由 -> 不报 404
本篇的实战过程中踩了不少坑,尤其是 Node.js 和 pnpm 的版本兼容性,都在下文完整记录。
二、部署架构
JeecgBoot 前后端分离,Nginx 是唯一入口:
浏览器
│
▼
Nginx :80
├── / → /usr/local/jeecg/frontend (静态文件)
├── /jeecgboot/ → 127.0.0.1:8080/jeecg-boot/ (API 反向代理)
└── /websocket → 127.0.0.1:8080/websocket (WebSocket)
三、编译前准备
3.1 修改 .env.production
cd /usr/local/src/JeecgBoot/jeecgboot-vue3
cp .env.production .env.production.bak-$(date +%Y%m%d-%H%M%S)
sed -i 's#^VITE_GLOB_DOMAIN_URL=.*#VITE_GLOB_DOMAIN_URL=http://192.168.1.6/jeecgboot#' .env.production
grep -E 'VITE_GLOB_API_URL|VITE_GLOB_DOMAIN_URL' .env.production
期望输出:
VITE_GLOB_API_URL=/jeecgboot
VITE_GLOB_DOMAIN_URL=http://192.168.1.6/jeecgboot
注意:JeecgBoot 3.9.5 的 VITE_GLOB_DOMAIN_URL 会在运行时通过 _app.config.js 注入,换 IP 只需改这个文件,不必重新编译。
3.2 初始环境版本
| 组件 | 版本 |
|---|---|
| Node.js | 20.18.2(系统 rpm 安装) |
| pnpm | 12.3.4 |
| 内存 | 93G |
看起来够用,但后面会证明这两项都不行。
四、编译踩坑全记录
坑 1:Node.js 版本不足导致 rolldown 原生模块缺失
第一次执行 pnpm install && pnpm run build,报错:
Error: Cannot find native binding. npm has a bug related to optional dependencies...
cause: Error: Cannot find module '@rolldown/binding-linux-x64-gnu'
原因:Vite 8 依赖 rolldown,其原生模块要求 Node.js ≥ 20.19 或 ≥ 22.12,而当前是 20.18.2。pnpm 在解析可选依赖时跳过了不兼容的包。
解决:升级 Node.js 到 22.23.3(手动下载官方二进制):
cd /tmp
LATEST=v22.23.3
curl -fLO https://nodejs.org/dist/${LATEST}/node-${LATEST}-linux-x64.tar.xz
tar -xJf node-${LATEST}-linux-x64.tar.xz
mv /usr/local/node22 /usr/local/node22-bak-22.11.0-$(date +%Y%m%d)
mv /tmp/node-${LATEST}-linux-x64 /usr/local/node22
export PATH=/usr/local/node22/bin:$PATH
node -v # v22.23.3
坑 2:pnpm 12 的 ERR_PNPM_IGNORED_BUILDS
安装依赖时提示:
Error: ERR_PNPM_IGNORED_BUILDS
× installing dependencies
╰─▶ Ignored build scripts: @logicflow/core@2.2.4, @scarf/scarf@1.4.0, core-js@2.6.12, ...
解决:批准构建脚本:
pnpm approve-builds --all
或在 pnpm-workspace.yaml 中配置 allowBuilds。
坑 3:pnpm 12 的 minimumReleaseAge 供应链策略
安装依赖时不断报:
Error: ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION
× installing dependencies
╰─▶ 4 lockfile entries failed verification:
exsolve@1.1.3 was published at 2026-10-03T09:36:58.881Z, within the minimumReleaseAge cutoff
...
pnpm 11+ 默认开启 minimumReleaseAge(默认 1440 分钟),拒绝安装发布不足 24 小时的包。
解决:在项目根目录的 pnpm-workspace.yaml 中显式设置 minimumReleaseAge: 0:
supportedArchitectures:
os:
- linux
cpu:
- x64
libc:
- glibc
allowBuilds:
'@logicflow/core': true
'@scarf/scarf': true
core-js: true
esbuild: true
vue-demi: true
minimumReleaseAge: 0
关键:命令行 --config.minimumReleaseAge=0 和环境变量方式在 pnpm 12 中可能被忽略,必须写进 pnpm-workspace.yaml。
坑 4:rolldown binding 始终缺失,降级 pnpm 10 并手动安装
即使 Node 升级到 22.23.3,@rolldown/binding-linux-x64-gnu 仍然没有装上。尝试 pnpm 12 多种方式无效,最终降级 pnpm 到 10.34.6:
npm install -g pnpm@10 --registry=https://registry.npmmirror.com
pnpm -v # 10.34.6
然后手动添加 binding 包:
cd /usr/local/src/JeecgBoot/jeecgboot-vue3
pnpm add -D @rolldown/binding-linux-x64-gnu@1.2.12 --registry=https://registry.npmmirror.com
验证:
ls -la node_modules/@rolldown/
# 应出现 binding-linux-x64-gnu 软链接
find node_modules -name "*.node" -path "*rolldown*"
# 找到 rolldown-binding.linux-x64-gnu.node
坑 5:cross-env 未找到命令
编译时出现:
sh: 行 1: cross-env: 未找到命令
这是因为前面的依赖安装因 minimumReleaseAge 失败,导致 node_modules 不完整。解决 minimumReleaseAge 后,重新执行 pnpm install 即可恢复。
五、最终编译成功
确保 Node 22.23.3、pnpm 10.34.6,且 pnpm-workspace.yaml 配置正确后,执行:
cd /usr/local/src/JeecgBoot/jeecgboot-vue3
export PATH=/usr/local/node22/bin:$PATH
export NODE_OPTIONS=--max-old-space-size=8192
pnpm install
pnpm run build
编译成功输出类似:
✓ built in 1m 20s
Done in 4.4s using pnpm v10.34.6
检查产物:
du -sh dist/ # 36M
ls dist/ # _app.config.js, assets, index.html, js, ...
ls -lh dist/index.html # 17K
关键文件 _app.config.js 内容:
window.__PRODUCTION__JEECGBOOT_PRO__CONF__={
...
"VITE_GLOB_API_URL":"/jeecgboot",
"VITE_GLOB_DOMAIN_URL":"http://192.168.1.6/jeecgboot",
...
}
六、部署到 Nginx
6.1 拷贝静态文件
mkdir -p /usr/local/jeecg/frontend
rm -rf /usr/local/jeecg/frontend/*
cp -rf /usr/local/src/JeecgBoot/jeecgboot-vue3/dist/* /usr/local/jeecg/frontend/
chown -R jeecg:jeecg /usr/local/jeecg/frontend
chmod -R 755 /usr/local/jeecg/frontend
chmod -R o+rX /usr/local/jeecg/frontend # 确保 nginx worker 可读
6.2 配置 Nginx vhost
创建 /usr/local/nginx/conf/vhost/jeecg.conf:
server {
listen 80;
server_name 192.168.1.6 localhost;
root /usr/local/jeecg/frontend;
index index.html;
access_log /data/logs/nginx/jeecg-access.log;
error_log /data/logs/nginx/jeecg-error.log;
location = /sw.js {
add_header Cache-Control "no-store, no-cache, must-revalidate";
}
location = /manifest.webmanifest {
add_header Cache-Control "no-store, no-cache, must-revalidate";
}
location = /_app.config.js {
add_header Cache-Control "no-store, no-cache, must-revalidate";
}
location ~* \.(?:js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
location / {
try_files $uri $uri/ /index.html;
}
location /jeecgboot/ {
proxy_pass http://127.0.0.1:8080/jeecg-boot/;
proxy_redirect off;
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 300s;
proxy_send_timeout 300s;
}
location /websocket {
proxy_pass http://127.0.0.1:8080/websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html { root html; }
}
在 /usr/local/nginx/conf/nginx.conf 的 http 块中补充:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
include /usr/local/nginx/conf/vhost/*.conf;
6.3 日志目录与重载
mkdir -p /data/logs/nginx
chown -R nginx:nginx /data/logs/nginx
/usr/local/nginx/sbin/nginx -t
systemctl reload nginx
七、验证
curl -sI http://192.168.1.6/ | head -3
curl -sI http://192.168.1.6/_app.config.js | head -3
curl -sI http://192.168.1.6/jeecgboot/sys/randomImage | head -3
全部返回 200。浏览器访问 http://192.168.1.6,使用 admin / 123456 登录成功。
八、遗留问题:界面显示为 3.8 风格
登录后界面仍是旧版风格,初步判断是主题配置未生效。
JeecgBoot 3.9.5 支持多种菜单风格,可在 src/settings/projectSetting.ts 中修改 menuType,然后重新编译。
此问题将在后续文章中解决。
九、总结
本次前端部署主要耗时在 Node.js 和 pnpm 的版本兼容性上,核心踩坑点:
| 坑 | 关键 | 解决 |
|---|---|---|
| rolldown 原生模块缺失 | Node ≥ 20.19 / 22.12 | 升级到 Node 22.23.3 |
| ERR_PNPM_IGNORED_BUILDS | pnpm 12 策略 | pnpm approve-builds --all |
| ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION | pnpm 11+ 默认 1440 分钟 | pnpm-workspace.yaml 写 minimumReleaseAge: 0 |
| binding 包缺失 | pnpm 12 可选依赖解析 bug | 降级到 pnpm 10.34.6 + 手动 add |
| cross-env 找不到 | 依赖装不全 | 修复 minimumReleaseAge 后重装 |
Nginx 配置要点:
- SPA 路由回落:
try_files $uri $uri/ /index.html _app.config.js不缓存:Cache-Control: no-store- WebSocket 需要
map $http_upgrade $connection_upgrade - 静态资源长缓存:
expires 30d
最终一键编译命令:
export PATH=/usr/local/node22/bin:$PATH
export NODE_OPTIONS=--max-old-space-size=8192
cd /usr/local/src/JeecgBoot/jeecgboot-vue3
pnpm install
pnpm run build
下一篇:部署归档与一键恢复。
项目地址:
- JeecgBoot PostgreSQL 工具链:https://gitee.com/dboru/jeecgboot-pg-tools
- SQL 转换工具:https://gitee.com/dboru/jeecgboot-pg-converter
本系列文章:
- 第 1 篇:为什么从 3.8.3 升级到 3.9.5
- 第 2 篇:环境准备与数据盘规划
- 第 3 篇:Redis 7.4 源码编译与内核参数调优
- 第 4 篇:Nginx 1.28 源码编译与反向代理配置
- 第 5 篇:PostgreSQL 17 源码编译 + pgvector + SQL 转换
- 第 6 篇:JeecgBoot 3.9.5 后端编译部署
- 第 7 篇:JeecgBoot 3.9.5 前端编译部署(本文)
配套文章:
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)