refactor(cli): discover app startup rows from injection
This commit is contained in:
@@ -14,9 +14,9 @@ dsh 启动器交给它所引导应用的那条命令行。启动器只解析属
|
||||
|
||||
没有命令行的嵌入宿主提供空列表;这是诚实的答案,而不是缺失的值。
|
||||
|
||||
## 入口点,以及它的应用所读取的服务
|
||||
## 启动行,以及它的应用所读取的服务
|
||||
|
||||
应用从自己的**入口点行**读取这些参数:入口点行是一个注入 `cmdlineArgs` 并调用 `runStartup(ctx, service, program, plan)` 的插件:
|
||||
应用从自己的**启动行**读取这些参数:这是一个在 Loader 行与插件中都注入 `cmdlineArgs`,并调用 `runStartup(ctx, service, program, plan)` 的插件:
|
||||
|
||||
```ts ignore
|
||||
export const name = 'web-startup'
|
||||
@@ -27,13 +27,17 @@ export function apply(ctx: Context): void {
|
||||
}
|
||||
```
|
||||
|
||||
组合包的 `package.json` 点名那一行,这正是 boot 先于其他一切挂载它的依据:
|
||||
Loader 行的注入同时也是发现声明,因此无需组合包 manifest 字段:
|
||||
|
||||
```json
|
||||
{ "dsh": { "bundle": { "patch": "./cordis.patch.yml", "entrypoint": "web-startup" } } }
|
||||
```yaml
|
||||
- id: web-startup
|
||||
name: '@deepseek-ai/dsh-web-app/startup'
|
||||
inject: [cmdlineArgs]
|
||||
```
|
||||
|
||||
应用用 flag 配置的每一行随后读取入口点解析出的取值,各自点名自己取用的键,以及回退时使用的值:
|
||||
启动器在组合结果中找出带有该注入的活跃行,并先于其他一切挂载它们。
|
||||
|
||||
应用用 flag 配置的每一行随后读取启动行解析出的取值,各自点名自己取用的键,以及回退时使用的值:
|
||||
|
||||
```yaml
|
||||
- id: webserver
|
||||
@@ -50,13 +54,13 @@ export function apply(ctx: Context): void {
|
||||
|
||||
### 为什么 boot 分阶段
|
||||
|
||||
行的配置表达式在 include 施加该行时求值,而严格的 `ctx.get` 只对提供方 fiber 已经 active 的服务作答。因此一套组合分两趟挂载:先是各入口点,然后才是其余部分——这正是 manifest(元数据清单)声明所换来的东西。后一趟的行读到的是活的取值,`--help` 在第二趟存在之前就退出,而用户编辑一个活动的 patch 文件时,这一趟会针对仍然在线的服务重新运行,因此 flag 不会被悄悄重置。
|
||||
行的配置表达式在 include 施加该行时求值,而严格的 `ctx.get` 只对提供方 fiber 已经 active 的服务作答。因此一套组合分两趟挂载:先是各个活跃的 `cmdlineArgs` 消费方,然后才是其余部分。后一趟的行读到的是活的取值,`--help` 在第二趟存在之前就退出,而用户编辑一个活动的 patch 文件时,这一趟会针对仍然在线的服务重新运行,因此 flag 不会被悄悄重置。
|
||||
|
||||
`enableRow(ctx, id)` 打开某个组合包以禁用状态交付、只有部分调用才需要的行(`dsh web --dev` 及其客户端插件重载链路)。要从与被启用行同一趟挂载的行里调用它,而不是从入口点:在第一趟被启用的行会去等待第二趟才挂载的服务。
|
||||
`enableRow(ctx, id)` 打开某个组合包以禁用状态交付、只有部分调用才需要的行(`dsh web --dev` 及其客户端插件重载链路)。要从与被启用行同一趟挂载的行里调用它,而不是从启动行:在第一趟被启用的行会去等待第二趟才挂载的服务。
|
||||
|
||||
### 一条命令行,一个所有者
|
||||
|
||||
一套组合有且只有一个命令行所有者。叠加在另一应用之上的应用会禁用下层的入口点行,并同时点名两个服务,使它吸收过来的行按各自回退值启动:[`dsh-headless`](../../bundle/headless/README.md) 相对 [`dsh-web-app`](../../bundle/web-app/README.md) 就是这么做的。
|
||||
一套组合有且只有一个命令行所有者。叠加在另一应用之上的应用会禁用下层的启动行,并同时点名两个服务,使它吸收过来的行按各自回退值启动:[`dsh-headless`](../../bundle/headless/README.md) 相对 [`dsh-web-app`](../../bundle/web-app/README.md) 就是这么做的。
|
||||
|
||||
树外插件会带来自己的一份 commander 副本,因此 commander 的控制流错误按结构识别,而不是按类身份识别;按身份判断会把已经打印出来的 help 重新抛成致命的加载失败。
|
||||
|
||||
@@ -71,5 +75,5 @@ export function apply(ctx: Context): void {
|
||||
## 已知限制与延期工作
|
||||
|
||||
- **启动器的 flag 必须写在应用参数之前**:切分按位置进行,启动器不认识的第一个 token 就是内层参数的起点,因此写在某个应用 flag 之后的 `--patch` 属于应用。启动器的解析器会消耗掉一个 `--`,因此必须以字面量 `--` 存活到应用的参数需要写成 `-- --`。
|
||||
- **启动服务没有声明所有者**:各行点名它,由入口点提供它;两者之间没有静态关联,因此交付了读取行却缺少对应入口点的组合包会在结算时失败(出现指向该服务的待处理条目),而不是在加载时失败。
|
||||
- **启动服务没有声明所有者**:读取行点名它,由 `cmdlineArgs` 消费方提供它;这两种注入之间没有静态关联,因此交付了读取行却缺少对应启动行的组合包会在结算时失败(出现指向该服务的待处理条目),而不是在加载时失败。
|
||||
- **用户 patch 若整体替换某行的 `config`,会连同其中的表达式一起丢掉**:flag 胜过的是表达式旁写着的那个值,而不是用户用字面量替换掉表达式之后的结果;保留表达式才能保留 flag 的优先级。
|
||||
|
||||
Reference in New Issue
Block a user