Packages 详解
CondorAdmin 前端采用 Monorepo 架构,将公共模块抽离为独立的内部包(Packages),提高代码复用性和可维护性。
Packages 架构
整体结构
packages/
├── materials/ # UI 布局组件
├── hooks/ # 组合式函数
├── utils/ # 工具函数
├── axios/ # Axios HTTP 客户端
├── alova/ # Alova HTTP 客户端(可选)
├── ofetch/ # oFetch HTTP 客户端(可选)
├── color/ # 颜色工具
├── uno-preset/ # UnoCSS 预设
├── elegant-router-core/# 路由核心
└── scripts/ # 构建脚本依赖关系
src/main.ts
↓
materials (布局组件)
↓
hooks (组合式函数)
↓
utils (工具函数) + axios/alova/ofetch (HTTP客户端)
↓
color (颜色处理)核心 Packages
1. @sa/materials
功能:提供管理后台的核心布局组件。
位置:packages/materials/
导出内容:
// packages/materials/src/index.ts
export {
AdminLayout, // 主布局组件
LAYOUT_MAX_Z_INDEX, // 布局最大 z-index
LAYOUT_SCROLL_EL_ID, // 滚动容器 ID
PageTab, // 标签页组件
SimpleScrollbar // 简易滚动条
};核心组件:
AdminLayout
管理后台主布局,包含头部、侧边栏、主内容区、标签页。
<template>
<AdminLayout>
<template #header>
<!-- 自定义头部 -->
</template>
<template #sider>
<!-- 自定义侧边栏 -->
</template>
<template #tab>
<!-- 自定义标签页 -->
</template>
<router-view />
</AdminLayout>
</template>配置项:
mode:布局模式(vertical/horizontal)scrollElId:滚动容器 IDscrollMode:滚动模式(wrapper/content)
PageTab
标签页组件,支持多种风格。
// 标签页样式
type TabMode = 'chrome' | 'button' | 'slider';使用:
<PageTab
:tabs="tabs"
:active-tab="activeTab"
mode="chrome"
@close="handleClose"
/>2. @sa/hooks
功能:提供可复用的 Vue 组合式函数(Composables)。
位置:packages/hooks/
核心 Hooks:
useBoolean
管理布尔状态及其切换。
import { useBoolean } from '@sa/hooks';
const [visible, { setTrue, setFalse, toggle }] = useBoolean(false);
// 使用
setTrue(); // visible.value = true
setFalse(); // visible.value = false
toggle(); // visible.value = !visible.valueuseLoading
管理加载状态。
import { useLoading } from '@sa/hooks';
const { loading, startLoading, endLoading } = useLoading();
async function fetchData() {
startLoading();
try {
await api.getData();
} finally {
endLoading();
}
}useCountDown
倒计时功能。
import { useCountDown } from '@sa/hooks';
const { count, start, stop, reset } = useCountDown(60);
// 开始倒计时
start(() => {
console.log('倒计时结束');
});3. @sa/utils
功能:提供通用工具函数。
位置:packages/utils/
核心工具:
类型判断
import { isArray, isObject, isString, isNumber } from '@sa/utils';
isArray([1, 2, 3]); // true
isObject({ a: 1 }); // true
isString('hello'); // true
isNumber(123); // true数据转换
import { objectToCamelCase, objectToSnakeCase } from '@sa/utils';
// 对象键名转驼峰
const camel = objectToCamelCase({ user_name: 'admin' });
// { userName: 'admin' }
// 对象键名转下划线
const snake = objectToSnakeCase({ userName: 'admin' });
// { user_name: 'admin' }防抖节流
import { debounce, throttle } from '@sa/utils';
// 防抖:300ms 内多次调用只执行最后一次
const debouncedSearch = debounce((keyword: string) => {
search(keyword);
}, 300);
// 节流:300ms 内最多执行一次
const throttledScroll = throttle(() => {
handleScroll();
}, 300);存储工具
import { localStg, sessionStg } from '@sa/utils';
// LocalStorage
localStg.set('token', 'abc123');
const token = localStg.get('token');
localStg.remove('token');
// SessionStorage
sessionStg.set('tempData', { id: 1 });
const data = sessionStg.get('tempData');4. @sa/axios
功能:基于 Axios 的 HTTP 客户端,内置拦截器和错误处理。
位置:packages/axios/
特性:
- 请求/响应拦截器
- 统一错误处理
- Token 自动注入
- 请求取消
- 请求重试
使用示例:
import { createRequest } from '@sa/axios';
// 创建实例
const request = createRequest({
baseURL: import.meta.env.VITE_SERVICE_BASE_URL,
timeout: 10000
});
// 请求拦截器
request.interceptors.request.use(config => {
const token = localStg.get('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
// 响应拦截器
request.interceptors.response.use(
response => {
const { code, data, msg } = response.data;
if (code === '0000') {
return { data, error: null };
}
return { data: null, error: { code, msg } };
},
error => {
return { data: null, error };
}
);5. @sa/color
功能:颜色处理工具,支持颜色格式转换、混合、主题色生成。
位置:packages/color/
核心功能:
颜色格式转换
import { hexToRgb, rgbToHex, hexToHsl } from '@sa/color';
hexToRgb('#3b82f6'); // { r: 59, g: 130, b: 246 }
rgbToHex(59, 130, 246); // '#3b82f6'
hexToHsl('#3b82f6'); // { h: 217, s: 91, l: 60 }颜色混合
import { mixColor } from '@sa/color';
// 混合两种颜色
const mixed = mixColor('#3b82f6', '#ffffff', 0.5);
// 返回中间色主题色生成
import { generateColorPalette } from '@sa/color';
// 生成主题色板(10个层级)
const palette = generateColorPalette('#3b82f6');
// ['#eff6ff', '#dbeafe', ..., '#1e40af', '#1e3a8a']6. @sa/uno-preset
功能:UnoCSS 自定义预设,定义项目的设计令牌和快捷方式。
位置:packages/uno-preset/
预设内容:
// uno.config.ts
import { defineConfig, presetUno } from 'unocss';
import { presetSoybean } from '@sa/uno-preset';
export default defineConfig({
presets: [
presetUno(),
presetSoybean()
]
});自定义快捷方式:
// 快捷类名
<div class="flex-center"> // flex + justify-center + items-center
<div class="card"> // 卡片样式
<div class="btn-primary"> // 主要按钮样式7. @sa/elegant-router-core
功能:路由核心库,提供文件路由和路由转换功能。
位置:packages/elegant-router-core/
特性:
- 基于文件系统的路由生成
- 支持动态路由
- 路由元信息配置
- 权限路由过滤
路由转换:
import { transformElegantRouter } from '@sa/elegant-router-core';
// 将文件路由转换为 Vue Router 路由
const routes = transformElegantRouter(elegantRoutes);8. @sa/scripts
功能:构建和开发脚本工具。
位置:packages/scripts/
命令:
# 清理依赖
pnpm sa cleanup
# 生成路由
pnpm sa gen-route
# 提交代码(规范化)
pnpm sa git-commit
# 更新依赖
pnpm sa update-pkgHTTP 客户端对比
CondorAdmin 提供三种 HTTP 客户端选择:
| 特性 | @sa/axios | @sa/alova | @sa/ofetch |
|---|---|---|---|
| 基础库 | Axios | Alova | oFetch |
| 请求缓存 | ❌ | ✅ | ❌ |
| 请求共享 | ❌ | ✅ | ❌ |
| SSR 支持 | ⚠️ | ✅ | ✅ |
| 包体积 | ~14KB | ~8KB | ~4KB |
| 学习成本 | 低 | 中 | 低 |
推荐:
- 通用项目:
@sa/axios(稳定、生态完善) - 性能优化:
@sa/alova(缓存、请求共享) - 轻量化:
@sa/ofetch(最小体积)
使用指南
安装依赖
项目使用 pnpm workspace,所有内部包已自动链接:
pnpm install导入使用
// 导入布局组件
import { AdminLayout, PageTab } from '@sa/materials';
// 导入 Hooks
import { useBoolean, useLoading } from '@sa/hooks';
// 导入工具函数
import { debounce, isArray } from '@sa/utils';
// 导入 HTTP 客户端
import { createRequest } from '@sa/axios';
// 导入颜色工具
import { hexToRgb, generateColorPalette } from '@sa/color';类型支持
所有 Packages 都提供完整的 TypeScript 类型定义:
import type { AdminLayoutProps } from '@sa/materials';
import type { UseLoadingReturn } from '@sa/hooks';自定义 Package
创建新 Package
# 1. 在 packages/ 下创建目录
mkdir packages/my-package
# 2. 初始化 package.json
cd packages/my-package
pnpm init
# 3. 配置 package.json
{
"name": "@sa/my-package",
"version": "1.0.0",
"exports": {
".": "./src/index.ts"
}
}
# 4. 创建入口文件
mkdir src
echo "export const myUtil = () => {}" > src/index.ts在项目中使用
// 1. 在根 package.json 添加依赖
{
"dependencies": {
"@sa/my-package": "workspace:*"
}
}
// 2. 导入使用
import { myUtil } from '@sa/my-package';最佳实践
1. Package 职责划分
- materials:仅放置 UI 布局组件
- hooks:通用业务逻辑的 Composables
- utils:纯函数工具,无副作用
- axios/alova/ofetch:HTTP 客户端封装
2. 避免循环依赖
✅ 正确:utils ← hooks ← materials
❌ 错误:utils ← hooks ← materials ← utils3. 导出规范
// ✅ 具名导出(推荐)
export { useBoolean, useLoading };
// ❌ 默认导出(避免)
export default { useBoolean, useLoading };4. 版本管理
所有内部 Packages 使用 workspace:* 版本,自动同步:
{
"dependencies": {
"@sa/hooks": "workspace:*"
}
}常见问题
Q1: 如何调试 Package 代码?
直接修改 packages/ 下的源码,项目会自动热更新。
Q2: Package 之间如何共享类型?
在 packages/utils/src/types/ 定义公共类型,其他包导入:
import type { CommonType } from '@sa/utils';Q3: 如何发布内部 Package?
内部 Package 不需要发布到 npm,通过 workspace 本地引用即可。
相关文档
- 📖 状态管理
- 🎨 主题系统
- 🔧 路由系统
- 🛠️ Composables