@manohub/app-kit 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRACT.md +174 -9
- package/README.md +9 -5
- package/bin/appkit.mjs +121 -0
- package/lint/__tests__/guardrails.spec.mjs +154 -0
- package/lint/component-audit.mjs +1 -1
- package/lint/guardrails.config.schema.json +42 -0
- package/lint/pre-commit.sample +38 -26
- package/lint/run-all.mjs +63 -59
- package/lint/shared.mjs +462 -347
- package/lint/structure-audit.mjs +1 -1
- package/lint/style-audit.mjs +1 -1
- package/package.json +7 -3
- package/skills/README.md +32 -10
- package/skills/app-kit/SKILL.md +19 -11
- package/skills/app-kit/references/adoption.md +76 -6
- package/skills/app-kit/references/contract-index.md +7 -2
- package/skills/app-kit-dev/SKILL.md +40 -8
- package/skills/app-kit-dev/references/page-recipes.md +53 -5
- package/skills/app-kit-dev/references/style-rules.md +2 -2
- package/skills/app-kit-migrate/SKILL.md +30 -11
- package/skills/app-kit-migrate/references/migration-playbook.md +53 -4
- package/skills/install.mjs +298 -222
package/lint/structure-audit.mjs
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* S8 用了 AppShell.Split 的应用,其 CSS 不应再出现竖直边框(分隔线由 Split 提供)→ warn
|
|
13
13
|
* S9 分页与承载表格的容器错位(文件里有 AppPanel 却把 AppPagination 放 AppShell.Footer)→ warn
|
|
14
14
|
*
|
|
15
|
-
* 用法:
|
|
15
|
+
* 用法:pnpm exec appkit lint:structure [--json] [--changed]
|
|
16
16
|
*/
|
|
17
17
|
import { readFileSync } from 'node:fs'
|
|
18
18
|
import { join } from 'node:path'
|
package/lint/style-audit.mjs
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* (规则 4/5/7/10/11/12 仍然生效)。
|
|
18
18
|
*
|
|
19
19
|
* 用法:
|
|
20
|
-
*
|
|
20
|
+
* pnpm exec appkit lint:style [--json] [--strict] [--changed] [--app=<name>]
|
|
21
21
|
* 配置:应用包根 appkit-guardrails.config.json
|
|
22
22
|
*/
|
|
23
23
|
import { readFileSync, existsSync } from 'node:fs'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@manohub/app-kit",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "子应用统一骨架层:入口编排(createSubApp)、布局契约(AppShell)、页面组件、原子件、服务、样式底座。farris 被收敛在本包内部,对外只暴露标准 API。",
|
|
@@ -18,9 +18,13 @@
|
|
|
18
18
|
"dist",
|
|
19
19
|
"lint",
|
|
20
20
|
"skills",
|
|
21
|
+
"bin",
|
|
21
22
|
"CONTRACT.md",
|
|
22
23
|
"README.md"
|
|
23
24
|
],
|
|
25
|
+
"bin": {
|
|
26
|
+
"appkit": "./bin/appkit.mjs"
|
|
27
|
+
},
|
|
24
28
|
"sideEffects": [
|
|
25
29
|
"**/*.css"
|
|
26
30
|
],
|
|
@@ -44,7 +48,7 @@
|
|
|
44
48
|
"scripts": {
|
|
45
49
|
"build": "node ../../scripts/clean-dist.mjs && vue-tsc -p tsconfig.build.json && vite build && node scripts/copy-styles.mjs",
|
|
46
50
|
"type-check": "vue-tsc --noEmit -p tsconfig.json",
|
|
47
|
-
"test:unit": "vitest run && node --test lint/__tests__/guardrails.spec.mjs __tests__/skills-install.test.mjs",
|
|
51
|
+
"test:unit": "vitest run && node --test lint/__tests__/guardrails.spec.mjs __tests__/skills-install.test.mjs __tests__/cli.test.mjs",
|
|
48
52
|
"test:guardrails": "node --test lint/__tests__/guardrails.spec.mjs",
|
|
49
53
|
"test:watch": "vitest"
|
|
50
54
|
},
|
|
@@ -59,7 +63,7 @@
|
|
|
59
63
|
},
|
|
60
64
|
"dependencies": {
|
|
61
65
|
"@farris/ui-vue": "^1.8.4",
|
|
62
|
-
"@manohub/icon": "^0.2.
|
|
66
|
+
"@manohub/icon": "^0.2.3"
|
|
63
67
|
},
|
|
64
68
|
"devDependencies": {
|
|
65
69
|
"@tanstack/vue-query": "catalog:",
|
package/skills/README.md
CHANGED
|
@@ -9,35 +9,57 @@
|
|
|
9
9
|
|
|
10
10
|
| 技能 | 职责 | 可独立调用 |
|
|
11
11
|
|---|---|---|
|
|
12
|
-
| `app-kit` | 入口编排:识别意图 → 调 `app-kit-migrate` 或 `app-kit-dev
|
|
13
|
-
| `app-kit-migrate` |
|
|
12
|
+
| `app-kit` | 入口编排:识别意图 → 调 `app-kit-migrate` 或 `app-kit-dev`(另有「从零建新应用」导到接入 SOP);承载全局硬约束 | 是(子技能也可直接调) |
|
|
13
|
+
| `app-kit-migrate` | 存量应用改造到本包(直连底层组件库,或其它 UI 库 / 自绘):产基线 → 逐文件替换 → 归零 → 验收 → 登记;支持**只迁一部分**(只迁骨架 / Shell-only,其余走规则级豁免) | 是 |
|
|
14
14
|
| `app-kit-dev` | 按本包规范做日常页面开发:选模板 / 选组件 / 样式纪律 / 缺件处置 / 自检 | 是 |
|
|
15
15
|
|
|
16
16
|
## 安装到消费方技能目录
|
|
17
17
|
|
|
18
|
-
在消费方**工程根**执行(缺省落 `.codebuddy/skills
|
|
18
|
+
在消费方**工程根**执行(缺省落 `.codebuddy/skills/`);`appkit` 是本包的命令入口(`bin`),
|
|
19
|
+
npm 消费方把 `pnpm exec` 换成 `npx`:
|
|
19
20
|
|
|
20
21
|
```bash
|
|
21
|
-
|
|
22
|
+
pnpm exec appkit install
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
pnpm exec appkit install --also-claude # 同时落 .claude/skills/
|
|
25
|
+
pnpm exec appkit install --target .x/skills
|
|
26
|
+
pnpm exec appkit install --dry-run # 只预览不落盘
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
输出示例(每个技能都会报告内容有没有变):
|
|
30
|
+
|
|
31
|
+
```text
|
|
32
|
+
[app-kit 技能安装]
|
|
33
|
+
源:…/node_modules/@manohub/app-kit/skills
|
|
34
|
+
目标:…/.codebuddy/skills
|
|
35
|
+
….codebuddy/skills/app-kit —— 更新 2(共 3 个文件)
|
|
36
|
+
….codebuddy/skills/app-kit-migrate —— 已是包内最新(内容无变化,共 3 个文件)
|
|
37
|
+
完成:技能目录已与包内内容对齐(包升级后重跑本命令即刷新)
|
|
26
38
|
```
|
|
27
39
|
|
|
28
40
|
安装器是幂等的:每次执行**先清理同名技能目录再整体复制**,所以包升级后重跑一次即刷新到新版内容。
|
|
41
|
+
等价写法(老脚本/钩子里可用):`node node_modules/@manohub/app-kit/skills/install.mjs`。
|
|
29
42
|
它只管理 `app-kit` / `app-kit-migrate` / `app-kit-dev` 这三个目录,不触碰目标目录下的其它内容。
|
|
43
|
+
每次执行都会报告**技能内容有没有变**(「更新 N / 新增 N」=本次升级改了技能、已生效;
|
|
44
|
+
「已是包内最新」=本次升级没动技能包),这样消费方不必靠猜「我的技能是不是旧的」。
|
|
30
45
|
|
|
31
46
|
## 维护约定(改本目录时遵守)
|
|
32
47
|
|
|
33
48
|
- 引用规范一律写**消费方视角**路径:`node_modules/@manohub/app-kit/CONTRACT.md` §x.y。
|
|
34
49
|
禁止出现本机绝对路径、worktree 路径、仓库内相对路径(技能落盘后与包目录分离,这些路径会失效)。
|
|
35
50
|
- `SKILL.md` 只放流程与硬约束(控制在 5k 词内);查表内容(替换映射、场景配方)放各自的 `references/`,按需加载。
|
|
36
|
-
- 三个技能的 `description`
|
|
37
|
-
-
|
|
51
|
+
- 三个技能的 `description` 触发条件互不重叠,否则代理会命中错的那个
|
|
52
|
+
(`app-kit` 只在「意图还没落到具体任务」时命中,具体任务交给两个子技能)。
|
|
53
|
+
- 技能引用的 `references/` 文件必须真实存在,文件名改动要同步 `SKILL.md`
|
|
54
|
+
(已由 `verify-pack` 的 `checkSkillPack` 机械校验,跨技能引用 `../<skill>/references/…` 同样校验)。
|
|
55
|
+
- 技能目录下的每个文件都必须真进 tarball(`references/` 漏发时「查表」会整体失效,也已机械校验)。
|
|
56
|
+
- 技能与文档里的命令一律写**消费方命令** `pnpm exec appkit …`(npm 注一句 `npx`),
|
|
57
|
+
不要再写 `node node_modules/@manohub/app-kit/...`(只有 `bin/appkit.mjs` 的说明性文字可引用它作对照)。
|
|
58
|
+
- 新增 `appkit` 子命令:在 `bin/appkit.mjs` 的 `COMMANDS` 表加一行即可(薄壳,转调包内脚本);
|
|
59
|
+
`__tests__/cli.test.mjs` 覆盖解析与「参数真透传」,`verify-pack` 校验 `bin/appkit.mjs` 随包分发。
|
|
38
60
|
- 改动后跑门禁与打包校验(在仓库根):
|
|
39
61
|
|
|
40
62
|
```bash
|
|
41
63
|
pnpm --filter @manohub/app-kit test:unit # 契约单测 + 护栏自测
|
|
42
|
-
pnpm release:check # build + verify-pack
|
|
64
|
+
pnpm release:check # build + verify-pack(含技能包结构/引用校验)
|
|
43
65
|
```
|
package/skills/app-kit/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: app-kit
|
|
3
3
|
version: 1.0.0
|
|
4
|
-
description: 子应用骨架层 @manohub/app-kit 的入口技能:识别意图并编排到 app-kit-migrate(存量应用改造)或 app-kit-dev
|
|
4
|
+
description: 子应用骨架层 @manohub/app-kit 的入口技能:识别意图并编排到 app-kit-migrate(存量应用改造)或 app-kit-dev(日常页面开发),并承载两个子技能共用的全局硬约束。触发条件:用户提到 app-kit 或骨架层本身、询问骨架层总体规范/该怎么接入或改造但尚未落到具体页面或文件、不确定该用哪个 app-kit 技能、或需要护栏命令/接入步骤/升级口径等跨场景事项时使用;一旦意图明确落到「迁移存量应用」或「写/改页面」,由对应子技能承接。
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# app-kit:骨架层入口编排
|
|
@@ -16,7 +16,9 @@ description: 子应用骨架层 @manohub/app-kit 的入口技能:识别意图
|
|
|
16
16
|
| 应用尚未接入本包;或页面/组件仍在直连底层组件库、仍写底层风格 prop;或出现「迁移」「改造」「接入」「护栏基线」「违规归零」 | `Skill('app-kit-migrate')` |
|
|
17
17
|
| 应用已接入,要新增或修改页面、组件;或要求「按 app-kit 规范写」「用 AppTable / AppDialog / AppForm…」 | `Skill('app-kit-dev')` |
|
|
18
18
|
| 两者交织(边接入边改页面) | 先跑 `app-kit-migrate` 的接入阶段(护栏能跑起来、基线在案),再进 `app-kit-dev` |
|
|
19
|
-
|
|
|
19
|
+
| 应用还不存在,要从零建一个子应用 | 按 `references/adoption.md` «9. 新应用从零搭建(最小骨架)» 走(工程、依赖、三行样式、入口、护栏、技能落盘、必须向宿主确认的项),建成后按上面的表继续 |
|
|
20
|
+
| 应用用的不是本包收敛的底层组件库(别的 UI 库 / 自绘),但页面要接骨架层 | 仍走 `app-kit-migrate`:阶段 0 有「存量源判定」分支,映射表查不到时按契约重建骨架 |
|
|
21
|
+
| 与骨架层无关(纯后端问题、非 Vue 前端工程) | 不使用本技能 |
|
|
20
22
|
|
|
21
23
|
意图不明时先问一句「是要把存量页面改造过来,还是新写页面」,不要猜。
|
|
22
24
|
|
|
@@ -24,7 +26,8 @@ description: 子应用骨架层 @manohub/app-kit 的入口技能:识别意图
|
|
|
24
26
|
|
|
25
27
|
1. **不得直连底层组件库**:应用侧禁止 `import '@farris/ui-vue'`、禁止把它装成依赖、禁止写它的内部类选择器(`.fv-*`)。
|
|
26
28
|
组件一律从 `@manohub/app-kit` 取;确需的能力按 `CONTRACT.md` §7 缺件处置流程办,不在应用侧自绘近似件。
|
|
27
|
-
2. **冲突时按此优先级**:包内 `CONTRACT.md` >
|
|
29
|
+
2. **冲突时按此优先级**:包内 `CONTRACT.md` > 组件类型声明里的 `@example`
|
|
30
|
+
(`node_modules/@manohub/app-kit/dist/**/*.d.ts`,本包为产物分发、没有源码)> 消费仓 `AGENTS.md` > 其它文档。
|
|
28
31
|
发现 `@example` 与契约冲突,按契约写,并把该 `@example` 当缺陷处理。
|
|
29
32
|
3. **护栏是唯一裁判**:三条护栏(style / component / structure)给出的 `file:line` + `correction` 就是唯一改法,
|
|
30
33
|
照它改,不要另想一套;每条违规都带 `doc` 锚点,指回契约章节。
|
|
@@ -35,16 +38,20 @@ description: 子应用骨架层 @manohub/app-kit 的入口技能:识别意图
|
|
|
35
38
|
## 三、固定命令(在应用包根执行)
|
|
36
39
|
|
|
37
40
|
```bash
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
pnpm exec
|
|
41
|
-
pnpm
|
|
41
|
+
pnpm exec appkit lint # 全量三条护栏
|
|
42
|
+
pnpm exec appkit lint --changed # 只查改动文件(提交前)
|
|
43
|
+
pnpm exec appkit lint --strict # 收口验收:挂起与豁免一律失效(§8.2)
|
|
44
|
+
pnpm exec appkit lint:style # 单条排查:style / component / structure
|
|
45
|
+
pnpm exec vue-tsc --noEmit # 类型检查
|
|
46
|
+
pnpm build # 生产构建
|
|
42
47
|
```
|
|
43
48
|
|
|
44
|
-
|
|
49
|
+
- `appkit` 是本包的命令入口(`package.json` 的 `bin`);npm 消费方把 `pnpm exec` 换成 `npx`。
|
|
50
|
+
老写法 `node node_modules/@manohub/app-kit/lint/run-all.mjs` 仍然等价可用,不必改已有脚本。
|
|
51
|
+
- 技能包内容更新后重新落盘(幂等,包升级后重跑即刷新):
|
|
45
52
|
|
|
46
53
|
```bash
|
|
47
|
-
node node_modules/@manohub/app-kit/skills/install.mjs
|
|
54
|
+
pnpm exec appkit install # 等价:node node_modules/@manohub/app-kit/skills/install.mjs
|
|
48
55
|
```
|
|
49
56
|
|
|
50
57
|
## 四、失败处理
|
|
@@ -54,12 +61,13 @@ node node_modules/@manohub/app-kit/skills/install.mjs
|
|
|
54
61
|
| 找不到 `node_modules/@manohub/app-kit` | 在应用包根执行 `pnpm add @manohub/app-kit`(包在 npm 官方仓公开) |
|
|
55
62
|
| 护栏报缺配置文件 | 应用包根缺 `appkit-guardrails.config.json`,配置片段见 `references/adoption.md` |
|
|
56
63
|
| 装到的版本低于 0.1.1 | 0.1.0 的发布物依赖协议有误已作废(被 deprecate),升级到 0.1.1 以上 |
|
|
57
|
-
| 调子技能报「技能不存在」 | 技能未安装或未刷新,跑上面的 `install
|
|
64
|
+
| 调子技能报「技能不存在」 | 技能未安装或未刷新,跑上面的 `pnpm exec appkit install` |
|
|
65
|
+
| 终端里敲 `appkit` 报 command not found | 用 `pnpm exec appkit …`(或 npm 的 `npx appkit …`);`appkit` 只在 scripts 与 `node_modules/.bin` 语境里可直接写 |
|
|
58
66
|
| 类型检查报「无法解析 `*.css`」 | 消费方 tsconfig 的 `types` 需包含 `vite/client`,见 `references/adoption.md` |
|
|
59
67
|
|
|
60
68
|
## 五、参考
|
|
61
69
|
|
|
62
|
-
- `references/adoption.md`:接入 SOP
|
|
70
|
+
- `references/adoption.md`:接入 SOP(安装、样式三行、入口、护栏、类型配置、验收清单、故障对照、**新应用从零搭建**、升级口径)
|
|
63
71
|
- `references/contract-index.md`:契约速查索引(按主题定位 `CONTRACT.md` 章节,不复制条款)
|
|
64
72
|
- 迁移查表:`../app-kit-migrate/references/migration-map.md`
|
|
65
73
|
- 开发配方:`../app-kit-dev/references/page-recipes.md`
|
|
@@ -57,6 +57,19 @@ export const { mount, unmount } = createSubApp({
|
|
|
57
57
|
})
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
+
`createSubApp` 的全部选项(缺省即用骨架层默认,不要自己再补一层):
|
|
61
|
+
|
|
62
|
+
| 选项 | 用途 |
|
|
63
|
+
|---|---|
|
|
64
|
+
| `rootComponent` / `routes` | 根组件与路由表(路由由应用维护,骨架层只负责装载与守卫) |
|
|
65
|
+
| `extraPlugins` | 额外插件(vue-i18n、埋点等);**i18next 不用它** |
|
|
66
|
+
| `i18n` | i18next 语义:`{ resources: { en: { translation: … }, zh: … }, fallbackLng? }`,随包做宿主语言切换 |
|
|
67
|
+
| `queryClient` | 已有 `@tanstack/vue-query` 实例时传入;不传则骨架层自建(不要传第二份) |
|
|
68
|
+
| `extraStyles` | 追加异步样式(`() => import('./xxx.css')`),用于迁移期还没收进三行链的样式 |
|
|
69
|
+
| `resetToRootOnBoot` | 首屏是否把非根路径重置到 `/`(缺省 `true`)。**不想被重置**时传 `false`;仍想重置但要放过某些入口,则用 `rootPathAliases` |
|
|
70
|
+
| `rootPathAliases` | 登记 `index.html?xxx=1` 这类直开入口,避免首屏守卫清空 query |
|
|
71
|
+
| `onReady` | 挂载完成回调(拿 `VueApp` 实例,用于收尾初始化) |
|
|
72
|
+
|
|
60
73
|
`createSubApp` 已统一负责 `.app-container` 包裹、pinia、Farris 插件、VueQuery、路由、挂载、
|
|
61
74
|
宿主语言监听、首屏守卫、`window.mount/unmount` 与 `microApp.mount/unmount` 协议、非微前端环境自动挂载 ——
|
|
62
75
|
**应用侧不要再手写这些**。
|
|
@@ -80,8 +93,9 @@ export const { mount, unmount } = createSubApp({
|
|
|
80
93
|
// package.json
|
|
81
94
|
{
|
|
82
95
|
"scripts": {
|
|
83
|
-
"lint": "
|
|
84
|
-
"lint:changed": "
|
|
96
|
+
"lint": "appkit lint",
|
|
97
|
+
"lint:changed": "appkit lint --changed",
|
|
98
|
+
"lint:strict": "appkit lint --strict"
|
|
85
99
|
}
|
|
86
100
|
}
|
|
87
101
|
```
|
|
@@ -93,14 +107,17 @@ export const { mount, unmount } = createSubApp({
|
|
|
93
107
|
|
|
94
108
|
```bash
|
|
95
109
|
# 在工程根执行:把三个技能落到 .codebuddy/skills/(幂等,包升级后重跑即刷新)
|
|
96
|
-
|
|
110
|
+
pnpm exec appkit install
|
|
97
111
|
|
|
98
|
-
|
|
99
|
-
|
|
112
|
+
pnpm exec appkit install --also-claude # 同时落 .claude/skills/
|
|
113
|
+
pnpm exec appkit install --dry-run # 只预览
|
|
100
114
|
```
|
|
101
115
|
|
|
102
116
|
装了之后,AI 代理在做本项目前端开发或改造时会自动命中骨架层的规范与流程。
|
|
103
117
|
|
|
118
|
+
安装器每次都会报告**技能内容有没有变**:显示「更新 N / 新增 N」说明这次升级改了技能内容、本次刷新已生效;
|
|
119
|
+
显示「已是包内最新(内容无变化)」说明本包这次升级没动技能包,不必重复刷新。
|
|
120
|
+
|
|
104
121
|
## 6. 类型与解析配置
|
|
105
122
|
|
|
106
123
|
- `tsconfig`:`moduleResolution: "bundler"`(包的 `exports` 走子路径,node10 解析不读 `exports`)。
|
|
@@ -131,7 +148,60 @@ node node_modules/@manohub/app-kit/skills/install.mjs --dry-run # 只预
|
|
|
131
148
|
| 页面被跳到根路径、query 丢了 | 直开入口未登记 `rootPathAliases` | 见 §3 注释与契约 §9 |
|
|
132
149
|
| 装到的版本低于 0.1.1 | 0.1.0 已作废 | 升级到 0.1.1+ |
|
|
133
150
|
|
|
134
|
-
## 9.
|
|
151
|
+
## 9. 新应用从零搭建(最小骨架)
|
|
152
|
+
|
|
153
|
+
> 本包**不生成脚手架**:只规定「一个子应用接入骨架层需要哪些动作」。工程模板、端口、产物路径、宿主注册
|
|
154
|
+
> 属宿主平台约定,**以平台既有子应用为范本照抄**,不要自创一套。
|
|
155
|
+
|
|
156
|
+
按顺序做,每步都有可验证的产出:
|
|
157
|
+
|
|
158
|
+
**① 工程与依赖**
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
pnpm create vite <app-name> --template vue-ts # 或按宿主平台范本初始化
|
|
162
|
+
cd <app-name>
|
|
163
|
+
pnpm add @manohub/app-kit
|
|
164
|
+
pnpm add vue vue-router pinia @tanstack/vue-query i18next i18next-vue i18next-browser-languagedetector
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
- **不要**单独安装 `@farris/ui-vue` / `@manohub/icon`(前者被骨架层收敛,后者由骨架层依赖带入)。
|
|
168
|
+
- 上面这批 peer 必须是**唯一实例**(monorepo 里不要出现第二份 vue/farris,见 §6)。
|
|
169
|
+
- 需要 JSX 页面时加 `@vitejs/plugin-vue-jsx`;`tsconfig` 用 `moduleResolution: "bundler"`(§6)。
|
|
170
|
+
|
|
171
|
+
**② 三行样式**(顺序即契约,§2)
|
|
172
|
+
|
|
173
|
+
```css
|
|
174
|
+
/* src/style.css */
|
|
175
|
+
@import "@manohub/app-kit/reset.css";
|
|
176
|
+
@import "@manohub/app-kit/styles.css";
|
|
177
|
+
@import "./app.css";
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**③ 入口走 `createSubApp`**(§3)—— 不要手写 `createApp` / `mount` / 微前端协议 / 首屏守卫 / pinia / 路由守卫 /
|
|
181
|
+
宿主语言监听;这些在工厂里已经有了。新应用的 `main.ts` 因此只有几十行。
|
|
182
|
+
|
|
183
|
+
**④ 第一个页面用模板 A**(`CONTRACT.md` §4.1):`AppShell` + `AppShell.Header` + `AppShell.Body mode="table"`
|
|
184
|
+
+ `AppShell.Footer`。写完先跑 §7 的验收清单,再往里填业务。
|
|
185
|
+
|
|
186
|
+
**⑤ 护栏接入**(§4):`appkit-guardrails.config.json` + `package.json` 挂 `lint` / `lint:changed`
|
|
187
|
+
(新应用**没有存量**,直接 `pending: false`,不要走挂起流程)。
|
|
188
|
+
|
|
189
|
+
**⑥ 技能包落盘**(§5):`pnpm exec appkit install`。
|
|
190
|
+
|
|
191
|
+
**⑦ 必须与宿主平台确认的项**(本包管不到,问清再动手):
|
|
192
|
+
|
|
193
|
+
| 项 | 为什么必须问 |
|
|
194
|
+
|---|---|
|
|
195
|
+
| 子应用产物路径与挂载方式(如 `/subapp/<group>/<app>/index.html`) | 宿主按约定路径加载,写错等于打不开 |
|
|
196
|
+
| 是否有 `index.html?xxx=1` 这类直开入口(iframe / 选择模式) | 有就必须登记 `rootPathAliases`,否则首屏守卫会清空 query(CONTRACT.md §9.2) |
|
|
197
|
+
| dev server 端口与代理规则 | 端口冲突与跨域问题都出在这里 |
|
|
198
|
+
| 宿主下发的语言键与初始路由约定 | 语言切换与首屏落点由宿主导 |
|
|
199
|
+
|
|
200
|
+
搭好之后,页面的日常开发走 `app-kit-dev`;若该应用还有一批历史页面要收口,走 `app-kit-migrate`。
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## 10. 升级与破坏性变更
|
|
135
205
|
|
|
136
206
|
- **0.x 单线**:所有消费方跟随同一条版本线,不做多版本共存。
|
|
137
207
|
- 注意语义化版本在 0.x 下的含义:`^0.1.0` **不覆盖** `0.2.0`,跨次版本升级要显式改依赖区间。
|
|
@@ -25,8 +25,13 @@
|
|
|
25
25
|
| 确认框 / 提示 / 报错怎么写 | §4.13 `messageBox` / `notify` / `loading` |
|
|
26
26
|
| 某个写法是不是违规 | §5 反例库 |
|
|
27
27
|
| 应用侧 CSS 能写什么、不能写什么 | §6 样式纪律 |
|
|
28
|
-
| 需要的能力包里没有怎么办 | §7
|
|
29
|
-
|
|
|
28
|
+
| 需要的能力包里没有怎么办 | §7 缺件处置流程(含 §7.1 当前缺件清单与替代口径) |
|
|
29
|
+
| 页签怎么写 | §4.14 `AppTabs` |
|
|
30
|
+
| 页面级筛选(字段 >3 / 跨区域 / 组合查询方案)怎么写 | §4.15 `AppFilter`(含 `appFilterSelect` / `appFilterInput` 两个编辑器工厂) |
|
|
31
|
+
| 树怎么写(受控展开、选中、节点附加内容) | §4.16 `AppTree` |
|
|
32
|
+
| 分页怎么写(服务端 / 客户端)、翻页事件叫什么 | §4.17 `AppPagination` / `useClientPagination` |
|
|
33
|
+
| 护栏怎么跑、提交前检查怎么挂 | §8 必跑命令与护栏(§8.3 提交前钩子、§8.4 包自身门禁) |
|
|
34
|
+
| **只迁一部分**(只换页面骨架、组件/样式下批次再收) | §8.1 规则级豁免 `waivedRules`;收口验收用 §8.2 的 `--strict` |
|
|
30
35
|
| 某些「看起来不对」的地方是不是 bug | §9 已知偏差(缩放、初始守卫与选择模式、行对象身份、自建件说明…) |
|
|
31
36
|
|
|
32
37
|
## 最容易踩的几条(先记住这些再动手)
|
|
@@ -11,9 +11,11 @@ description: 按 @manohub/app-kit 骨架层规范做日常页面与组件开发
|
|
|
11
11
|
## 一、开工前必做
|
|
12
12
|
|
|
13
13
|
1. 读 `node_modules/@manohub/app-kit/CONTRACT.md` 的相关章节(用 `../app-kit/references/contract-index.md` 按主题定位)。
|
|
14
|
-
**契约 >
|
|
14
|
+
**契约 > 组件类型声明里的 `@example`(`node_modules/@manohub/app-kit/dist/**/*.d.ts`,本包没有源码)> 消费仓
|
|
15
|
+
`AGENTS.md` > 其它文档**;冲突时按此优先级执行。
|
|
15
16
|
2. 确认组件是否存在、是否是自建件(自建件有额外约束,如 `AppTree` 的缩进与展开态、`AppNotice` 的语义 tone)。
|
|
16
|
-
3.
|
|
17
|
+
3. 组件不存在时先查 `CONTRACT.md` §7.1 缺件清单(那里给了替代口径),仍不够再走 §7 建件流程,
|
|
18
|
+
**不在应用侧自绘近似件**。
|
|
17
19
|
|
|
18
20
|
## 二、按意图取配方
|
|
19
21
|
|
|
@@ -23,7 +25,10 @@ description: 按 @manohub/app-kit 骨架层规范做日常页面与组件开发
|
|
|
23
25
|
| 表格、筛选、分页、多选 | `references/page-recipes.md`「表格」;四处操作位见 §4.5 |
|
|
24
26
|
| 表单、校验、字段文案 | `references/page-recipes.md`「表单」;§4.7 |
|
|
25
27
|
| 弹窗(含页脚按钮、确认框) | `references/page-recipes.md`「弹窗」;§4.10、§4.13 |
|
|
26
|
-
| 树、卡片单选、步骤条 | `references/page-recipes.md`;§4.9、§4.8 与 §9.6 |
|
|
28
|
+
| 树、卡片单选、步骤条 | `references/page-recipes.md`;§4.16、§4.9、§4.8 与 §9.6 |
|
|
29
|
+
| 页签 | `references/page-recipes.md`「页签 / 页面级筛选 / 分页」;§4.14 |
|
|
30
|
+
| 页面级筛选(字段 >3 / 跨区域) | `references/page-recipes.md` 同节;§4.15(编辑器只用 `appFilterSelect` / `appFilterInput`) |
|
|
31
|
+
| 分页(服务端 / 客户端) | `references/page-recipes.md` 同节;§4.17(事件是 `onPageChange` / `onPageSizeChange`,`page` 0 基) |
|
|
27
32
|
| 加载 / 空 / 错三态 | `references/page-recipes.md`「三态」;§4.6 |
|
|
28
33
|
| 样式怎么写、哪些禁止 | `references/style-rules.md`;§6 |
|
|
29
34
|
| 不确定某写法是否违规 | `references/style-rules.md`「反例」+ `CONTRACT.md` §5 |
|
|
@@ -38,28 +43,55 @@ description: 按 @manohub/app-kit 骨架层规范做日常页面与组件开发
|
|
|
38
43
|
4. **不重复骨架职责**:入口编排、pinia、路由、微前端协议、宿主语言监听都不在应用侧写。
|
|
39
44
|
5. **两处操作位、两级滚动、分页归属**先定清楚再动手(§4.4、§4.5、分页归属按承载表格的容器决定)。
|
|
40
45
|
|
|
41
|
-
##
|
|
46
|
+
## 四、本包不管的三件事(别在这里找写法)
|
|
47
|
+
|
|
48
|
+
1. **数据获取**:走消费仓既有方式(如 `@tanstack/vue-query` / 自建 api 层)。本包只**收结果** ——
|
|
49
|
+
把 `isLoading` / `error` / `data` 映射到组件的 `loading` / `error` / `rows`(§4.6),
|
|
50
|
+
不要为「加载中」自绘遮罩或骨架,也不要在这里引入新的请求库。
|
|
51
|
+
2. **文案与 i18n**:`createSubApp({ i18n })` 是 **i18next** 语义(`resources` + `fallbackLng`),文案用 `t()`;
|
|
52
|
+
应用已用 vue-i18n 时走 `extraPlugins` 注入,**两套不要混用**(`../app-kit/references/adoption.md` §3)。
|
|
53
|
+
组件内建的中文只是兜底,页面文案一律自己传。
|
|
54
|
+
3. **路由与权限**:路由表由应用维护并交给 `createSubApp({ routes })`;权限判断、菜单、面包屑属消费仓,
|
|
55
|
+
本包不做(页面级跳转用 `useRouter`,不要自己包一层路由工具)。
|
|
56
|
+
|
|
57
|
+
## 五、`.vue`(SFC)项目怎么用这些配方
|
|
58
|
+
|
|
59
|
+
配方以 TSX 书写(消费方主流形态)。SFC 项目按等价转写:
|
|
60
|
+
|
|
61
|
+
| TSX 配方 | SFC 写法 |
|
|
62
|
+
|---|---|
|
|
63
|
+
| `modelValue={x} onChange={(v) => (x = v)}` | `:model-value="x" @change="x = $event"`(或 `v-model`) |
|
|
64
|
+
| `v-slots={{ extra: () => <span/> }}` | `<template #extra><span/></template>` |
|
|
65
|
+
| `footer={() => <>…</>}` | `<template #footer>…</template>` |
|
|
66
|
+
| `columns={cols}` + `render: (row) => <span/>` | 列定义放 `setup` 的常量,`render` 返回 `h(...)` 或 JSX 片段 |
|
|
67
|
+
|
|
68
|
+
⚠️ **结构护栏只扫 `.ts` / `.tsx`,不扫 `.vue`**(已知缺口)。SFC 为主的仓,「护栏全绿」**不能**当作页面已合规的证据 ——
|
|
69
|
+
需另建抽查口径:人工按 §4.1 三种模板核对页面结构,并在代码评审里查 §5 反例。
|
|
70
|
+
|
|
71
|
+
## 六、收工前自检(必跑)
|
|
42
72
|
|
|
43
73
|
```bash
|
|
44
|
-
|
|
74
|
+
pnpm exec appkit lint --changed # 只查本次改动文件
|
|
45
75
|
pnpm exec vue-tsc --noEmit # 类型
|
|
46
76
|
```
|
|
47
77
|
|
|
48
78
|
- 违规条目自带 `file:line` + `correction`(唯一改法)+ `doc`(契约章节):照改,不要另想一套。
|
|
49
79
|
- 新增文件**必须归零**;若所在文件有存量豁免,只保证自己没新增违规。
|
|
80
|
+
新建的文件若还没 `git add`,`--changed` 也覆盖得到(护栏已按「已跟踪改动 + 未跟踪新增」求和),不必先提交。
|
|
50
81
|
- 页面骨架类违规(`structure/no-shell` 等)表示路由页没用 `AppShell`——这是最容易被漏掉的一类,动手前先看 §4.1。
|
|
51
82
|
|
|
52
|
-
##
|
|
83
|
+
## 七、失败处理
|
|
53
84
|
|
|
54
85
|
| 现象 | 处理 |
|
|
55
86
|
|---|---|
|
|
56
|
-
| 想要的组件/能力不存在 |
|
|
87
|
+
| 想要的组件/能力不存在 | 先查 `CONTRACT.md` §7.1 缺件清单(那里给了替代口径),仍不够再走 §7 建件流程(包维护侧建件,应用侧不自绘) |
|
|
88
|
+
| 表单里要日期 / 数字控件 | 本版没有 `AppDatePicker` / `AppNumber`;按 §7.1 用 `AppInput` 顶住并标注格式,需要真控件走建件 |
|
|
57
89
|
| 组件渲染了但样式不对 | 检查 `src/style.css` 三行导入与顺序(§1);不要在页面里补视觉样式 |
|
|
58
90
|
| 视觉想「微调一下」 | 属于违反样式纪律;用语义 prop(`tone` / `shape` / `size`)或换件,必要时提为骨架层待建件 |
|
|
59
91
|
| provide/inject 失效、服务拿不到上下文 | 疑似双实例,检查依赖树与单例收敛(`../app-kit/references/adoption.md`) |
|
|
60
92
|
| 护栏报「前缀未登记」 | 应用类名前缀应在 `appkit-guardrails.config.json` 登记,而不是改类名绕过 |
|
|
61
93
|
|
|
62
|
-
##
|
|
94
|
+
## 八、参考
|
|
63
95
|
|
|
64
96
|
- `../app-kit/references/contract-index.md`:按主题定位契约章节(含 §4 各组件契约与 §9 已知偏差)
|
|
65
97
|
- `references/page-recipes.md`:页面模板与高频场景配方
|
|
@@ -15,7 +15,9 @@
|
|
|
15
15
|
<AppTable framed rows={rows} columns={cols} rowKey="id" loading={loading} error={error} />
|
|
16
16
|
</AppShell.Body>
|
|
17
17
|
<AppShell.Footer>
|
|
18
|
-
<AppPagination page={page} pageSize={size} total={total}
|
|
18
|
+
<AppPagination page={page} pageSize={size} total={total}
|
|
19
|
+
onPageChange={(p) => (page = p)}
|
|
20
|
+
onPageSizeChange={(s) => { size = s; page = 0 }} />
|
|
19
21
|
</AppShell.Footer>
|
|
20
22
|
</AppShell>
|
|
21
23
|
```
|
|
@@ -37,7 +39,9 @@
|
|
|
37
39
|
<AppButton tone="secondary" onClick={refresh}>刷新</AppButton>
|
|
38
40
|
</>}>
|
|
39
41
|
<AppTable framed rows={rows} columns={cols} rowKey="id" />
|
|
40
|
-
<AppPanel.Footer
|
|
42
|
+
<AppPanel.Footer>
|
|
43
|
+
<AppPagination page={page} pageSize={size} total={total} onPageChange={(p) => (page = p)} />
|
|
44
|
+
</AppPanel.Footer>
|
|
41
45
|
</AppPanel>
|
|
42
46
|
</AppShell.Split>
|
|
43
47
|
</AppShell.Body>
|
|
@@ -182,9 +186,10 @@ notify.error('保存失败:' + msg, { timeout: 6000 })
|
|
|
182
186
|
## 六、树 / 卡片单选 / 步骤条
|
|
183
187
|
|
|
184
188
|
```tsx
|
|
185
|
-
// 树:受控展开,数据刷新不丢展开态(§9)
|
|
186
|
-
<AppTree nodes={nodes}
|
|
187
|
-
|
|
189
|
+
// 树:受控展开,数据刷新不丢展开态(§4.16、§9.6)
|
|
190
|
+
<AppTree nodes={nodes} rowKey="id" labelKey="name"
|
|
191
|
+
expandedKeys={expandedKeys} onExpandChange={(keys) => (expandedKeys = keys)}
|
|
192
|
+
selected={selectedId} onSelect={(node) => (selectedId = node.id)} />
|
|
188
193
|
|
|
189
194
|
// 卡片单选:选项内容长时用卡片,不要用下拉(§4.9)
|
|
190
195
|
<AppRadioCard modelValue={form.type}
|
|
@@ -238,3 +243,46 @@ notify.error('保存失败:' + msg, { timeout: 6000 })
|
|
|
238
243
|
| 表单内分组 | `AppForm.Section`(与 `AppSection` 同一件) |
|
|
239
244
|
|
|
240
245
|
拿 `AppPanel` 当「带标题的卡片」会把 48px 区域头与滚动契约带进不需要的地方(§5、§4.11)。
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## 九、页签 / 页面级筛选 / 分页(§4.14、§4.15、§4.17)
|
|
250
|
+
|
|
251
|
+
```tsx
|
|
252
|
+
// 页签:items 的 key 同时是内容插槽名;点击只上报,须回写 modelValue(§4.14)
|
|
253
|
+
<AppTabs modelValue={activeTab}
|
|
254
|
+
items={[{ key: 'overview', label: '概览' }, { key: 'tools', label: '工具' }]}
|
|
255
|
+
v-slots={{ overview: () => <Overview />, tools: () => <Tools /> }}
|
|
256
|
+
onChange={(key) => (activeTab = key)} />
|
|
257
|
+
|
|
258
|
+
// 页面级筛选(>3 字段 / 跨区域 / 组合查询方案)—— 位置只此一处:AppShell.Filter(§4.5、§4.15)
|
|
259
|
+
const fields: AppFilterField[] = [
|
|
260
|
+
{ id: 'field-repo', code: 'repoId', name: '所属仓库', editor: appFilterSelect(repoOptions) },
|
|
261
|
+
{ id: 'field-state', code: 'state', name: '状态', editor: appFilterSelect(stateOptions) },
|
|
262
|
+
{ id: 'field-owner', code: 'owner', name: '负责人', editor: appFilterInput('输入负责人') },
|
|
263
|
+
]
|
|
264
|
+
|
|
265
|
+
<AppShell.Filter>
|
|
266
|
+
<AppFilter fields={fields} defaults={{ 'field-state': 'all' }}
|
|
267
|
+
searchFields="name" searchPlaceholder="搜索名称"
|
|
268
|
+
onChange={(values) => applyFilter(values)}
|
|
269
|
+
onQuery={(values) => applyFilter({ ...values, force: true })} />
|
|
270
|
+
</AppShell.Filter>
|
|
271
|
+
|
|
272
|
+
// 服务端分页:页面持有 page / pageSize,事件是 onPageChange / onPageSizeChange(没有 onChange)
|
|
273
|
+
<AppPagination page={page} pageSize={size} total={total}
|
|
274
|
+
onPageChange={(p) => (page = p)}
|
|
275
|
+
onPageSizeChange={(s) => { size = s; page = 0 }} />
|
|
276
|
+
|
|
277
|
+
// 客户端分页:整批数据在前端时用它,别自己写 slice + 越界处理(§4.17)
|
|
278
|
+
const list = useClientPagination(() => filteredRows.value)
|
|
279
|
+
<AppTable framed rows={list.pageRows} columns={cols} rowKey="id" />
|
|
280
|
+
<AppPagination page={list.page} pageSize={list.pageSize} total={list.total}
|
|
281
|
+
pageSizeOptions={list.pageSizeOptions}
|
|
282
|
+
onPageChange={list.setPage} onPageSizeChange={list.setPageSize} />
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
- 筛选字段的编辑器**只能用两个工厂**(`appFilterSelect` / `appFilterInput`):底层字段配置、`all` 哨兵、payload 形态归一、
|
|
286
|
+
默认值注入时序、就绪轮询都在组件内,应用侧写不出来也不必写。
|
|
287
|
+
- `fields[].id` 是字段标识(`defaults` 按它索引),`fields[].code` 是业务条件名(事件值与后端参数按它走),别混。
|
|
288
|
+
- `AppPagination` 的 `page` 是 **0 基**;`onChange` 不是它的 prop。
|
|
@@ -56,8 +56,8 @@
|
|
|
56
56
|
## 五、自检
|
|
57
57
|
|
|
58
58
|
```bash
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
pnpm exec appkit lint:style # 只查样式
|
|
60
|
+
pnpm exec appkit lint --changed # 三条护栏查改动文件
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
每条违规都带 `file:line` + `correction`(唯一改法)+ `doc`(契约章节)—— 照 `correction` 改,不要另想一套。
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: app-kit-migrate
|
|
3
3
|
version: 1.0.0
|
|
4
|
-
description:
|
|
4
|
+
description: 把存量子应用改造为使用 @manohub/app-kit 骨架层(含清理直连底层组件库与底层风格 prop 的写法):接入护栏产违规基线、划定范围、逐文件替换、基线归零、验收与登记;也支持只迁一部分(典型是「只迁页面骨架 / Shell-only」,其余登记规则级豁免、分批收口)。触发条件:用户要求迁移/改造/接入子应用、要求处理护栏违规或降低违规基线、要求先只迁页面骨架或分阶段迁移、或代码里出现直连 farris / 底层风格 prop 需要清理时使用。
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# app-kit-migrate:存量应用改造
|
|
@@ -14,26 +14,40 @@ description: 把仍在直连底层组件库的存量子应用改造为使用 @ma
|
|
|
14
14
|
1. 确认是否已接入:`package.json` 里有 `@manohub/app-kit`,且应用包根有 `appkit-guardrails.config.json`。
|
|
15
15
|
未接入 → 先按 `../app-kit/references/adoption.md` 完成接入(安装、样式三行、入口、护栏配置),再回来。
|
|
16
16
|
2. 读应用自己的 `AGENTS.md` 与结构分层(`views/`、`components/`、样式文件分布),确认业务边界。
|
|
17
|
-
3.
|
|
17
|
+
3. **判定存量源**(决定映射表怎么用):
|
|
18
|
+
- 页面直连**底层组件库**(`@farris/ui-vue` / `.fv-*` 内部类 / `columnTemplate` 这类底层 prop)——
|
|
19
|
+
这是映射表的主源,按 `references/migration-map.md` 逐条替换。
|
|
20
|
+
- 页面用的是**其它 UI 库或完全自绘**(Element Plus / antd / 自研组件)—— 映射表里查不到对应项时**不要硬套**:
|
|
21
|
+
先按 `CONTRACT.md` §4 的三种模板把页面骨架换成 `AppShell` / `AppPanel`(这一步与源无关,且能一次消掉大部分
|
|
22
|
+
`structure/*`),再把交互件逐个换成 `App*` 件;每个位置在骨架层里归谁,查契约对应章节,查不到走 §7 建件。
|
|
23
|
+
4. 记录改造前基线:**类型检查、构建产物大小**(后续验收要与它对比)。
|
|
18
24
|
|
|
19
25
|
## 阶段 1 · 接入护栏并产出违规基线
|
|
20
26
|
|
|
21
27
|
以「只报告、不拦断」的方式取得一份**可比的数字**:
|
|
22
28
|
|
|
23
29
|
```bash
|
|
24
|
-
|
|
30
|
+
pnpm exec appkit lint
|
|
25
31
|
```
|
|
26
32
|
|
|
27
33
|
- 逐条规则记录违规数(style / component / structure 各自分规则),写入应用自己的基线文档
|
|
28
34
|
(放在应用包根,供后续「只减不增」比对)。
|
|
29
|
-
- 同步在 `appkit-guardrails.config.json` 里登记:应用目录、类名前缀、豁免注册表、`contractDoc
|
|
30
|
-
|
|
35
|
+
- 同步在 `appkit-guardrails.config.json` 里登记:应用目录、类名前缀、豁免注册表、`contractDoc`。
|
|
36
|
+
- **选口径**(两个机制都只是「暂不计入退出码」,都会照常报告):
|
|
37
|
+
- **全量迁移**:存量未清完前 `pending: true`,清完置 `false`。
|
|
38
|
+
- **只迁一部分**(典型是「只迁骨架 / Shell-only」):`pending: false` + `waivedRules` 登记本批不做的规则
|
|
39
|
+
(如 `api/*`、`style/*`),**已迁到的那一层即刻纳入门禁**(口径见 `CONTRACT.md` §8.1、
|
|
40
|
+
路径细则见 `references/migration-playbook.md`「九、变体路径:只迁骨架」)。
|
|
41
|
+
每条豁免必须写 `reason`,配置校验会拦没理由的豁免。
|
|
31
42
|
- 基线文档结构参见 `references/migration-playbook.md`「基线登记」。
|
|
32
43
|
|
|
33
44
|
## 阶段 2 · 划定范围与顺序
|
|
34
45
|
|
|
35
46
|
- 按**文件**而不是按规则推进:一个文件内的所有违规一次改完,避免反复进同一文件。
|
|
36
47
|
- 推荐顺序:入口与全局(`main.ts`、`style.css`、`app.css`)→ 页面骨架(路由页的 `AppShell`)→ 组件(弹窗、表格、表单)→ 演示/边缘页。
|
|
48
|
+
- **若本批只迁骨架**:只做上面第 2 步(第 1 步仅取样式三行与入口),组件与样式停手,
|
|
49
|
+
按 `references/migration-playbook.md`「九、变体路径:只迁骨架」的三条硬前置与里程碑 A 验收走 ——
|
|
50
|
+
其中「接样式三行」「去掉 `100vh`」「拆旧页头/面板头」缺一条就会出现「迁完更丑」。
|
|
37
51
|
- 每个文件开改前先查 `references/migration-map.md`,按表替换;表里没有的项,先查
|
|
38
52
|
`node_modules/@manohub/app-kit/CONTRACT.md` 对应章节,再动手。
|
|
39
53
|
|
|
@@ -42,7 +56,7 @@ node node_modules/@manohub/app-kit/lint/run-all.mjs
|
|
|
42
56
|
单文件循环(每个文件走一遍,不要攒着一起跑):
|
|
43
57
|
|
|
44
58
|
```bash
|
|
45
|
-
|
|
59
|
+
pnpm exec appkit lint --changed # 本文件违规清零
|
|
46
60
|
pnpm exec vue-tsc --noEmit # 未引入类型错误
|
|
47
61
|
```
|
|
48
62
|
|
|
@@ -61,8 +75,13 @@ pnpm exec vue-tsc --noEmit # 未引入类
|
|
|
61
75
|
| 类型 | `pnpm exec vue-tsc --noEmit` 0 错 |
|
|
62
76
|
| 构建 | `pnpm build` 成功;产物大小与阶段 0 记录值量级一致(差异要能解释) |
|
|
63
77
|
|
|
64
|
-
|
|
65
|
-
|
|
78
|
+
- **本批只迁了一部分时,用分层口径**(`CONTRACT.md` §8.1、§8.2):
|
|
79
|
+
① `run-all.mjs` 退出码 0 且已迁到的规则**没有**豁免(如 Shell-only 的 `structure/*`);
|
|
80
|
+
② 跑一次 `run-all.mjs --strict` 记录剩余违规总数 —— 那是下一批次的起点,写进应用文档;
|
|
81
|
+
③ 撤销豁免的顺序 = 收口顺序(撤一条、跑一次、能归零再撤下一条)。
|
|
82
|
+
- 报告里出现「以下豁免当前 0 条命中,可以撤销了」就是在提醒撤销。
|
|
83
|
+
- 若某规则无法在当前骨架层能力下归零,**先查 `CONTRACT.md` §7 缺件处置流程**,
|
|
84
|
+
不要私自留下违规或放宽护栏。
|
|
66
85
|
|
|
67
86
|
## 阶段 5 · 验收(缺一不可)
|
|
68
87
|
|
|
@@ -71,14 +90,14 @@ pnpm exec vue-tsc --noEmit # 未引入类
|
|
|
71
90
|
`createSubApp` 的 `rootPathAliases` 里登记,否则首屏守卫会清空 query(见 `CONTRACT.md` §9.2)。
|
|
72
91
|
3. 已知缺口要如实判断是否属于本次范围,不要误判为「漏改」:
|
|
73
92
|
- 结构护栏只扫 `.ts` / `.tsx`,不扫 `.vue`;未纳入骨架的 `.vue` 页面不会报 `structure/no-shell`。
|
|
74
|
-
- 骨架层尚未提供的件(缺件清单见 `CONTRACT.md` §7
|
|
93
|
+
- 骨架层尚未提供的件(缺件清单见 `CONTRACT.md` §7.1)只能按该表的替代口径顶住,不得自绘。
|
|
75
94
|
4. 结论记录到应用文档:改了什么、验收证据、遗留项。
|
|
76
95
|
|
|
77
96
|
## 阶段 6 · 收尾登记
|
|
78
97
|
|
|
79
98
|
- 基线文档更新为「迁移后:0」并写明日期;豁免登记表清空(或保留设计还原类豁免并注明节点)。
|
|
80
99
|
- `appkit-guardrails.config.json` 的挂起状态置为不挂起(纳入门禁)。
|
|
81
|
-
- 建议启用提交前钩子(包内提供样本),见 `CONTRACT.md` §8.
|
|
100
|
+
- 建议启用提交前钩子(包内提供样本),见 `CONTRACT.md` §8.3。
|
|
82
101
|
- 在应用 `AGENTS.md` 里补充「本应用已接入骨架层」与本次改造的关键结论。
|
|
83
102
|
|
|
84
103
|
## 失败处理
|
|
@@ -94,6 +113,6 @@ pnpm exec vue-tsc --noEmit # 未引入类
|
|
|
94
113
|
## 参考
|
|
95
114
|
|
|
96
115
|
- `references/migration-map.md`:替换映射表(旧写法 → 骨架层写法 → 注意事项),按类目查
|
|
97
|
-
- `references/migration-playbook.md
|
|
116
|
+
- `references/migration-playbook.md`:阶段细则、基线登记格式、归零口径、验收清单、**「只迁骨架」变体路径(第九节)**
|
|
98
117
|
- `../app-kit/references/adoption.md`:接入 SOP
|
|
99
118
|
- `node_modules/@manohub/app-kit/CONTRACT.md`:规范唯一事实源
|