bun + vite7 的结合,孕育的 Robot Admin 靓仔出道(五)

Robot Admin 应用架构详解

🏛️ 现代化 Vue 3 架构深度解析

深入理解模块化、基于插件的架构设计,掌握可扩展性和可维护性的核心原则

Robot Admin 是一个现代化的 Vue 3 应用程序,采用模块化、基于插件的架构设计,旨在实现可扩展性和可维护性。本文档提供了该应用程序架构的概述、不同组件之间的交互以及代码库中使用的设计模式。

Robot Admin 遵循分层架构模式,具有清晰的关注点分离。该应用程序基于 Vue 3 和 TypeScript 构建,使用 Vite 作为构建工具,Pinia 用于状态管理,Naive UI 作为组件库。

🎯 核心架构原则

架构围绕以下关键原则组织:

原则 说明 实现方式
组件驱动开发 UI 由可重用组件组成 全局/局部组件分离
基于插件的扩展性 通过插件添加功能 模块化插件系统
集中式状态管理 应用程序状态在 Pinia 存储中管理 按域分离的存储模块
基于权限的路由 路由根据用户权限动态加载 动态路由生成

🚀 应用程序启动过程

应用程序初始化过程通过 main.ts 中定义的分阶段方法精心编排。这确保了依赖项按正确顺序加载,并在挂载前正确初始化应用程序。

启动流程

启动过程遵循以下阶段:

scss 复制代码
// main.ts 启动流程
async function bootstrap() {
  // 1️⃣ 预初始化
  setupLoading();

  // 2️⃣ Vue 实例创建
  const app = createApp(App);
  const pinia = createPinia();
  pinia.use(piniaPluginPersistedstate);

  // 3️⃣ 插件初始化
  setupStore(app);
  setupNaiveUI(app);
  setupDynamicComponents(app);
  setupHighlight(app);
  setupMarkdown(app);
  setupDirectives(app);
  setupAnalytics(app);

  // 4️⃣ 路由就绪
  await router.isReady();

  // 5️⃣ 应用程序挂载
  app.mount("#app");
}

启动阶段详解:

  1. 预初始化 - 设置加载指示器和其他非 Vue 依赖项
  2. Vue 实例创建 - 创建 Vue 应用并初始化 Pinia
  3. 插件初始化 - 设置所有必需的插件
  4. 路由就绪 - 确保在挂载前路由就绪
  5. 应用程序挂载 - 将应用挂载到 DOM

🛣️ 路由系统

应用程序使用 Vue Router,具有复杂的路由系统,将公共路由与基于用户权限动态加载的路由分开。

公共路由

公共路由无需认证即可访问,包括登录和错误页面。它们在应用程序代码中静态定义。

javascript 复制代码
// publicRouter.ts
export const publicRoutes: RouteRecordRaw[] = [
  {
    path: "/login",
    name: "Login",
    component: () => import("@/views/login/index.vue"),
    meta: { requiresAuth: false },
  },
  {
    path: "/404",
    name: "NotFound",
    component: () => import("@/views/error-page/404.vue"),
  },
];

动态路由

动态路由根据用户权限加载,并在运行时构建。应用程序采用灵活的方法动态加载组件:

  1. 权限获取 - 根据用户权限从后端获取路由
  2. 组件解析 - 使用 Vite 的 import.meta.glob 动态解析组件
  3. 路由注册 - 将路由添加到路由实例
typescript 复制代码
// dynamicRouter.ts - 动态路由关键功能
const dynamicRoutes = {
  // 组件解析:基于路径名解析组件
  resolveComponent: (componentPath: string) => {
    const modules = import.meta.glob("@/views/**/*.vue");
    return modules[componentPath];
  },

  // 路径规范化:确保路径格式正确
  normalizePath: (path: string) => {
    return path.startsWith("/") ? path : `/${path}`;
  },

  // 错误处理:优雅处理缺失组件
  handleMissingComponent: (path: string) => {
    console.warn(`Component not found for path: ${path}`);
    return () => import("@/views/error-page/404.vue");
  },
};

动态路由提供的关键功能:

  • 组件解析 - 基于路径名解析组件
  • 路径规范化 - 确保路径格式正确
  • 错误处理 - 优雅处理缺失组件
  • 开发工具 - 在开发模式下提供有帮助的警告

🔐 权限控制

路由访问通过权限系统控制,检查用户认证和授权:

权限验证流程

  1. 导航守卫验证 - 验证用户认证
  2. 动态路由加载 - 如果已认证,根据用户权限加载动态路由
  3. 未授权重定向 - 未授权访问重定向到适当的错误页面
