README.md 自动同步生成。# 当前实现状态
2026-09-18 补充:Theme/UI 已按确认记录为试点闭环;HTTP 已在 g2rain-member-app 完成制品接入、真实验证和本地兼容组件清理,记录为试点通过。应用专属的 Client 注册表、Mock、IAM Key、Loading 组合和刷新协调仍保留在应用 runtime,公共请求内核由 @g2rain/http 提供。详细配置见 HTTP 包说明 (opens new window)。
截至 2026-09-19,npm workspace、四个包目录和 Playground 已建立。@g2rain/theme、@g2rain/ui、@g2rain/http 与 @g2rain/platform 均已具备首版实现。Platform 提供共享契约、Sub 生命周期 Kernel、Loading、Theme、微应用消息 Adapter 与权限 Provider;HTTP 包提供 Axios Client 工厂、语义化参数序列化、标准错误、Token 刷新单航班、DPoP 纯签名与资源释放。http 与 platform 互不依赖,由应用组合根装配。Token、登录行为、环境地址和权限数据均由应用注入。
接入分档:库内阶段一已通过,当前统一处于 g2rain-member-app 验证期。Theme/UI/HTTP 的局部试点结论不等同于 Appkit 可发布;必须完成 Member 独立运行、qiankun 集成及 Platform 主子协作的整体验证,才会发布任何 @g2rain/* 包。验证期仅使用 npm pack 制品,不发布到 npm Registry。详见 docs/integration/readiness.md 与 CHANGELOG.md (opens new window)。
# 1. 背景
当前 G2rain 的多个前端应用以独立 Git 仓库维护,包括:
g2rain-app-templateg2rain-cms-appg2rain-department-appg2rain-infra-appg2rain-manager-appg2rain-member-app
这些应用统一采用 Vue 3、Vite、Element Plus、TypeScript 和 qiankun。现有的 QueryForm、TableSort、RemoteSelect、HTTP、权限、错误处理、Loading 和微应用通信等代码,主要通过项目间复制传播。
复制方式会产生以下问题:
- 修复缺陷时需要同步修改多个仓库。
- 相同组件逐渐产生不可控的实现差异。
- 新应用模板持续复制旧版本代码。
- 主题、交互规范和基础能力难以统一升级。
- 无法明确表达公共能力的兼容范围和版本关系。
本方案将公共能力抽取为独立 npm 包,通过语义化版本进行发布和升级,同时保留各应用独立开发、构建和部署的模式。
# 2. 目标与非目标
# 2.1 目标
- 公共组件和基础能力只有一个事实来源。
- 各应用通过 npm 依赖选择升级时间,不强制同步发布。
- 支持应用独立运行和 qiankun 集成运行。
- 支持统一亮色、暗色和客户品牌主题。
- 避免公共包依赖具体应用的 Store、API、路由和目录别名。
- 新建应用默认使用公共包,不再复制公共实现。
# 2.2 非目标
- 不把
D:\github下的所有独立仓库合并为一个 Monorepo。 - 不在第一阶段一次性迁移所有公共代码。
- 不把业务页面或特定领域 API 放入公共组件包。
- 不要求所有应用在同一时间升级公共包版本。
# 3. 总体方案
新建独立仓库 g2rain-appkit。仓库内部使用 npm workspaces 管理多个可独立发布的包:
g2rain-appkit/
├─ package.json
├─ package-lock.json
├─ README.md
├─ packages/
│ ├─ theme/
│ ├─ ui/
│ ├─ http/
│ └─ platform/
└─ examples/
└─ playground/
包之间采用单向依赖;http 与 platform 并行,不形成包级硬依赖:
@g2rain/theme
↑
@g2rain/ui
↑
业务应用 / g2rain-app-template
@g2rain/http ←── 业务应用 ──→ @g2rain/platform
(主题 CSS 由应用显式引入 theme)
建议的包职责如下:
| 包 | 职责 | 不应包含 |
|---|---|---|
@g2rain/theme | 设计变量、亮暗主题、Element Plus 变量映射、基础样式 | Vue、Pinia、业务 API、qiankun |
@g2rain/ui | 通用 Vue 组件和组合式函数 | 具体应用 Store、路由、业务接口 |
@g2rain/http | HTTP Client、参数序列化、错误模型、签名和可复用拦截器 | 应用环境读取、具体 Token Store、业务 Mock 数据 |
@g2rain/platform | 共享契约、Sub 生命周期、权限插件、Loading 协调、微应用通信、主题切换 | 业务页面、领域 API、Main Shell Store |
@g2rain/platform 是前端应用运行与主子协作 SDK:包根导出共享协议,/sub 提供框架无关生命周期,/main 提供协调端口;两侧尚待在 Main Shell 与 Member 的真实运行链路中联合验证。Vue、Pinia、Router、qiankun 和应用启动继续由 Main Shell 或业务应用拥有。Runtime 只作为内部 Kernel 概念,不另发布包,也不提供兼容入口。详见 docs/architecture/platform-framework.md。
# 4. 仓库与 npm workspace 配置
根目录 package.json:
{
"name": "g2rain-appkit",
"private": true,
"workspaces": [
"packages/*",
"examples/*"
],
"engines": {
"node": ">=22"
},
"scripts": {
"build": "npm run build --workspaces --if-present",
"typecheck": "npm run typecheck --workspaces --if-present",
"test": "npm run test --workspaces --if-present",
"pack:check": "tsx scripts/check-package-artifacts.ts"
}
}
根包设置为 private: true,防止误发布。packages 下各子包单独维护名称和版本。
# 5. @g2rain/theme 主题方案
# 5.1 包结构
packages/theme/
├─ package.json
└─ src/
├─ styles.css
├─ tokens.css
├─ element-plus.css
├─ base.css
└─ themes/
├─ light.css
└─ dark.css
# 5.2 设计变量
主题变量使用 G2rain 自己的语义命名,不让业务组件直接依赖 Element Plus 的变量名称:
:root {
--g2-color-primary: #409eff;
--g2-color-success: #67c23a;
--g2-color-warning: #e6a23c;
--g2-color-danger: #f56c6c;
--g2-text-primary: #303133;
--g2-text-regular: #606266;
--g2-bg-page: #f5f7fa;
--g2-bg-container: #ffffff;
--g2-border-color: #dcdfe6;
--g2-font-size-base: 14px;
--g2-border-radius-base: 4px;
--g2-space-sm: 8px;
--g2-space-md: 16px;
--g2-space-lg: 24px;
}
变量应优先表达用途,例如“页面背景”和“主要文字”,避免只使用 blue-500 之类的具体颜色名称。这样切换暗色或客户品牌主题时,组件代码无需变化。
# 5.3 Element Plus 映射
:root {
--el-color-primary: var(--g2-color-primary);
--el-color-success: var(--g2-color-success);
--el-color-warning: var(--g2-color-warning);
--el-color-danger: var(--g2-color-danger);
--el-text-color-primary: var(--g2-text-primary);
--el-text-color-regular: var(--g2-text-regular);
--el-border-color: var(--g2-border-color);
--el-border-radius-base: var(--g2-border-radius-base);
--el-font-size-base: var(--g2-font-size-base);
}
G2rain 变量是平台主题契约,Element Plus 变量只是适配层。后续升级或替换 UI 框架时,不需要修改全部业务样式。
# 5.4 亮色与暗色主题
:root,
:root[data-g2-theme='light'] {
color-scheme: light;
--g2-bg-page: #f5f7fa;
--g2-bg-container: #ffffff;
--g2-text-primary: #303133;
}
:root[data-g2-theme='dark'] {
color-scheme: dark;
--g2-bg-page: #141414;
--g2-bg-container: #1d1e1f;
--g2-text-primary: #e5eaf3;
}
主题切换通过根节点属性完成,但修改 DOM 的能力属于 @g2rain/platform/theme,不放入 CSS-only 的主题包:
const theme = createThemeController()
theme.setTheme('dark')
const unsubscribe = theme.subscribe(current => console.log(current))
# 5.5 主题包发布配置
{
"name": "@g2rain/theme",
"version": "1.0.1",
"type": "module",
"files": [
"dist"
],
"exports": {
"./styles.css": "./dist/styles.css",
"./base.css": "./dist/base.css",
"./tokens.css": "./dist/tokens.css",
"./element-plus.css": "./dist/element-plus.css",
"./light.css": "./dist/themes/light.css",
"./dark.css": "./dist/themes/dark.css"
},
"sideEffects": [
"**/*.css"
]
}
默认入口同时加载 tokens、亮色、暗色、Element Plus 映射和基础样式。应用显式引入主题,公共 UI 包不应隐式修改全局样式:
import '@g2rain/theme/styles.css'
import '@g2rain/ui/style.css'
具体输出路径和构建规则见 docs/development/build-and-test-contract.md。
# 6. @g2rain/ui 组件方案
# 6.1 第一批组件
第一版建议迁移依赖较少、复用价值较高的组件:
QueryFormTableSortRemoteSelect基础组件ApiSelect
带组织、字典或状态语义的组件从 @g2rain/ui/platform 导入,不进入根入口:
DictSelectOrganSelectDictTextStatusSwitch
这三个组件已完成能力注入改造;各应用入口提供组织策略、字典查询和状态提交,User 等实体将沿用相同 Provider 契约逐步组件化。
各组件不能整目录选取单一 App 版本;规范来源、公开 Props、事件、Slots 和 Expose 以 docs/packages/component-migration-baseline.md 为准。
# 6.2 组件约束
公共组件不得导入以下应用内路径:
@/views/**
@platform/**
@runtime/**
@shared/**
需要的能力通过 Props、Slots、事件、Provider 或工厂参数传入。例如远程选择组件通过函数获取数据:
<script setup lang="ts">
import { DictSelect } from '@g2rain/ui/platform'
</script>
<DictSelect
usage-code="user_status"
:api-method="dictApi.list"
/>
平台级能力可以通过插件注入:
export interface G2rainUiOptions {
locale?: () => string
translate?: (key: string) => string
}
app.use(G2rainUi, {
locale: () => localeStore.locale,
translate: key => i18n.global.t(key),
})
# 6.3 包配置
{
"name": "@g2rain/ui",
"version": "1.0.1",
"type": "module",
"files": [
"dist"
],
"main": "./dist/index.js",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
},
"./style.css": "./dist/style.css"
},
"sideEffects": [
"*.css"
],
"peerDependencies": {
"@element-plus/icons-vue": "^2.3.0",
"@g2rain/theme": "^1.0.1",
"element-plus": "^2.13.0",
"vue": "^3.5.0"
},
"devDependencies": {
"@element-plus/icons-vue": "^2.3.0",
"@vitejs/plugin-vue": "^6.0.3",
"element-plus": "^2.13.0",
"typescript": "5.9.3",
"vite": "^7.3.0",
"vue": "^3.5.26",
"vue-tsc": "3.2.1"
}
}
# 6.4 组件导出
export * from './query-form'
export * from './table-sort'
export * from './remote-select'
对外只允许从稳定入口导入,不保证内部文件路径兼容。通用组件从包根导入,平台数据组件从 @g2rain/ui/platform 导入:
import {
QueryForm,
RemoteSelect,
SortableTable,
TableColumn,
} from '@g2rain/ui'
import { OrganSelect, DictText, StatusSwitch } from '@g2rain/ui/platform'
# 7. @g2rain/http 和 @g2rain/platform
# 7.1 HTTP 包
@g2rain/http 可包含:
- HTTP Client 类型和创建工厂。
- 参数序列化与请求体处理。
- DPoP 等通用签名能力。
- 通用错误类型和错误标准化。
- 可组合的基础拦截器。
应用专属内容不进入该包:
import.meta.env的直接读取。- 具体 AccessToken Store。
- 具体登录跳转行为。
- 资源 JSON 和业务 Mock 数据。
- 具体 API Endpoint。
推荐通过工厂参数装配:
const { client, dispose } = createHttpClient({
baseURL: runtimeConfig.apiBaseUrl,
authSessionProvider: () => accessTokenStore.session,
ensureAccessToken: options => accessTokenStore.ensure(options),
authErrorHandler: (reason, error) => authService.handleFailure(reason, error),
getLocale: () => localeStore.locale,
})
# 7.2 Platform 包
@g2rain/platform 当前包含:
- 包根共享契约:
RuntimeContext、RuntimeMessage、PlatformError。 /sub的createSubPlatform、Scope 与 Capability 生命周期。- 权限 Provider 和 Vue 插件(仅
./permission)。 - 全局 Loading 协调。
- 微应用事件类型和浏览器 Event Adapter。
- 主题 Controller。
包根和 Kernel 不导入 Vue。具体 Store、qiankun lifecycle 和独立启动仍由应用维护。/main 协调端口与标准 Preset 已在库内实现,尚待在 Main Shell 与 Member 的真实运行链路中验证。
HTTP 工厂、错误模型、刷新单航班、主题 Controller 和消息 Adapter 的精确签名见 docs/packages/http-runtime-contract.md。
# 8. qiankun 主题协作
主应用 g2rain-main-shell 是集成模式下的主题所有者:
- 主应用读取用户主题偏好。
- 主应用设置
document.documentElement.dataset.g2Theme。 - 主应用通过微应用消息机制广播主题变更。
- 子应用被 qiankun 加载时服从主应用主题。
- 子应用独立运行时自行读取和初始化主题。
- 子应用卸载时只清理自己的监听器,不删除主应用设置的根主题属性。
同一页面中的 CSS 自定义变量可以被微应用继承,适合当前 qiankun 架构。各子应用不得在集成模式下使用不同值覆盖 :root 主题变量。
建议增加统一消息:
export type ThemeChangedMessage = MicroAppMessage<
MicroAppEventType.THEME_CHANGED,
{ theme: 'light' | 'dark' }
>
消息沿用现有 MicroAppMessage.data 信封,不增加 payload 字段。
# 9. 发布策略
# 9.1 npm Registry
当前应用仓库使用 Apache-2.0 且 private: false,优先考虑发布到公开 npm Registry:
npm publish --workspace @g2rain/theme --access public
npm publish --workspace @g2rain/ui --access public
如果公共包暂时不能公开,可改用 GitHub Packages。私有 Registry 会要求开发者环境和 CI 配置读取 Token,应在确定有保密需求时采用。
# 9.2 版本规则
遵循语义化版本:
- Patch:兼容性缺陷修复,例如
0.1.1。 - Minor:兼容性新组件或新参数,例如
0.2.0。 - Major:不兼容 API 调整,例如
1.0.0到2.0.0。
在 1.0.0 稳定后,业务应用建议使用 ^ 范围:
{
"dependencies": {
"@g2rain/theme": "^1.0.1",
"@g2rain/ui": "^1.0.1"
}
}
公共包的 Breaking Change 必须包含迁移说明。
# 9.3 发布校验
正式发布前至少执行:
- TypeScript 类型检查。
- 单元测试。
- 生产构建。
npm pack检查压缩包文件清单。- 在 Playground 安装打包产物并构建。
- 验证一个真实子应用的独立模式和 qiankun 模式。
# 10. 迁移计划
# 阶段一:建立主题和基础 UI
- 初始化
g2rain-appkitnpm workspace。 - 创建
@g2rain/theme@0.1.0。 - 定义第一版设计变量和 Element Plus 映射。
- 迁移
QueryForm和TableSort。 - 迁移
RemoteSelect基础组件,移除应用内别名依赖。 - 使用
npm pack在一个试点应用中验证。
代码生成必须满足 docs/development/build-and-test-contract.md 的制品布局和完成条件。
推荐 g2rain-member-app 作为首个迁移试点。
# 阶段二:Member 整体验证
- 使用
npm pack制品在g2rain-member-app验证 Theme、UI、HTTP 与 Platform 的组合。 - 完成 Member 的独立运行、qiankun 挂载、卸载和重新挂载验证,并由 Main Shell 验证主子协作。
- 验证期间不发布任何
@g2rain/*包,也不要求其他业务 App 提前迁移。 - 仅在整体验证通过后,发布各包并再逐步迁移其他业务 App、模板和 CLI。
# 阶段三:发布与推广
- 整体验证通过后,按
theme → ui / http / platform的顺序发布 npm 包。 packages/platform已直接改名完成,不建立兼容包。- 逐个应用迁移;应用内部可以短期保留组合适配,但不得依赖已删除的旧工作包名。
- 修改
g2rain-app-template与g2rain-app-cli,让新项目默认使用已发布的公共包。
# 11. 兼容与回滚策略
- 每个应用独立决定公共包升级时间。
- 首次迁移尽量保持组件名称、Props 和事件不变。
- 迁移时可以临时保留原导出路径,由本地
index.ts转发到 npm 包。 - 出现问题时通过回退
package.json和 lockfile 中的版本进行恢复。 - 不使用
npm link作为正式验收方式,优先使用npm pack,使验证行为更接近真实发布包。 - 新旧实现并存期间,应明确唯一调用入口,避免同一应用同时加载两套全局插件。
兼容转发示例:
export {
QueryForm,
SortableTable,
TableColumn,
} from '@g2rain/ui'
# 12. 验收标准
分档门槛见 docs/integration/readiness.md。
库内阶段一(已完成)应满足:
- 四个包可以独立构建;含 JS 的包生成类型声明。
- npm 压缩包只包含必要的发布文件。
- 公共包源码不存在对具体应用目录别名的依赖。
- Playground 可组合验证 Theme / UI / Platform 主题能力。
试点与平台闭环(尚未完成)还应满足:
- 试点应用类型检查和生产构建通过。
- 试点应用独立运行与 qiankun 加载、卸载、重新加载正常。
- 亮色与暗色主题可以切换,Element Plus 与公共组件主题一致。
- 试点应用不再保留已迁移组件的源码副本。
- 新应用模板默认通过 npm 使用公共组件。
# 13. 关键决策
- 保留各 App 独立仓库,仅将公共包仓库内部组织为 Monorepo。
- 主题包位于依赖最底层,不依赖 Vue、Pinia 和 qiankun。
- 公共 UI 使用 G2rain 语义变量,不直接硬编码品牌颜色。
- 应用 Store、业务 API 和路由不进入公共 UI 包。
- 主应用管理集成模式主题,子应用兼容独立运行。
- 优先小范围迁移并发布,再逐步抽取 HTTP 和 Platform,避免一次性重构。