Skip to content

移动端环境准备与启动 ​

适用端:移动端 | 类型:操作

本页把移动端从零跑起来:装什么、依赖什么、三条启动路径(H5 / 微信小程序 / App)各自怎么走、env/.env* 的叠加顺序,以及怎么确认真的跑通了(不是「dev server 起来了」,是「登录进去能看到工作台」)。

前置阅读:环境准备与启动(后端与数据库那半边,本页不重复)。

它解决什么问题 ​

移动端与 Web 端共用同一个后端,所以「跑起来」的前提是后端已经在跑。差别在于移动端有三个目标平台、一套代码,而只有 H5 能在浏览器里直接验证——小程序要开发者工具、App 要 HBuilderX,这两条路本机都没实测过(见「未证实」)。

代码在哪 ​

要看什么文件
脚本与引擎约束package.json:24-98(scripts)、:3(engines: node>=20, pnpm>=9)、:4(packageManager: pnpm@10.10.0)
Vite 配置与插件链vite.config.ts(18 个插件,顺序敏感,见工程结构)
环境变量env/.env、env/.env.development、env/.env.test、env/.env.production
基础文件生成器scripts/create-base-files.js
页面 / 应用清单的全局配置pages.config.ts、manifest.config.ts
dev server 端口env/.env:2(VITE_APP_PORT = 9000)→ vite.config.ts:229

核心机制 ​

1. 只能用 pnpm,且 install 不能跳 ​

json
"preinstall": "npx only-allow pnpm",
"prepare":    "pnpm init-husky & pnpm init-baseFiles",
"init-baseFiles": "node ./scripts/create-base-files.js"

用 npm / yarn 会在 preinstall 直接报错。prepare 用的是 &(并行)不是 &&——init-husky 与 init-baseFiles 互不阻塞,一个失败不影响另一个。

init-husky 里藏着一条 git init

package.json 的 init-husky = git init && husky。在本仓(已是 git 仓库)里 git init 是幂等空操作,但在别的目录跑 pnpm install 会凭空造出一个仓库。这是 unibest 骨架带过来的,不要照着改。

init-baseFiles 生成两个被 gitignore 的必需文件(.gitignore:42-43):

生成物内容为什么必需
src/manifest.json空对象占位uni 编译期强依赖,缺了直接起不来
src/pages.json只含 index / me 两页的最小占位同上;真实内容由 UniPages 插件在 dev/build 时覆写

所以新克隆的正确顺序是 pnpm install(prepare 自动生成)→ pnpm dev。跳过 install 直接 dev 会失败。

🔴 只有三个脚本挂了 init-baseFiles 前置钩子

实测 package.json 里 pre* 钩子只有五个:preinstall、predev、predev:app、predev:mp、prepare。

也就是说 pnpm dev:h5 / dev:mp-weixin / dev:test / dev:prod 以及所有 build:* 都不会自动生成基础文件。新克隆后直接跑 pnpm dev:mp-weixin 会失败,而报错信息不会告诉你是 pages.json 缺失。

对策:新克隆先跑一次 pnpm init-baseFiles(或 pnpm dev,它有 predev 钩子),再切到别的脚本。

2. 环境变量的叠加顺序 ​

Vite 的 loadEnv(mode, 'env')(vite.config.ts:70)按 .env → .env.${mode} 合并,后者覆盖前者。env/ 下只有 4 个文件:

文件什么时候参与
.env总是(所有 mode 的基线)
.env.developmentpnpm dev(mode = development)
.env.testpnpm dev:test / build:test
.env.productionpnpm build:h5 等生产构建

关键变量(值取自本机,2026-10-25):