scss 复制代码
// permission.ts
router.beforeEach(async (to, from, next) => {
  const userStore = useUserStore();
  const permissionStore = usePermissionStore();

  // 🔍 路由守卫:防止未授权访问
  if (to.meta.requiresAuth && !userStore.isLoggedIn) {
    return next("/login");
  }

  // 📋 白名单:允许未经认证访问公共路由
  if (whiteList.includes(to.path)) {
    return next();
  }

  // ⚡ 动态路由初始化:根据用户权限加载路由
  if (userStore.isLoggedIn && !permissionStore.isRoutesLoaded) {
    await permissionStore.generateRoutes();
    return next({ ...to, replace: true });
  }

  // 🏷️ 标题管理:根据路由元数据设置页面标题
  document.title = to.meta.title || "Robot Admin";

  next();
});

权限系统实现:

  • 路由守卫 - 防止未授权访问
  • 白名单 - 允许未经认证访问公共路由
  • 动态路由初始化 - 根据用户权限加载路由
  • 标题管理 - 根据路由元数据设置页面标题

🗃️ 状态管理

应用程序使用 Pinia 进行状态管理,具有模块化存储结构。每个领域都有自己的存储,包含状态、获取器和操作。

用户存储

用户存储管理认证状态和用户信息:

ini 复制代码
// user/index.ts
export const useUserStore = defineStore("user", () => {
  // 🔐 认证:管理用户令牌和登录状态
  const token = ref<string>("");
  const userInfo = ref<UserInfo | null>(null);
  const isLoggedIn = computed(() => !!token.value);

  // 👤 用户信息:存储和检索用户详细信息
  const setUserInfo = (info: UserInfo) => {
    userInfo.value = info;
  };

  // 🚪 登录/注销操作:处理认证流程
  const login = async (credentials: LoginCredentials) => {
    try {
      const response = await authApi.login(credentials);
      token.value = response.token;
      userInfo.value = response.userInfo;

      // 持久化存储
      localStorage.setItem("token", response.token);

      return response;
    } catch (error) {
      throw error;
    }
  };

  const logout = () => {
    token.value = "";
    userInfo.value = null;
    localStorage.removeItem("token");
    router.push("/login");
  };

  return {
    token,
    userInfo,
    isLoggedIn,
    setUserInfo,
    login,
    logout,
  };
});

存储模式的关键特性:

  • 持久化 - 使用 pinia-plugin-persistedstate 持久化状态
  • 类型化状态 - TypeScript 确保类型安全
  • 基于操作的状态变更 - 状态变更封装在操作中
  • 跨存储交互 - 存储之间可以在需要时交互

🔌 插件架构

应用程序使用基于插件的架构,功能可以通过插件添加和配置。这种方法提供了多项好处:

插件系统优势

优势 说明
模块化 功能可以添加或移除,不影响其他部分
配置 插件可以在初始化时配置
依赖管理 插件可以以受控方式相互依赖
测试 插件可以独立测试

插件在应用程序启动时设置,包括:

scss 复制代码
// plugins/index.ts
export const setupPlugins = (app: App) => {
  // UI 框架:NaiveUI 设置
  setupNaiveUI(app);

  // 状态管理:Pinia 存储设置
  setupStore(app);

  // 动态组件:懒加载组件注册
  setupDynamicComponents(app);

  // 实用插件:分析、高亮、Markdown 支持等
  setupAnalytics(app);
  setupHighlight(app);
  setupMarkdown(app);
};

🧩 组件结构

应用程序将组件组织成逻辑层次结构:

组件组织

bash 复制代码
components/
├── global/          # 全局组件:在整个应用程序中可重用
├── local/           # 局部组件:特定于某些视图或功能
├── layout/          # 布局组件:定义应用程序结构
├── ui/              # UI 组件:实现设计系统
└── icons/           # 图标组件:应用程序中使用的 SVG 图标

组件分类说明:

  • 全局组件 - 在整个应用程序中可重用
  • 局部组件 - 特定于某些视图或功能
  • 布局组件 - 定义应用程序结构
  • UI 组件 - 实现设计系统
  • 图标组件 - 应用程序中使用的 SVG 图标

🌐 HTTP 请求层

应用程序使用 Axios 进行 HTTP 请求,采用请求拦截器模式:

javascript 复制代码
// axios/request.ts - HTTP 请求配置
const request = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL,
  timeout: 10000,
});

