应用发布
Oak 应用的发布,至少包含三件事:
- 发布后端可执行代码;
- 发布前端目标端产物;
- 发布和校验应用本身的运行配置。
如果只做了前两件事,而忽略了 application/system/domain 这些运行时数据配置,那么应用很可能能启动,但无法正确识别自己,也无法向客户端提供正确的版本和域名信息。
一、Oak 应用真正的发布单元
从源码上看,一个 Oak 应用上线时真正依赖的东西包括:
1. 后端 lib
后端运行的是编译后的 lib 目录,而不是 src 目录中的 TypeScript。
2. 前端目标端产物
不同目标端分别由 Oak CLI 构建:
- web
- wechatMp
- native
3. 数据库与静态数据
数据库中不仅有业务数据,还包括:
- 权限相关数据
- i18n 数据
- 系统与应用配置数据
4. application / system 运行配置
如果你使用了 oak-general-business,前端启动时会先通过 features.application.initialize(...) 去拉取当前应用信息。这个过程最终会调用 getApplication(version, type, domain, appId)。
也就是说,Oak 前端并不是“只要打包好就能随便跑”,它还需要在后台找到与当前域名、当前端类型、当前版本匹配的 application 配置。
二、为什么 application 配置是发布的一部分
oak-general-business/src/aspects/application.ts 中的 getApplication(...) 在返回应用配置前,会调用 checkAppVersionSafe(...) 检查当前版本是否允许访问。
这一步会参考:
system.oldestVersionsystem.platform.oldestVersionapplication.dangerousVersionsapplication.warningVersions
如果当前客户端版本过低或命中了危险版本,后端会直接抛出 OakApplicationHasToUpgrade。
这说明 Oak 的发布不是“前端和后端各发各的”那么简单,而是要把版本策略也纳入发布动作。
三、一个推荐的发布顺序
比较稳妥的发布顺序如下:
- 在构建机执行
make:domain、make:locale、make:dep,依赖模块有增删时先执行project:init; - 编译后端
npm run build; - 对已有数据库执行
npm run db:upgrade:plan生成结构升级计划,并审核migration.sql、warnings.json、rename-candidates.json; - 按目标端构建前端,如
npm run build:web、npm run build:mp; - 发布后端代码和配置;
- 首次部署执行
npm run server:init;已有库按审核后的结构升级计划升级数据库; - 执行
upgrade:locale/upgrade:auth/upgrade:all这类静态数据同步脚本; - 校验
application/system/domain数据是否已经准备好; - 启动后端;
- 再发布前端静态资源或客户端包。
之所以把“校验应用配置”单独列出来,是因为 Oak 应用经常在这一环节出问题,而不是出在代码本身。
四、发布前至少要检查什么
对一个新手来说,发布前最值得检查的是下面这些信息:
- 当前目标端的
application.type是否正确; - web 端域名是否与
application/domain/system配置一致; - 小程序 / 公众号 / App 所需的
appId、appSecret等参数是否已配置; - 当前版本是否会被
oldestVersion或dangerousVersions拦截; - 依赖的对象存储、短信、OAuth、微信等外部配置是否已经上线可用。
这些信息很多并不在代码仓库里,而是在 Oak 的业务数据里。所以 Oak 项目的发布,往往天然就要求“代码发布”和“配置数据发布”配套进行。
五、如何理解“前端发布成功”
在 Oak 里,前端发布成功不只是“静态资源可访问”。
更准确地说,应该至少同时满足:
- 前端资源可正常加载;
- 前端能拿到正确的
application; - 后端没有因为版本策略直接拒绝它;
- 当前目标端的关键配置已经就位。
否则,用户看到的可能不是一个正常页面,而是直接进入升级态、错误态或配置异常态。
六、一个很重要的实践建议
在 Oak 中,把“应用配置数据”视为发布产物的一部分,而不是上线后的手工补丁。
只要你接受了这一点,Oak 的发布流程就会清晰很多。因为你会自然地把:
- 代码构建
- 数据初始化
- 配置校验
- 版本拦截策略
看成同一件事的不同阶段,而不是互不相干的杂项。