变量env/.env.env.production谁读它
VITE_APP_TITLE启凌智搭—manifest.config.ts + H5 的 transformIndexHtml(vite.config.ts:170)
VITE_APP_PORT9000—vite.config.ts:229
VITE_SERVER_BASEURLhttp://localhost:48080/admin-apihttps://demo.enlev.cn/admin-apisrc/utils/index.ts:141-160
VITE_STATIC_BASEURL''(空)''src/utils/download.ts:335-343 的 staticUrl()
VITE_APP_PUBLIC_BASE/—Vite base + manifest.config.ts:33-34
VITE_AUTH_MODE'double'—src/utils/index.ts:179 → 双 token 模式
VITE_APP_PROXY_ENABLEfalse—vite.config.ts:231-240;false 时 proxy: undefined
VITE_APP_CAPTCHA_ENABLEfalse—登录页滑块验证码
VITE_APP_TENANT_ENABLEtrue—src/http/interceptor.ts:10
VITE_APP_DEFAULT_LOGIN_TENANT_ID1—登录页租户选择器默认值
VITE_COPY_NATIVE_RES_ENABLEfalse—App 端原生插件资源复制
VITE_APP_API_ENCRYPT_ENABLEtrue—见下 ⚠️

VITE_UPLOAD_BASEURL 根本不存在

env/.env:23-25 自己写着「没有任何代码读取」。上传地址是拼出来的:${getEnvBaseUrl()}/infra/file/upload(src/api/infra/file/index.ts:78)。别去配它。

VITE_APP_API_ENCRYPT_ENABLE=true 但请求加密是休眠的

拦截器两侧都接了线:请求侧 src/http/interceptor.ts:83-95、响应侧 src/http/http.ts:84-94。但请求侧只在 options.isEncrypt 为真时才加密,而全仓没有任何 API 调用方传过 isEncrypt(只有类型声明 src/http/types.ts:13)。

所以真实状态是:响应解密是活的(由后端 X-Api-Encrypt 响应头驱动),请求加密是死代码。别把这个开关当成「已启用接口加密」去对外声明。

3. 三条启动路径 ​

目标命令产物 / 打开方式本机实测
H5pnpm dev(= uni)http://localhost:9000,host 0.0.0.0(vite.config.ts:227)✅
微信小程序pnpm dev:mp-weixindist/dev/mp-weixin,用微信开发者工具「导入项目」❌ 未实测
Apppnpm dev:appdist/dev/app,用 HBuilderX 打开❌ 未实测

非 H5 端的 dev 也是 build command

vite.config.ts:59-64 的注释写得很清楚:pnpm dev:mp-weixin 得到的是 command='build' + mode='development',不是 serve。所有按 command === 'serve' 分支的插件逻辑(包括 eruda 注入)在非 H5 端的 dev 下都不会生效。

CI 或不想被自动弹起开发者工具打断时,设 SKIP_OPEN_DEVTOOLS=true(vite.config.ts:193-194)。

怎么验证跑通了 ​

四步,每步都有确定的判据。只看 dev server 打印 ready 是不够的。

第 1 步:后端在跑 ​

bash
curl -s -X POST http://localhost:48080/admin-api/system/auth/login \
  -H 'Content-Type: application/json' -H 'tenant-id: 1' \
  -d '{"username":"admin","password":"admin123"}'
# 期望:{"code":0,...,"data":{"userId":1,"accessToken":"...","refreshToken":"..."}}

返回 code:0 且 data 里同时有 accessToken 与 refreshToken —— 后者是 VITE_AUTH_MODE='double' 的前提。

这条 curl 返回 code:0 不代表 mock token 没开

Bearer test1 那条免登录后门见坑位索引 A1。这里用的是真实账号口令,走的是正常登录。

第 2 步:导航树接口通 ​

bash
TOKEN=$(curl -s -X POST http://localhost:48080/admin-api/system/auth/login \
  -H 'Content-Type: application/json' -H 'tenant-id: 1' \
  -d '{"username":"admin","password":"admin123"}' \
  | node -pe 'JSON.parse(require("fs").readFileSync(0)).data.accessToken')
curl -s "http://localhost:48080/admin-api/system/nav-node/tree?terminal=app" \
  -H "Authorization: Bearer $TOKEN" -H 'tenant-id: 1'