// 请求拦截器:添加认证头,处理常见参数
request.interceptors.request.use(
  (config) => {
    const userStore = useUserStore();
    if (userStore.token) {
      config.headers.Authorization = `Bearer ${userStore.token}`;
    }
    return config;
  },
  (error) => Promise.reject(error)
);

// 响应拦截器:处理响应,处理常见错误
request.interceptors.response.use(
  (response) => response.data,
  (error) => {
    if (error.response?.status === 401) {
      // 处理未授权访问
      const userStore = useUserStore();
      userStore.logout();
    }
    return Promise.reject(error);
  }
);

HTTP 层的关键特性:

  • 请求拦截器 - 添加认证头,处理常见参数
  • 响应拦截器 - 处理响应,处理常见错误
  • API 模块 - 按领域/功能组织
  • 类型安全 - TypeScript 接口用于请求/响应类型

🛠️ 实用层

应用程序包括丰富的实用函数和钩子,以处理常见任务:

实用工具分类

类型 功能 示例
认证实用工具 令牌管理,时间戳验证 getToken(), validateToken()
菜单实用工具 菜单处理和转换 transformMenus(), filterMenus()
路由实用工具 路由映射和导航助手 generateRoutes(), navigateTo()
自定义钩子 常见模式的可重用组合函数 useRequest(), usePermission()

⚙️ 构建和开发工具

应用程序使用 Vite 作为构建工具,具有丰富的插件和配置:

技术栈

  • TypeScript - 应用程序中强类型
  • ESLint 和 Prettier - 代码质量和格式化
  • Husky - Git 钩子用于预提交检查
  • Vitest - 单元测试框架
  • UnoCSS - 原子 CSS 实用框架

开发工作流程优化

开发工作流程优化了开发者体验:

json 复制代码
{
  "scripts": {
    "dev": "vite",                // 快速构建:Vite 的按需编译
    "build": "vite build",        // 生产构建
    "type:check": "vue-tsc",      // 类型检查:实时 TypeScript 验证
    "lint": "eslint . --fix",     // 全面检查:多个检查器协同工作
    "test:unit": "vitest"         // 单元测试
  }
}

优化特性:

  • 快速构建 - Vite 的按需编译
  • 热模块替换 - 开发过程中的即时反馈
  • 类型检查 - 实时 TypeScript 验证
  • 全面检查 - 多个检查器协同工作

🎯 架构总结

Robot Admin 实现了一个现代化、可维护的架构,强调:

核心特点

特点 实现方式 优势
模块化 组件、存储和插件按逻辑单元组织 易于维护和扩展
灵活性 动态路由和插件系统允许扩展 适应业务变化
类型安全 整个代码库使用 TypeScript 减少运行时错误
开发者体验 工具优化了生产力 提升开发效率
可维护性 清晰的关注点分离和一致的模式 降低维护成本

💡 架构价值

该架构为构建复杂管理应用程序提供了坚实的基础,同时保持了代码库可维护性和可扩展性。


期待共建

如果这个项目对你有帮助,请给个 Star ⭐️ 支持一下!

点击直达GitHub: github.com/ChenyCHENYU...

项目资源:

• 项目预览:robotadmin.cn/

• 项目文档:www.tzagileteam.com/

让我们一起构建更好的开发体验!

相关推荐
十年一梦惊觉醒2 分钟前
快手视频发布助手,全自动视频发布带货工具
开发语言·前端·javascript
Solara2 分钟前
中文字体子集化实录:3.2MB → 200KB 的完整脚本、踩坑清单与三条反直觉经验
前端·css·架构
Htr_17 分钟前
Cortex 使用指南:开源 API 知识层
前端·数据库·人工智能·重构·计算机外设
计算机魔术师20 分钟前
Dario Amodei 发文呼吁 AI 行业放慢前沿速度并公布三步计划
前端
EatFan24 分钟前
前后端分离项目中 Token 到底应该怎么设计?Access Token + Refresh Token 实战
java·前端·后端
dsyyyyy110131 分钟前
Typescript装饰器
前端·javascript·typescript
一拳不是超人2 小时前
一个没测暗色模式的 Bug,吃掉了我一半 谷歌扩展用户
前端·javascript·程序员
liangshanbo12152 小时前
React useState 函数式更新面试题整理
前端·react.js·前端框架
涛涛ing2 小时前
为什么你的页面在 Safari 上总出问题?Interop 2027 正在解决这个 20 年老毛病
前端
不一样的少年_2 小时前
WebP 压缩到底在干嘛?小白也能看懂的原理拆解
前端·后端·图片资源