asai-vue-host
v0.2.58
Published
asai for you
Downloads
2,021
Readme
asai-vue-host — 应用宿主框架(核心)
概述
asai-vue-host 是 AsaiWeb CMS 的核心应用宿主框架,提供应用加载、模块管理、路由分发、WebSocket 通信和数据库响应的能力。它是整个前端架构的运行容器。
功能
- 🚀 应用启动:管理完整应用加载流程
- 📦 模块管理:动态加载和卸载功能模块
- 🧭 路由分发:基于 Hash 路由的页面分发
- 🔌 WebSocket 通信:WebSocket 连接管理与事件系统
- 💾 数据库响应:IndexedDB / 本地数据响应式提供
- 🎯 功能注入:通过
provide提供全局数据和方法 - ⏳ 加载状态管理:多种加载动画组件
- 🚨 错误处理:404 页面、加载错误页面
文件结构
asai-vue-host/
├── src/
│ └── components/
│ ├── index.ts # 插件安装入口(install 方法)
│ ├── asengine/
│ │ └── provide/
│ │ ├── providedb.ts # 数据库响应式数据 Provide
│ │ ├── providedbwork.ts # 数据库工作线程 Provide
│ │ ├── providefn.ts # 功能函数 Provide
│ │ └── providews.ts # WebSocket 数据 Provide
│ └── asui/
│ ├── app/
│ │ ├── AsaiWebItemIndex.vue # 应用入口页面
│ │ ├── AsaiWebItemDefault.vue # 默认页面
│ │ ├── AsaiWebModule.vue # 模块容器
│ │ ├── AsaiWebModuleDefault.vue # 默认模块
│ │ ├── AsaiWebModuleIndex.vue # 模块索引页
│ │ ├── AsaiWebServer.vue # 服务器页面
│ │ └── AsaiComponent.vue # 通用组件容器
│ ├── common/
│ │ ├── AsPageBusy.vue # 页面繁忙状态
│ │ ├── AsPageBusyGif.vue # GIF 加载动画
│ │ ├── AsReset.vue # 重置组件
│ │ ├── MenuShowFix.vue # 菜单显示修复
│ │ ├── RouterMap.vue # 路由映射组件
│ │ ├── AsPageBusy/
│ │ │ ├── AsLoadingA3d.vue # 3D 加载动画
│ │ │ └── AsLoadingCircle.vue# 圆形加载动画
│ │ └── _comps/
│ │ └── Asai404.vue # 404 页面
│ └── page/
│ ├── PageErr.vue # 错误页面
│ ├── PageLoadErr.vue # 加载错误
│ ├── PageLoadServer.vue # 服务器加载
│ ├── PageLoadUserToken.vue # 用户 Token 加载
│ ├── PageLoadUserTokenOnline.vue # 在线 Token 加载
│ └── PageLoadWs.vue # WebSocket 加载
└── README.md安装方式
import AsaiVueHost from 'asai-vue-host';
app.use(AsaiVueHost, {
loadts: (options) => { /* 加载 TypeScript 模块 */ },
loadvue: (options) => { /* 加载 Vue 组件 */ },
loadfn: (path) => { /* 加载函数 */ },
});Provide 系统
插件通过 Vue 的 provide/inject 机制注入以下全局功能:
| Provide Key | 说明 |
|-------------|------|
| $engineasai | 主引擎上下文 |
| providedb | 数据库响应式数据 |
| providews | WebSocket 数据 |
| providefn | 功能函数 |
| providedbwork | 数据库工作线程 |
核心组件
应用组件
| 组件 | 说明 |
|------|------|
| AsaiWebServer | 服务器连接管理 |
| AsaiWebModule | 模块容器,管理子页面 |
| AsaiWebModuleIndex | 模块首页索引 |
| AsaiWebModuleDefault | 默认模块视图 |
| AsaiWebItemIndex | 应用主入口页面 |
| AsaiWebItemDefault | 应用默认页面 |
| AsaiComponent | 动态组件渲染容器 |
公共组件
| 组件 | 说明 |
|------|------|
| AsPageBusy | 页面繁忙/加载中状态 |
| AsPageBusyGif | GIF 格式加载动画 |
| AsLoadingA3d | 3D 风格加载动画 |
| AsLoadingCircle | 圆形旋转加载动画 |
| AsReset | 数据重置组件 |
| MenuShowFix | 菜单显示修正 |
| RouterMap | Hash 路由映射 |
| Asai404 | 404 页面 |
页面组件
| 组件 | 说明 |
|------|------|
| PageErr | 通用错误页面 |
| PageLoadErr | 加载失败页面 |
| PageLoadServer | 服务器加载页面 |
| PageLoadUserToken | 用户认证 Token 加载 |
| PageLoadUserTokenOnline | 在线用户 Token 加载 |
| PageLoadWs | WebSocket 连接加载 |
技术细节
- 插件安装模式:通过 Vue 插件系统集成,使用
install(app, opt)模式 - 自动扫描加载:使用
import.meta.glob自动发现并注册组件 - 模块化注入:通过
$engineasai注入点集中管理 - 异步加载:组件使用动态导入,按需加载减少首屏体积
- 加载动画:提供 CSS3 动画和 GIF 动画两种方案
代码优化分析
已做优化
- ✅ 插件化架构:使用 Vue 插件
install(app, opt)模式,可组合安装 - ✅ 自动扫描加载:
import.meta.glob自动发现注册组件 - ✅ 模块化注入:不同功能使用独立 key(
$engineasai),避免命名冲突 - ✅ Provide/Inject 模式:全局数据解耦,组件按需注入
- ✅ 提供多种加载动画(CSS3 动画 + GIF),降级方案
可优化点
1. Provide 数据为简单 reactive 对象
// providedb.ts
export default reactive({
providedb: { data: {} }
});
// providews.ts
export default reactive({
providews: { data: { rooms: {}, wssys: {} } }
});问题:三个 provide 都使用 reactive 包裹但在对象中嵌套对象。Vue3 的 reactive 是深度的,嵌套对象的属性变更也会触发更新。但数据变更后,如果 inject 方直接替换内部对象(如 providedb.data = newData),可能会丢失响应性。
建议:使用 readonly 包装 inject 数据,或明确提供数据修改方法。
2. 组件扫描使用 eager: false(lazy 模式)
files: (import.meta as any).glob(['./asui/*/*.vue'])问题:lazy 模式(非 eager)意味着组件只在首次渲染时异步加载。对于核心宿主组件(如 AsaiWebModule、AsaiWebItemIndex),它们是首屏必需组件,懒加载可能导致白屏闪烁。
建议:对核心组件使用 eager 加载,次要组件使用 lazy。
3. PageLoadUserToken 等页面组件未定义Props
一些页面加载组件(如 PageLoadWs、PageLoadErr)没有明确的 Props 定义。建议添加 Props 接口,至少支持错误信息、重试函数等。
4. 错误页面没有重试机制
PageErr 和 PageLoadErr 只显示错误信息,没有"重试"按钮。建议添加 retry 属性和 @retry 事件。
5. "asany" 类型过多
整个插件的 TypeScript 大量使用 any 类型,失去类型检查的意义。建议:
- 定义核心类型接口(如
AsaiContext、ModuleConfig、AppRoute) - 将
$fn、$global、$model等全局对象的类型定义为接口
6. Index.ts 中的 opt.loadts 和 opt.loadvue 缺少类型定义
install(app, opt) 的 opt 参数没有 TypeScript 接口,调用方不知需传入哪些方法。建议:
interface HostPluginOptions {
loadts: (opts: { app: any; key: string; eager: boolean; files: Record<string, any> }) => void;
loadvue: (opts: { loadfn: any; app: any; eager: boolean; files: Record<string, any> }) => void;
loadfn: (path: string) => any;
}