期望 code:0 且 data 是非空数组。本机实测返回 3 个顶层分组 / 19 个节点(库里 20 行存活,AI 大模型 组因零个存活子节点被剪枝)——这条剪枝规则见服务端驱动导航。

用 admin 测出来的是「不过滤」的树

admin 是超级管理员,权限判定走短路(GrantDecisionService#isSuperAdmin)。要验证 permissions 过滤真的生效,必须换一个非超管账号——这是坑位索引 D3 在移动端的同一件事。

第 3 步:H5 页面起来了 ​

浏览器打开 http://localhost:9000,应当自动跳到登录页(/pages-core/auth/login),因为路由拦截器默认「需要登录」(src/router/config.ts:8-10)。

🔴 页面标题可能还是旧的——env 改了必须重启 dev server

loadEnv 只在 vite.config.ts:70 求值一次,VITE_APP_TITLE 被闭包捕获后交给 transformIndexHtml(:170)。Vite 不会因为 .env 变化重新求值 config。

本机 2026-10-25 实测:env/.env:1 已是 启凌智搭(提交 d434864f,2026-10-24 改的),但正在跑的 :9000 进程仍返回 <title>X评云</title>——那是改名前的值。进程比源文件旧,标题、base、端口都是启动那一刻定死的。

所以「标题不对」不是 bug,是该重启了。同理适用于任何 env/.env* 的改动。

第 4 步:登录进去,工作台有卡片 ​

用 admin / admin123 登录(租户默认 id=1,其名称实测为「启凌智搭」)。登录后应当看到工作台,上面有 系统管理 / 基础设施 / 工作流程 三个分组的卡片。

浏览器 Network 面板里应当看到 /system/nav-node/tree?terminal=app 返回 200,请求打的是 localhost:48080(直连,没有 proxy 前缀)。

如果工作台是空的但登录成功:先查第 2 步的接口返回是不是空数组,再查当前账号是不是非超管且没有对应 permissions(见服务端驱动导航的过滤链)。

怎么扩展 ​

  • 加一个页面:移动端页面开发范式
  • 加一个环境变量:写进 env/.env(基线)或对应 mode 文件,然后在 src/env.d.ts:11-36 的 ImportMetaEnv 里补类型声明——否则 import.meta.env.XXX 在 type-check 下报错
  • 改端口 / 后端地址:只改 env/,改完重启 dev server

坑与注意 ​

  • env/.env.local 不存在,与 Web 仓不同(Web 仓的 .env.local 是纳入 git 跟踪的,见坑位索引 B2)。移动端只有 4 个 env 文件,别按 Web 的习惯去找 .env.local。
  • pnpm dev 会占住终端并 watch,改 pages.config.ts / src/tabbar/config.ts 这类生成 pages.json 的配置必须重启——pages.json 是产物,HMR 覆盖不到它。
  • eruda(移动端调试面板)只在 H5 + development 注入(vite.config.ts:189-191)。dev:test / dev:prod 的 mode 不是 development,所以没有 eruda,别以为是坏了。
  • 小程序端要在开发者工具里勾「不校验合法域名」(详情 → 本地设置),否则 localhost:48080 会被拦。
  • 后端库名是 ainb-professional-init,不是上游的 ruoyi-vue-pro,见坑位索引与环境准备与启动。

→ 本节是贴着上下文的提醒;按症状查的移动端全域清单见移动端坑位,跨端清单见坑位索引。

未证实 ​

  • 微信小程序与 App 两条路径本机从未实测:dist/dev/mp-weixin 的导入流程、miniprogram-ci 上传、HBuilderX 打包、原生插件资源复制都只有源码依据。
  • pnpm install 在全新克隆上的完整行为未实测(本机 node_modules 已存在)。prepare 用 & 并行,init-husky 失败时 init-baseFiles 是否仍会执行,取决于 shell 对 & 的处理,没有验证过。
  • 「新克隆不跑 init-baseFiles 则 type-check 失败」是静态推断:src/utils/index.ts:3 直接 import { pages, subPackages } from '@/pages.json',而该文件不入库。没有真的在干净目录上复现。

相关页面 ​