部署
Oak 的开发模式非常灵活,但真正部署到线上时,建议把它理解成两部分:
- 前端产物的构建与发布;
- 后端服务进程的编译、初始化与运行。
本地开发也应默认使用真实后端运行态。当前模板的 npm run dev 会同时启动 server:start 和 start:web,线上部署时则应把后端服务进程和各目标端产物分开发布。
部署前要先明确的事实
一个真正启动起来的 Oak 后端,不只是提供查询和保存数据这么简单。根据 oak-backend-base/src/AppLoader.ts 的实现,服务启动后还会继续负责:
- 装配所有
trigger、checker和内置逻辑; - 暴露
aspect和endpoint; - 注册导入导出
port; - 每 120 秒轮询一次
watcher; - 通过
node-schedule运行timer; - 在启动和停止时执行
routines/start、routines/stop。
所以,线上环境中的 Oak 后端,本质上是整个业务系统的运行核心,而不只是一个“给前端提供接口”的薄服务。
一、部署后端
1. 编译项目
先在项目根目录执行:
npm run make:domain
npm run make:locale
npm run make:dep
npm run build
如果这次发布增删了 Oak 依赖模块,先执行 npm run project:init,再执行 npm run make:domain 和 npm run make:dep。这一步完成后,项目中的 TypeScript 后端代码会被编译到 lib 目录。真正上线运行的 Node.js 进程,就是基于这里的代码。
已有数据库的结构变更不要直接混在 server:init 里处理。编译后先生成升级计划:
npm run db:upgrade:plan
它会在 .oak-upgrade/<时间戳> 下输出 migration.sql、rollback.sql、summary.json、table-changes.json、warnings.json 和 rename-candidates.json。审核无误后,再由 DBA 或发布脚本执行结构升级。只有明确接受风险时,才使用:
npm run db:upgrade:plan -- --execute
如果计划里有 manualSql、warnings 或 renameCandidates,不要直接执行;先确认是否是列/索引重命名、大表索引调整、枚举变更或需要人工拆分的 DDL。
2. 准备数据库
Oak 后端当前按数据库类型 mysql -> postgres -> sqlite 查找配置;每种类型都先检查环境文件,再检查普通文件:
configuration/mysql.${NODE_ENV}.json
configuration/mysql.json
configuration/postgres.${NODE_ENV}.json
configuration/postgres.json
configuration/sqlite.${NODE_ENV}.json
configuration/sqlite.json
找到第一份有效配置后就确定 store。项目还必须安装对应驱动:MySQL 使用 mysql2,PostgreSQL 使用 pg,SQLite 使用 better-sqlite3。
本书前面已经提到过,常见做法是在项目配置中写好数据库参数,并先创建空库:
create database xxx default character set utf8mb4;
然后执行:
npm run server:init
它会根据当前项目编译后的 Storage 定义和 src/data 中的静态数据去初始化数据库。
::: danger 只能用于首次初始化
当前普通模板的 initServer.js 通常调用 AppLoader.initialize('dropIfNotStatic')。该模式会删除并重建所有非 static 实体表,再插入 seed 数据。它不是“补一条初始化数据”的增量命令,已有开发库和生产库都不能为了刷新 src/data 随手执行。
已有数据库应使用审核后的 schema migration 和明确的数据迁移;执行任何初始化脚本前,先读取项目自己的 scripts/initServer.js,确认实际 ifExists 参数。
:::
SQLite 适合本地单机工具、Desktop 配套服务和较轻量部署。最小配置示例:
{
"filename": "data/app.sqlite",
"poolSize": 4
}
SQLite 已支持 schema inspection 和 migration plan,但仍有方言边界,例如不支持任意列定义原地修改和数据库 view。升级时同样先审核 db:upgrade:plan,不要把它当作无结构数据库。
3. 启动服务
npm run server:start
此命令启动的就是正式的 Oak 后端运行进程。通常线上环境还会再用 pm2、systemd、容器编排系统等方式去守护这个进程,这一层属于通用 Node.js 运维能力,并不是 Oak 特有的部分。
4. 可选的 server bundle
新项目还提供:
npm run build:bundle
它使用 esbuild 生成独立的后端部署目录,主要包含:
dist/
├── server.js
├── package.json
├── server-metafile.json
├── target/
├── configuration/
└── oak-packages/
项目根的 pm2.*.json 会按原名复制;构建器不会生成固定的 pm2.prod.config.json。启动、初始化和升级命令都由 dist/package.json 指向本地入口:
node server.js
node server.js initialize
node server.js db:upgrade:plan
Server bundle 当前是 opt-in 路径,不替代普通 build:lib。部署前检查:
configuration/*.json是否已按环境安全提供,且没有把密码配置提交到仓库;- 目标数据库驱动是否进入部署环境;
server.nodeModules.bundle与第三方依赖安装策略是否一致;- Oak 包是否按
package.json.oak.package输出到dist/oak-packages; - 动态 require、原生模块和项目根资源是否能在干净机器上解析。
建议在空目录或容器中只使用 dist 和计划中的外部依赖做一次真实启动验证,不能仅以构建成功作为部署成功。
二、部署 web 前端
web 端一般通过 Oak CLI 构建:
npm run build:web
或者在预发环境使用:
npm run build:web:staging
这些脚本本质上都来自 oak-cli build --target web --mode ...。构建完成后,再把生成的静态资源发布到你的 web 服务器或 CDN 即可。
需要注意的是,线上 web 前端必须请求真实后端服务。start:web 只是本地 Vite 开发服务,不是生产运行方式。
三、部署小程序、App 和 Desktop
微信小程序和 App 的部署思路与 web 一样,都是“先构建目标端产物,再发布目标端”:
npm run build:mp
React Native 端则还会涉及原生包的打包与签名,这部分更多取决于 React Native 自身的工程流程。
Desktop 先通过 oak-cli add desktop 创建 workspace,再执行生成的构建脚本:
npm run build:desktop:desktop
Tauri 会生成原生 Rust 应用产物,Electron 会交给 electron-builder。Desktop renderer 使用相对 public path,并把 Web 依赖打进本地 bundle,不应依赖在线 CDN 才能启动。发布前还要验证:
src/data/i18n.json已生成并进入原生资源;.oak-desktop.json的identifyId与后端 Desktop Application 配置一致;src/configuration/access.ts指向真实后端;- 安装包签名、自动更新和操作系统权限符合项目发布策略。
但无论是哪一个前端目标端,只要业务逻辑依赖真实数据库、第三方服务、消息推送、定时任务或导入导出能力,线上都必须配套部署 Oak 后端。
四、推荐的上线顺序
一个比较稳妥的上线顺序如下:
- 在构建机上执行生成与编译脚本;
- 发布后端代码和配置;
- 对已有数据库执行并审核
db:upgrade:plan; - 首次部署执行
server:init,已有库执行审核后的结构升级 SQL; - 执行权限、i18n、静态数据升级脚本;
- 启动新的后端进程;
- 再发布前端静态资源或多端包。
如果你的项目已经进入持续发布阶段,还应把数据库变更、静态数据更新和前端发布进一步拆成明确的流水线步骤。Oak 在框架层面已经把“对象定义”“依赖装配”“国际化编译”“服务端运行”这些关键阶段分清楚了,部署脚本只需要老老实实顺着这个顺序来。
五、不要把开发命令直接当成生产命令
最后强调一个很容易被新手忽略的问题:
start:web、start:mp这类命令只负责目标端开发服务,不是为了替代正式部署。
真正的业务系统仍然需要一个完整运行的 Oak 后端进程来承担一致性、权限、定时、导入导出、外部集成等职责。前端目标端产物只是用户入口,不是业务运行核心。