@manohub/app-kit
v0.4.3
Published
子应用统一骨架层:入口编排(createSubApp)、布局契约(AppShell)、页面组件、原子件、服务、样式底座。farris 被收敛在本包内部,对外只暴露标准 API。
Readme
@manohub/app-kit
子应用统一骨架层(预编译产物分发,消费方按版本号安装):入口编排、布局契约(AppShell/AppPanel)、页面组件、原子件、服务、样式底座。
底层组件库(farris)被收敛在本包内部 —— 消费方不得安装或直连它。
- 接入方必读:CONTRACT.md —— 页面结构契约、组件用法与词表、样式纪律、反例库、护栏用法、已知偏差。 写页面代码前先读它;它随包分发,冲突时以它为准。
- 接入 SOP(安装 → 样式 → 入口 → 护栏 → 验收 → 故障对照 → 新应用从零搭建):
skills/app-kit/references/adoption.md,随包分发。 - 改本包时才看:
AGENTS.md(包内实现踩坑与硬性要求,不随包分发) - 入口:
@manohub/app-kit/entry→createSubApp - 组件/服务:
@manohub/app-kit→AppShell/AppPanel/AppTree/AppNav/AppTable/AppButton/notify… - 样式:
@manohub/app-kit/reset.css+@manohub/app-kit/styles.css(应用侧style.css固定三行,见下) - 命令入口:
appkit(package.json的bin,在应用包根执行)pnpm exec appkit lint [--changed|--strict|--json]—— 三条护栏;单条排查用appkit lint:style/lint:component/lint:structurepnpm exec appkit install [--also-claude|--dry-run]—— 落 AI 技能到本工程- npm 消费方把
pnpm exec换成npx;scripts 里可直接写appkit lint(.bin在 PATH 里) - 等价写法(老脚本/钩子可用):
node node_modules/@manohub/app-kit/lint/run-all.mjs、node node_modules/@manohub/app-kit/skills/install.mjs - 各护栏脚本仍单独可跑(用法见 CONTRACT.md §8)
新项目接入(快速开始)
下面是「从零接一个子应用」的最小动作序列,完整版与故障对照见随包分发的
skills/app-kit/references/adoption.md; 每一条契约条款以 CONTRACT.md 为准。
1. 安装
pnpm add @manohub/app-kit
# 自备 peer(必须是工程内唯一实例)
pnpm add vue vue-router pinia @tanstack/vue-query vue-i18n不要再单独安装
@farris/ui-vue(被骨架层收敛)或@manohub/icon(由骨架层依赖带入)。vue-i18n即使不用也必须装:createSubApp所在模块会静态引入它,漏装时vite build直接失败 (Rollup failed to resolve import "vue-i18n")—— 应用侧不传i18n选项、不写useI18n()也一样要装。应用侧禁止
import '@farris/ui-vue'(护栏会拦),组件一律从@manohub/app-kit取。本包发布在 npm 官方仓(公开),默认 registry 直接可装。工程若把默认 registry 指到了内网镜像, 需显式声明作用域(凭据不入库):
# .npmrc @manohub:registry=https://registry.npmjs.org/工程配置两项:
tsconfig用moduleResolution: "bundler"(包的子路径导出靠exports),types含vite/client;需要 JSX 页面时加@vitejs/plugin-vue-jsx。出现「同名类型互不兼容 / provide 取不到」这类双实例症状时,按 adoption.md §6 收敛单例 (
resolve.dedupe+ tsconfigpaths)。
2. 样式:固定三行,顺序即契约
/* src/style.css */
@import "@manohub/app-kit/reset.css";
@import "@manohub/app-kit/styles.css";
@import "./app.css";styles.css 内部已按 farris CSS → 令牌 → 桥接 → 组件样式汇总,不要自行打乱顺序或改写内部导入。
3. 入口:统一走 createSubApp
// src/main.ts
import { createSubApp } from '@manohub/app-kit/entry'
import App from './App.vue'
import { routes } from './router'
import './style.css'
export const { mount, unmount } = createSubApp({
rootComponent: App,
routes,
// i18n(vue-i18n):实例由骨架层唯一创建并注册,这里只给词条;详见 CONTRACT.md §10
// i18n: { messages: { en, zh } },
// 以 `index.html?xxx=1` 直开的入口(iframe / 选择模式)必须登记,否则首屏守卫会清空 query
// rootPathAliases: ['/index.html'],
// 宿主不支持深路径 fallback 时改 hash;需要自定义 base 时传 RouterHistory 实例
// history: 'hash',
})createSubApp 已统一负责 .app-container 包裹、pinia、farris 插件、i18n 装配与宿主语言同步、VueQuery、路由、挂载、
首屏守卫、window.mount/unmount 与 microApp.mount/unmount 协议、非微前端环境自动挂载 ——
应用侧不要再手写这些。全部选项见 adoption.md §3 或 CONTRACT.md §1,i18n 专项见 CONTRACT.md §10。
4. 第一个页面用模板 A
import { AppShell, AppSearchBox, AppTable, AppPagination } from '@manohub/app-kit'
<AppShell>
<AppShell.Header title="技能分类" toolbar={<AppSearchBox … />} />
<AppShell.Body mode="plain">
<AppTable framed rows={rows} columns={cols} rowKey="id" />
</AppShell.Body>
<AppShell.Footer>
<AppPagination page={page} pageSize={size} total={total} … />
</AppShell.Footer>
</AppShell>三种页面模板(列表 / 双栏 / 详情)、筛选与操作位归属、两级滚动契约见 CONTRACT.md §4; 写页面前务必过一遍 CONTRACT.md 的「四条铁律」与反例库。
5. 护栏接入(建议,机械判定规范合规)
// appkit-guardrails.config.json(应用包根)
{
"$schema": "./node_modules/@manohub/app-kit/lint/guardrails.config.schema.json",
"apps": [{ "dir": ".", "name": "<app-name>", "prefixes": ["<your-prefix>"], "pending": false }],
"srcGlobs": ["src/**/*.ts", "src/**/*.tsx"],
"styleGlobs": ["src/**/*.css"],
"contractDoc": "node_modules/@manohub/app-kit/CONTRACT.md"
}// package.json
{
"scripts": {
"lint": "appkit lint",
"lint:changed": "appkit lint --changed",
"lint:strict": "appkit lint --strict"
}
}新工程没有存量,直接 pending: false;存量应用先产基线再逐步归零(口径见 CONTRACT.md §8)。
6. 技能包落盘(AI 代理用)
pnpm exec appkit install # → .codebuddy/skills/(幂等,包升级后重跑即刷新)
pnpm exec appkit install --also-claude # 同时 → .claude/skills/7. 验收
| 项 | 命令 | 通过标准 |
|---|---|---|
| 类型 | pnpm exec vue-tsc --noEmit | 0 错(含 @manohub/app-kit/entry 等子路径可解析) |
| 构建 | pnpm build | 成功产出 |
| 护栏 | pnpm exec appkit lint | 无违规(或与基线一致;收口用 --strict) |
| 运行 | 启动后打开页面 | 骨架与组件样式正常、弹层落点正常 |
还有一批本包管不到、必须向宿主平台确认的项(子应用产物路径与挂载方式、是否有 index.html?xxx=1
直开入口、dev server 端口与代理、宿主下发的语言键与初始路由约定)—— 清单见 adoption.md §9.7。
分发形态
由源码分发改为产物分发:exports 指向 dist(含类型声明与 styles.css / reset.css)。
- 公开入口名与源码分发期逐字一致,消费方的引用语句与样式导入三行不需要改;
- 消费方不再需要为本包准备 TSX 编译配置或单例包的类型钉死;
lint/、CONTRACT.md仍原样随包分发(消费方的护栏与契约按包内路径引用它们);skills/是随包分发的 AI 技能包(见下);- 包内不存在
dist/时先执行构建再联调。
技能包(AI 代理用,随包分发)
随包分发三个技能:app-kit(入口编排)/ app-kit-migrate(存量应用改造)/ app-kit-dev(日常页面开发)。
在消费方工程根执行即可落到自己的技能目录(幂等,包升级后重跑即刷新):
pnpm exec appkit install # → .codebuddy/skills/
pnpm exec appkit install --also-claude # 同时 → .claude/skills/
pnpm exec appkit install --dry-run # 只预览装了之后,代理在做接入、迁移或页面开发时会命中本包规范与流程;技能职责边界与维护约定见 skills/README.md。
来源
本包由 gsp-cloud-ds/dip/ibp/aihub/aihub-frontend 的 app-kit 分支(导入 commit 315b60f)迁入,
只调整分发形态,未改包内实现。设计与实现依据(原仓 docs/plans/*)未随包迁入,留档在来源仓。
