npm package: @gulibs/vgrove-client
Description: Client-side utilities for React auto routes
Author: HectorGu
Latest version: 0.0.170

# @gulibs/vgrove-client

一个功能强大的 React 路由自动化客户端库，提供完整的路由保护、状态管理、国际化和性能优化解决方案。

## ✨ 特性

- 🛡️ **路由保护** - 支持认证、权限、角色和自定义守卫，提供组件包装器、高阶组件和 Hook 三种使用方式
- 🏗️ **中间件系统** - 可插拔的中间件架构，支持优先级排序和开发环境限制
- 🌍 **国际化支持** - 与 @gulibs/vgrove-i18n 完美集成，支持虚拟模块、资源加载和路由集成
- 📊 **状态管理** - 基于 React Storage 的用户认证状态管理，支持 Token 自动刷新
- 💾 **存储管理** - 统一的 localStorage/sessionStorage 管理接口，支持跨标签页同步
- ⚡ **性能优化** - 内置 LRU 缓存、批处理器、性能追踪器和内存优化器，智能保护需求检测
- 🚀 **布局抖动修复** - 智能检测空配置文件，避免不必要的状态转换，提供快速通道渲染
- 🎯 **TypeScript** - 完整的类型定义支持，提供类型安全的国际化键
- 📱 **现代化** - 支持 React 18+ 和现代浏览器，兼容最新的 React Router v7
- 🔄 **热更新** - 支持开发时的热模块替换和资源热重载
- 📦 **模块化** - 按需导入，减小包大小，支持 Tree Shaking
- 🛠️ **工具函数** - 丰富的实用工具函数库，涵盖路径处理、查询参数、防抖节流等
- 🔒 **安全设计** - 调试功能默认全部关闭，需要显式启用，确保生产环境安全
- 🔍 **调试支持** - 细粒度调试控制系统，支持模块化开关和浏览器开发者工具集成

## 📦 安装

```bash
npm install @gulibs/vgrove-client
# 或
pnpm add @gulibs/vgrove-client
# 或
yarn add @gulibs/vgrove-client
```

### 对等依赖

```bash
npm install react react-dom react-router lodash
```

## 🚀 快速开始

### 0. 配置管理（推荐） ⚠️

⚠️ **重要：安全设计**
- **调试功能默认全部关闭**，包括开发环境
- 必须显式启用调试才能看到相关日志
- 这避免了意外暴露敏感信息到调试日志中

首先初始化 VGrove Client，配置调试选项和开发者工具：

```tsx
import { initVGroveClient } from '@gulibs/vgrove-client';

// 🔒 生产环境推荐配置（默认安全）
initVGroveClient();  // 所有调试功能默认关闭

// 🛠️ 开发环境配置（需要显式启用调试）
initVGroveClient({
  debug: {
    enabled: true,        // 必须显式启用调试系统
    auth: true,           // 启用认证调试
    i18n: false,          // 保持国际化调试关闭
    performance: true,    // 启用性能监控
    routing: true,        // 启用路由调试
    storage: false        // 保持存储调试关闭
  },
  devtools: process.env.NODE_ENV === 'development' // 只在开发环境启用
});
```

使用浏览器开发者工具（开发环境）：

```javascript
// 在浏览器控制台中使用内置开发者工具
__VGROVE_DEVTOOLS__.debug.status();              // 查看调试状态（表格形式）
__VGROVE_DEVTOOLS__.debug.enable();              // 启用所有调试
__VGROVE_DEVTOOLS__.debug.enableModule('auth');  // 启用特定模块
__VGROVE_DEVTOOLS__.debug.disableModule('routing'); // 禁用特定模块
__VGROVE_DEVTOOLS__.client.getState();           // 查看客户端状态
```

### 1. 路由保护

```tsx
import { RouteProtectionWrapper, defineAuth, defineGuard } from '@gulibs/vgrove-client';

// 定义认证守卫
const authGuard = defineAuth({
  redirectTo: '/login',
  errorMessage: '请先登录'
});

// 定义自定义守卫
const adminGuard = defineGuard({
  name: 'admin-only',
  condition: (context) => context.user?.role === 'admin',
  redirectTo: '/forbidden',
  errorMessage: '需要管理员权限'
});

function ProtectedPage() {
  return (
    <RouteProtectionWrapper
      guards={[authGuard, adminGuard]}
      loadingElement={<div>验证中...</div>}
      component={<YourPageComponent />}
    />
  );
}
```

### 2. 用户状态管理

```tsx
import { useUser } from '@gulibs/vgrove-client';

function AuthComponent() {
  const {
    user,
    isAuthenticated,
    isLoading,
    login,
    logout,
    error
  } = useUser({
    loginApi: async (credentials) => {
      const response = await fetch('/api/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(credentials)
      });
      return response.json();
    },
    fetchUser: async (token) => {
      const response = await fetch('/api/user', {
        headers: { Authorization: `Bearer ${token}` }
      });
      return response.json();
    }
  });

  if (isLoading) return <div>加载中...</div>;
  if (error) return <div>错误: {error}</div>;

  return (
    <div>
      {isAuthenticated ? (
        <div>
          <p>欢迎, {user?.name}</p>
          <button onClick={logout}>退出登录</button>
        </div>
      ) : (
        <button onClick={() => login({ username: 'demo', password: '123' })}>
          登录
        </button>
      )}
    </div>
  );
}
```

### 3. 性能优化与布局抖动修复 🚀

VGrove Client 提供了先进的性能优化功能，特别针对布局抖动问题进行了专项修复。

#### 3.1 智能保护需求检测

当 `_configs.tsx` 文件为空或无实际保护需求时，系统会自动启用快速通道，避免不必要的状态转换：

```tsx
// ❌ 之前：即使空配置也会执行完整状态机
// _configs.tsx (空配置)
export default defineConfigs({});

// ✅ 现在：自动检测无保护需求，启用快速通道
import { RouteProtectionWrapper } from '@gulibs/vgrove-client';

function OptimizedPage() {
  return (
    <RouteProtectionWrapper
      component={<YourPageComponent />}
      // 空配置时自动跳过状态转换，直接渲染组件
    />
  );
}
```

#### 3.2 布局抖动解决方案

**问题描述**：空配置文件导致页面经历 `checking` → `passed` 状态转换，造成布局抖动。

**解决方案**：智能检测 + 快速通道

```tsx
import { RouteProtectionWrapper, defineAuth, defineGuard } from '@gulibs/vgrove-client';

// ✅ 有实际保护需求 - 正常执行保护逻辑
const protectedPageConfig = {
  guards: [
    defineAuth({ redirectTo: '/login' }),
    defineGuard({
      condition: (ctx) => ctx.user?.permissions.includes('read'),
      redirectTo: '/forbidden'
    })
  ]
};

// ✅ 无保护需求 - 启用快速通道
const publicPageConfig = {
  guards: [],           // 无守卫
  middlewares: [],      // 无中间件
  stateRenderers: {},   // 无状态渲染器
  redirectConfig: {}    // 无重定向配置
};

function SmartProtectedPage() {
  return (
    <RouteProtectionWrapper
      {...protectedPageConfig}
      component={<YourPageComponent />}
      // 智能检测：有保护需求时执行完整逻辑
      // 无保护需求时直接渲染，0ms 状态转换
    />
  );
}
```

#### 3.3 性能指标对比

| 场景 | 修复前 | 修复后 | 改善 |
|------|--------|--------|------|
| 空配置页面首次渲染 | ~50ms + 布局抖动 | ~5ms 无抖动 | 90% ⬇️ |
| 有保护需求页面 | ~50ms | ~45ms | 10% ⬇️ |
| 调试输出（生产环境） | 20+ console 调用 | 0 console 调用 | 100% ⬇️ |
| 内存占用 | ~200KB | ~150KB | 25% ⬇️ |

#### 3.4 调试性能监控

```tsx
import { debug } from '@gulibs/vgrove-client';

// ✅ 高性能调试（仅在需要时执行）
function PerformanceOptimizedComponent() {
  useEffect(() => {
    // 只有在调试启用时才执行相关逻辑
    debug.performance('组件渲染完成', {
      timestamp: Date.now(),
      componentName: 'PerformanceOptimizedComponent'
    });
  }, []);

  return <div>组件内容</div>;
}
```

#### 3.5 验证修复效果

```tsx
// 验证工具：检查页面是否使用了快速通道
function usePerformanceVerification() {
  const [hasLayoutShift, setHasLayoutShift] = useState(false);
  const [renderTime, setRenderTime] = useState(0);

  useEffect(() => {
    const startTime = performance.now();

    // 检测布局抖动
    const observer = new PerformanceObserver((list) => {
      for (const entry of list.getEntries()) {
        if (entry.entryType === 'layout-shift' && entry.value > 0) {
          setHasLayoutShift(true);
        }
      }
    });

    observer.observe({ entryTypes: ['layout-shift'] });

    // 测量渲染时间
    requestAnimationFrame(() => {
      setRenderTime(performance.now() - startTime);
    });

    return () => observer.disconnect();
  }, []);

  return { hasLayoutShift, renderTime };
}

// 使用验证工具
function VerifiedPage() {
  const { hasLayoutShift, renderTime } = usePerformanceVerification();

  return (
    <div>
      <RouteProtectionWrapper component={<YourContent />} />
      {process.env.NODE_ENV === 'development' && (
        <div style={{ position: 'fixed', top: 0, right: 0, background: '#f0f0f0', padding: '8px' }}>
          <p>布局抖动: {hasLayoutShift ? '❌ 检测到' : '✅ 无'}</p>
          <p>渲染时间: {renderTime.toFixed(2)}ms</p>
        </div>
      )}
    </div>
  );
}
```

### 4. 国际化支持

```tsx
import { I18nProvider, useI18n, createI18nClient } from '@gulibs/vgrove-client';

// 创建国际化客户端
const i18nClient = createI18nClient({
  defaultLocale: 'zh',
  supportedLocales: ['zh', 'en'],
  resources: {
    zh: {
      welcome: '欢迎',
      hello: '你好, {name}!'
    },
    en: {
      welcome: 'Welcome',
      hello: 'Hello, {name}!'
    }
  }
});

function App() {
  return (
    <I18nProvider client={i18nClient}>
      <MyComponent />
    </I18nProvider>
  );
}

function MyComponent() {
  const { t, locale, setLocale } = useI18n();

  return (
    <div>
      <p>{t('welcome')}</p>
      <p>{t('hello', { name: '张三' })}</p>
      <button onClick={() => setLocale(locale === 'zh' ? 'en' : 'zh')}>
        切换语言
      </button>
    </div>
  );
}
```

### 5. 存储管理

```tsx
import { useStorage } from '@gulibs/vgrove-client';

function StorageExample() {
  // 基础存储使用
  const [userPrefs, setUserPrefs, removeUserPrefs] = useStorage('user_preferences', {
    theme: 'light',
    language: 'zh'
  });

  // 使用 sessionStorage
  const [tempData, setTempData] = useStorage('temp_data', null, {
    storage: 'session'
  });

  // 带过期时间的存储（1小时后过期）
  const [cacheData, setCacheData, removeCacheData, setCacheWithExpiry, isCacheExpired, cleanupCache] = useStorage(
    'api_cache',
    {},
    {
      storage: 'local',
      maxAge: 60 * 60 * 1000, // 1小时
      autoCleanup: true,      // 自动清理过期数据
      cleanupInterval: 5 * 60 * 1000 // 每5分钟清理一次
    }
  );

  // 临时令牌存储（30分钟后过期）
  const [tempToken, setTempToken, removeTempToken, setTokenWithExpiry, isTokenExpired] = useStorage(
    'temp_token',
    null,
    {
      storage: 'session',
      maxAge: 30 * 60 * 1000, // 30分钟
      autoCleanup: true
    }
  );

  return (
    <div>
      <p>当前主题: {userPrefs.theme}</p>
      <button onClick={() => setUserPrefs({ ...userPrefs, theme: 'dark' })}>
        切换到暗色主题
      </button>
      <button onClick={removeUserPrefs}>
        重置偏好设置
      </button>

      {/* 缓存数据管理 */}
      <div>
        <p>缓存状态: {isCacheExpired() ? '已过期' : '有效'}</p>
        <button onClick={() => setCacheData({ apiData: 'some data' })}>
          设置缓存（使用默认过期时间）
        </button>
        <button onClick={() => setCacheWithExpiry({ quickData: 'quick' }, 5 * 60 * 1000)}>
          设置快速缓存（5分钟过期）
        </button>
        <button onClick={cleanupCache}>
          手动清理过期数据
        </button>
      </div>

      {/* 临时令牌管理 */}
      <div>
        <p>令牌状态: {isTokenExpired() ? '已过期' : '有效'}</p>
        <button onClick={() => setTempToken('temp-token-123')}>
          设置临时令牌
        </button>
        <button onClick={() => setTokenWithExpiry('extended-token', 60 * 60 * 1000)}>
          设置扩展令牌（1小时）
        </button>
      </div>
    </div>
  );
}
```

### 6. 认证状态管理 Hooks

```tsx
import { useUser, useUserState, useAuthToken } from '@gulibs/vgrove-client';

// 只读用户状态
function ReadOnlyUserInfo() {
  const { user, isAuthenticated, token } = useUserState('auth', false);

  if (!isAuthenticated) return <div>未登录</div>;

  return (
    <div>
      <p>用户: {user?.name}</p>
      <p>Token: {token?.substring(0, 20)}...</p>
    </div>
  );
}

// Token 管理
function TokenManager() {
  const {
    token,
    refreshToken,
    setToken,
    setRefreshToken,
    clearAllTokens,
    hasToken,
    hasRefreshToken
  } = useAuthToken('auth');

  return (
    <div>
      <p>有 Token: {hasToken ? '是' : '否'}</p>
      <p>有 Refresh Token: {hasRefreshToken ? '是' : '否'}</p>
      <button onClick={() => setToken('new-token-123')}>
        设置新 Token
      </button>
      <button onClick={clearAllTokens}>
        清除所有 Token
      </button>
    </div>
  );
}
```

### 7. 路由保护的不同形式

```tsx
import {
  RouteProtectionWrapper,
  withRouteProtection,
  useRouteProtection
} from '@gulibs/vgrove-client';

// 1. 组件包装器形式（已展示）
function ComponentWrapper() {
  return (
    <RouteProtectionWrapper
      guards={[authGuard]}
      component={<ProtectedContent />}
    />
  );
}

// 2. 高阶组件形式
const ProtectedComponent = withRouteProtection(MyComponent, {
  guards: [authGuard, adminGuard],
  loadingElement: <div>验证中...</div>
});

function App() {
  return <ProtectedComponent prop1="value1" />;
}

// 3. Hook 形式
function HookBasedProtection() {
  const { isLoading, error, hasAccess, user } = useRouteProtection([authGuard]);

  if (isLoading) return <div>检查访问权限...</div>;
  if (error) return <div>错误: {error}</div>;
  if (!hasAccess) return <div>访问被拒绝</div>;

  return (
    <div>
      <h1>受保护的内容</h1>
      <p>欢迎, {user?.name}</p>
    </div>
  );
}
```

## 🛡️ 认证与守卫系统完全指南

### 认证 vs 守卫的区别

| 特性 | Auth （认证） | Guard （守卫） |
|------|-------------|--------------|
| **主要用途** | 身份验证 | 权限控制 |
| **检查内容** | 用户是否已登录 | 用户是否有权限访问 |
| **失败后果** | 重定向到登录页 | 重定向到错误页 / 拒绝页 |
| **适用场景** | 保护需要登录的页面 | 保护需要特定权限的页面 |
| **执行顺序** | 优先执行 | 在认证通过后执行 |

### 🔐 认证系统详解

#### 1. 基础认证 - defineAuth

**最简单的认证方式，适合基础的登录检查**

```tsx
import { defineAuth } from '@gulibs/vgrove-client';

// 页面级认证文件：pages/dashboard/auth.ts
export default defineAuth({
    name: 'dashboard-auth',                    // 认证名称（可选）
    redirectTo: '/login',                      // 失败时重定向路径
    errorMessage: '请先登录访问仪表板',         // 错误消息
    check: (context) => {                      // 认证检查函数
        // context 包含：path, params, query, user, roles, permissions, data
        const token = localStorage.getItem('auth_token');

        // ⚠️ 关键：必须返回 boolean 值
        return !!token;
    }
});
```

**❌ 常见错误：**

```tsx
// 错误1：没有返回值
check: (context) => {
    const token = localStorage.getItem('auth_token');
    // ❌ 缺少 return 语句
}

// 错误2：返回非布尔值
check: (context) => {
    return localStorage.getItem('auth_token'); // ❌ 返回 string | null
}

// 错误3：异步函数但没有正确处理
check: (context) => {
    return fetch('/api/verify').then(res => res.ok); // ❌ 返回 Promise
}
```

**✅ 正确用法：**

```tsx
// 同步检查
check: (context) => {
    const token = localStorage.getItem('auth_token');
    return !!token; // ✅ 返回 boolean
}

// 异步检查
check: async (context) => {
    try {
        const response = await fetch('/api/verify', {
            headers: { Authorization: `Bearer ${context.user?.token}` }
        });
        return response.ok; // ✅ 返回 boolean
    } catch (error) {
        console.error('Auth check failed:', error);
        return false; // ✅ 异常时返回 false
    }
}
```

#### 2. 智能认证 - defineSmartAuth ⭐

**推荐使用！自动处理循环重定向，防止常见错误**

```tsx
import { defineSmartAuth } from '@gulibs/vgrove-client';

// 页面级认证文件：pages/auth.ts (根目录)
export default defineSmartAuth({
    name: 'root-smart-auth',
    redirectTo: '/login',
    errorMessage: '请先登录后访问应用',

    // 🚀 智能特性配置
    enableLoopDetection: true,              // 启用循环重定向检测
    excludeCommonPublicPaths: true,         // 自动排除常见公共路径
    publicPaths: [                          // 自定义公共路径
        '/about',
        '/help',
        '/docs/*',                          // 支持通配符
        '/api/*'
    ],

    check: (context) => {
        // 智能认证会自动处理：
        // 1. 如果是公共路径，直接允许访问
        // 2. 如果检测到循环重定向，自动阻止
        // 3. 然后才执行这里的检查逻辑

        const token = localStorage.getItem('auth_token');
        console.log('🔐 Smart Auth Check:', {
            path: context.path,
            hasToken: !!token,
            user: context.user
        });

        return !!token;
    }
});
```

**内置公共路径列表：**

```tsx
// defineSmartAuth 自动排除这些路径：
const DEFAULT_PUBLIC_PATHS = [
    '/login', '/signin', '/sign-in',
    '/register', '/signup', '/sign-up',
    '/auth/login', '/auth/signin',
    '/auth/register', '/auth/signup',
    '/reset-password', '/forgot-password',
    '/verify-email', '/verify',
    '/public', '/'
];
```

#### 3. 根目录认证 - defineRootAuth

**专用于整个应用的登录保护**

```tsx
import { defineRootAuth } from '@gulibs/vgrove-client';

// 页面级认证文件：pages/auth.ts
export default defineRootAuth({
    redirectTo: '/login',
    errorMessage: '请先登录后访问应用',
    publicPaths: ['/help', '/about'],       // 自定义公共路径
    check: (context) => {
        const token = localStorage.getItem('auth_token');
        return !!token;
    }
});
```

### 🛡️ 守卫系统详解

#### 1. 自定义守卫 - defineGuard

**适用于复杂的业务逻辑判断**

```tsx
import { defineGuard } from '@gulibs/vgrove-client';

// 页面级守卫文件：pages/admin/guard.ts
export default defineGuard({
    name: 'admin-access',                      // 守卫名称
    type: 'custom',                            // 守卫类型
    redirectTo: '/forbidden',                  // 失败时重定向
    errorMessage: '需要管理员权限访问此页面',   // 错误消息
    condition: (context) => {                  // 守卫条件函数
        // context 包含：path, params, query, user, permissions, roles, data

        // 检查用户角色
        if (!context.user?.role) return false;

        // 检查是否是管理员
        const isAdmin = context.user.role === 'admin';

        // 检查时间限制（示例：只允许工作时间访问）
        const now = new Date();
        const workingHours = now.getHours() >= 9 && now.getHours() <= 18;

        return isAdmin && workingHours;
    }
});
```

#### 2. 角色守卫 - defineRoleGuard

**基于用户角色的访问控制**

```tsx
import { defineRoleGuard } from '@gulibs/vgrove-client';

// 在 _configs.tsx 中使用
export default defineConfigs({
    guard: defineRoleGuard(
        ['admin', 'manager'],                  // 允许的角色列表
        '/forbidden',                          // 可选：重定向路径
        {                                      // 可选：额外选项
            publicPaths: ['/help'],
            enableLoopDetection: true
        }
    )
});
```

#### 3. 权限守卫 - definePermissionGuard

**基于具体权限的访问控制**

```tsx
import { definePermissionGuard } from '@gulibs/vgrove-client';

// 在 _configs.tsx 中使用
export default defineConfigs({
    guard: definePermissionGuard(
        ['user.write', 'user.update'],         // 所需权限列表
        '/no-permission',                      // 可选：重定向路径
        {                                      // 可选：额外选项
            enableLoopDetection: true
        }
    )
});
```

#### 4. 守卫工厂函数

**快速创建常用的守卫**

```tsx
import { defineCustomGuard } from '@gulibs/vgrove-client';

// VIP 用户守卫
export const vipGuard = defineCustomGuard(
    'vip-only',
    (context) => context.user?.membership === 'VIP',
    '/upgrade'
);

// 时间限制守卫
export const workingHoursGuard = defineCustomGuard(
    'working-hours',
    (context) => {
        const hour = new Date().getHours();
        return hour >= 9 && hour <= 18;
    },
    '/not-available'
);

// 地理位置守卫
export const regionGuard = defineCustomGuard(
    'region-check',
    async (context) => {
        const region = await getUserRegion();
        return ['US', 'CA', 'EU'].includes(region);
    },
    '/region-blocked'
);
```

### 📁 使用方式对比

#### 方式 1：单文件方式

```
src/pages/
├── dashboard/
│   ├── auth.ts          # 认证配置
│   ├── guard.ts         # 守卫配置
│   └── page.tsx         # 页面组件
└── admin/
    ├── auth.ts
    ├── guard.ts
    └── page.tsx
```

**优点：** 功能分离清晰，易于理解
**缺点：** 文件较多，配置分散

#### 方式 2：配置文件方式 （推荐）

```
src/pages/
├── dashboard/
│   ├── _configs.tsx     # 集中配置
│   └── page.tsx         # 页面组件
└── admin/
    ├── _configs.tsx
    └── page.tsx
```

**优点：** 配置集中，支持自定义组件，功能完整
**缺点：** 单文件可能较大

**完整示例：**

```tsx
// pages/dashboard/_configs.tsx
import { defineConfigs, defineSmartAuth, defineGuard } from '@gulibs/vgrove-client';
import React from 'react';

// 自定义错误组件
const AccessDeniedError = ({ error, retry }: { error?: Error; retry?: () => void }) => (
    <div className="access-denied">
        <h2>访问被拒绝</h2>
        <p>{error?.message}</p>
        <button onClick={retry}>重试</button>
        <button onClick={() => window.location.href = '/login'}>
            重新登录
        </button>
    </div>
);

// 自定义加载组件
const AuthLoading = ({ progress }: { progress?: number }) => (
    <div className="auth-loading">
        <div className="spinner" />
        <p>验证身份中...</p>
        {progress && <div>进度: {Math.round(progress * 100)}%</div>}
    </div>
);

export default defineConfigs({
    // 智能认证配置
    auth: defineSmartAuth({
        name: 'dashboard-smart-auth',
        redirectTo: '/login',
        errorMessage: '请先登录访问仪表板',
        enableLoopDetection: true,
        excludeCommonPublicPaths: true,
        check: (context) => {
            const token = localStorage.getItem('auth_token');
            console.log('Dashboard auth check:', {
                path: context.path,
                hasToken: !!token
            });
            return !!token;
        }
    }),

    // 守卫配置
    guard: defineGuard({
        name: 'dashboard-access',
        type: 'custom',
        redirectTo: '/upgrade',
        errorMessage: '需要升级账户以访问仪表板',
        condition: (context) => {
            // 检查用户类型
            if (!context.user) return false;

            // 免费用户不能访问仪表板
            return context.user.plan !== 'free';
        }
    }),

    // 自定义错误组件
    error: AccessDeniedError,

    // 自定义加载组件
    loading: AuthLoading
});
```

### 🚨 常见错误和解决方案

#### 错误 1：循环重定向死循环

**症状：** 页面不断重定向，浏览器显示"重定向次数过多"

**原因：** 登录页面设置了认证保护

```tsx
// ❌ 错误示例
// pages/login/auth.ts
export default defineAuth({
    redirectTo: '/login',      // 重定向到自己
    check: () => false         // 总是返回false
});
```

**解决方案：**

```tsx
// ✅ 方案1：删除登录页面的认证文件
// 直接删除 pages/login/auth.ts

// ✅ 方案2：使用智能认证自动处理
export default defineSmartAuth({
    redirectTo: '/login',
    enableLoopDetection: true,    // 自动检测并阻止循环
    excludeCommonPublicPaths: true, // 自动排除登录页面
    check: (context) => !!context.user
});
```

#### 错误 2：守卫执行顺序混乱

**症状：** 权限检查在认证检查之前执行

```tsx
// ❌ 错误：在需要认证的页面只设置守卫
export default defineConfigs({
    // 缺少 auth 配置
    guard: defineGuard({
        condition: (context) => context.user?.role === 'admin' // 用户可能为 null
    })
});

// ✅ 正确：先认证，再守卫
export default defineConfigs({
    // 先进行身份认证
    auth: defineSmartAuth({
        redirectTo: '/login',
        check: (context) => !!context.user
    }),

    // 认证通过后检查权限
    guard: defineGuard({
        condition: (context) => {
            // 此时 context.user 已经确保存在
            return context.user?.role === 'admin';
        },
        redirectTo: '/forbidden'
    })
});
```

### 🎯 最佳实践

#### 1. 分层认证架构

```
src/pages/
├── auth.ts                    # 根目录：基础身份认证
├── public/                    # 公开页面（无需认证）
│   ├── login/
│   ├── register/
│   └── about/
├── user/                      # 用户区域
│   ├── _configs.tsx          # 用户认证 + 基础权限
│   ├── dashboard/
│   └── profile/
├── admin/                     # 管理员区域
│   ├── _configs.tsx          # 管理员认证 + 管理权限
│   ├── users/
│   └── settings/
└── premium/                   # 高级功能区域
    ├── _configs.tsx          # 会员认证 + 会员权限
    └── analytics/
```

#### 2. 认证状态管理

```tsx
// utils/auth.ts - 集中的认证工具
export class AuthManager {
    private static instance: AuthManager;

    static getInstance(): AuthManager {
        if (!AuthManager.instance) {
            AuthManager.instance = new AuthManager();
        }
        return AuthManager.instance;
    }

    // 获取当前用户
    getCurrentUser(): User | null {
        try {
            const userData = localStorage.getItem('user_data');
            return userData ? JSON.parse(userData) : null;
        } catch {
            return null;
        }
    }

    // 检查认证状态
    isAuthenticated(): boolean {
        const token = localStorage.getItem('auth_token');
        const user = this.getCurrentUser();
        return !!(token && user && user.status === 'active');
    }

    // 检查角色
    hasRole(roles: string[]): boolean {
        const user = this.getCurrentUser();
        return user?.roles?.some(role => roles.includes(role)) || false;
    }

    // 检查权限
    hasPermission(permissions: string[]): boolean {
        const user = this.getCurrentUser();
        return permissions.every(permission =>
            user?.permissions?.includes(permission)
        );
    }

    // 登出
    logout(): void {
        localStorage.removeItem('auth_token');
        localStorage.removeItem('user_data');
        localStorage.removeItem('refresh_token');

        // 触发自定义事件通知其他组件
        window.dispatchEvent(new CustomEvent('authStateChange'));

        // 重定向到登录页
        window.location.href = '/public/login';
    }
}

// 在认证配置中使用
export default defineSmartAuth({
    check: (context) => {
        const authManager = AuthManager.getInstance();
        return authManager.isAuthenticated();
    }
});
```

#### 3. 调试和开发工具

```tsx
// utils/authDebug.ts - 认证调试工具
export class AuthDebugger {
    private static enabled = process.env.NODE_ENV === 'development';

    static log(message: string, data?: any): void {
        if (!this.enabled) return;

        console.group(`🔐 Auth Debug: ${message}`);
        if (data) {
            console.log('Data:', data);
        }
        console.log('Timestamp:', new Date().toISOString());
        console.groupEnd();
    }

    static logAuthCheck(
        checkName: string,
        result: boolean,
        context: any,
        reason?: string
    ): void {
        if (!this.enabled) return;

        const emoji = result ? '✅' : '❌';
        console.group(`${emoji} Auth Check: ${checkName}`);
        console.log('Result:', result);
        console.log('Context:', {
            path: context.path,
            user: context.user ? 'Present' : 'Missing',
            roles: context.roles,
            permissions: context.permissions
        });
        if (reason) console.log('Reason:', reason);
        console.groupEnd();
    }
}

// 在认证配置中使用
export default defineSmartAuth({
    name: 'debug-auth',
    redirectTo: '/login',
    check: (context) => {
        const token = localStorage.getItem('auth_token');
        const result = !!token;

        AuthDebugger.logAuthCheck(
            'Token Check',
            result,
            context,
            result ? 'Token found' : 'Token missing'
        );

        return result;
    }
});
```

### 🔧 调试指南

#### 浏览器控制台调试命令

```javascript
// 1. 检查当前认证状态
console.log('Auth Token:', localStorage.getItem('auth_token'));
console.log('User Data:', JSON.parse(localStorage.getItem('user_data') || 'null'));

// 2. 模拟登录状态
localStorage.setItem('auth_token', 'debug-token-123');
localStorage.setItem('user_data', JSON.stringify({
    id: 'debug-user',
    name: 'Debug User',
    role: 'admin',
    status: 'active',
    permissions: ['read', 'write', 'admin']
}));

// 3. 清除认证状态
localStorage.removeItem('auth_token');
localStorage.removeItem('user_data');
localStorage.removeItem('refresh_token');

// 4. 检查页面保护状态
console.log('Current Path:', window.location.pathname);
console.log('Should be protected:', !window.location.pathname.includes('/public/'));
```

### 📝 快速参考

#### 认证类型对比表

| 场景 | 推荐方案 | 配置示例 |
|------|----------|----------|
| 简单登录检查 | `defineAuth` | `check: (ctx) => !!ctx.user` |
| 复杂认证逻辑 | `defineSmartAuth` | `enableLoopDetection: true` |
| 根目录保护 | `defineRootAuth` | `publicPaths: ['/public/*']` |
| 角色权限 | `defineRoleGuard` | `['admin', 'manager']` |
| 具体权限 | `definePermissionGuard` | `['user.read', 'user.write']` |
| 自定义业务逻辑 | `defineGuard` | `condition: (ctx) => {...}` |

#### 记住这些关键点

- ✅ 认证函数必须返回 `boolean`
- ✅ 登录页面不要设置认证保护
- ✅ 使用 `defineSmartAuth` 避免循环重定向
- ✅ 先设置 `auth` 再设置 `guard`
- ✅ 异步认证要用 `async/await`
- ✅ 错误处理要提供用户友好的提示

---

> **💡 提示：** 对于初学者，建议先使用 `defineSmartAuth` 和 `defineRoleGuard`，它们内置了大部分常见错误的处理逻辑。

### 7. 高级国际化 Hooks

```tsx
import {
  useI18nKeyValidator,
  useI18nNamespace,
  usePlural,
  useTranslateLocalized
} from '@gulibs/vgrove-client';

// 键验证 Hook
function I18nKeyValidator() {
  const { hasKey, validateKey, getAvailableKeys } = useI18nKeyValidator();

  const checkKey = (key: string) => {
    if (hasKey(key)) {
      console.log('键存在:', key);
    } else {
      const { suggestions } = validateKey(key);
      console.log('键不存在，建议:', suggestions);
    }
  };

  return (
    <div>
      <button onClick={() => checkKey('welcome.title')}>
        检查键: welcome.title
      </button>
      <p>可用键数量: {getAvailableKeys().length}</p>
    </div>
  );
}

// 命名空间 Hook
function NamespaceExample() {
  const { t, resources, exists } = useI18nNamespace('user');

  if (!exists) return <div>命名空间不存在</div>;

  return (
    <div>
      <h1>{t('profile.title')}</h1> {/* 相当于 user.profile.title */}
      <p>{t('profile.description')}</p>
    </div>
  );
}

// 复数形式 Hook
function PluralExample() {
  const plural = usePlural();
  const [count, setCount] = useState(1);

  return (
    <div>
      <p>{plural('message.count', count, { count })}</p>
      <button onClick={() => setCount(count + 1)}>增加</button>
    </div>
  );
}

// 本地化对象翻译 Hook
function LocalizedTranslation() {
  const translateLocalized = useTranslateLocalized();

  const localizedTitle = { localizedId: 'page.title' };

  return (
    <div>
      <h1>{translateLocalized(localizedTitle)}</h1>
    </div>
  );
}
```

### 8. I18nMessage 组件

```tsx
import { I18nMessage, I18nTitle, I18nText, I18nSwitch } from '@gulibs/vgrove-client';

// 基础用法
function MyComponent() {
  return (
    <div>
      <I18nMessage id="welcome.title" defaultValue="欢迎" />
      <I18nMessage
        id="welcome.description"
        params={{ name: '用户' }}
        defaultValue="你好，{name}！"
      />
    </div>
  );
}

// 使用便捷组件
function PageContent() {
  return (
    <div>
      <I18nTitle id="page.title" level={1} />
      <I18nText id="page.subtitle" className="text-gray-600" />

      {/* 支持不同格式 */}
      <I18nMessage
        id="rich.content"
        format="markdown"
        defaultValue="**粗体** 和 *斜体* 文本"
      />

      {/* 组件标记格式 */}
      <I18nMessage
        id="component.text"
        format="component"
        defaultValue="点击 {strong}这里{/strong} 查看更多"
      />
    </div>
  );
}

// 语言切换器
function LanguageSwitcher() {
  return (
    <I18nSwitch
      variant="select"
      locales={[
        { code: 'zh', label: '中文' },
        { code: 'en', label: 'English' }
      ]}
      onLocaleChange={(locale) => console.log('语言切换到:', locale)}
    />
  );
}
```

### 9. 性能优化工具详细示例

```tsx
import {
  PerformanceCache,
  BatchProcessor,
  PerformanceTracker,
  MemoryOptimizer,
  Debouncer,
  measureAsync
} from '@gulibs/vgrove-client';

// 缓存管理
function CacheExample() {
  const cache = useMemo(() => new PerformanceCache<string, any>(100), []);

  const fetchWithCache = useCallback(async (key: string) => {
    if (cache.has(key)) {
      return cache.get(key);
    }

    const data = await fetch(`/api/data/${key}`).then(res => res.json());
    cache.set(key, data);
    return data;
  }, [cache]);

  return (
    <div>
      <button onClick={() => fetchWithCache('user-1')}>
        获取用户数据（带缓存）
      </button>
      <p>缓存大小: {cache.size()}</p>
    </div>
  );
}

// 批处理示例
function BatchProcessingExample() {
  const batchProcessor = useMemo(() => new BatchProcessor(5, 100), []);

  const processBatchData = useCallback(async () => {
    const userIds = ['1', '2', '3', '4', '5', '6', '7', '8'];

    const users = await batchProcessor.processBatch(
      userIds,
      async (id) => {
        const response = await fetch(`/api/users/${id}`);
        return response.json();
      }
    );

    console.log('批处理完成:', users);
  }, [batchProcessor]);

  return (
    <button onClick={processBatchData}>
      批量处理用户数据
    </button>
  );
}

// 性能追踪示例
function PerformanceExample() {
  const tracker = useMemo(() => new PerformanceTracker(), []);

  const expensiveOperation = useCallback(async () => {
    tracker.startTimer('expensive-operation');

    // 模拟耗时操作
    await new Promise(resolve => setTimeout(resolve, 1000));

    const duration = tracker.endTimer('expensive-operation');
    console.log(`操作耗时: ${duration}ms`);

    tracker.increment('operation-count');
    console.log(`操作次数: ${tracker.getCounter('operation-count')}`);
  }, [tracker]);

  return (
    <div>
      <button onClick={expensiveOperation}>
        执行耗时操作
      </button>
      <button onClick={() => console.log(tracker.getStats())}>
        查看性能统计
      </button>
    </div>
  );
}

// 防抖示例
function DebounceExample() {
  const debouncer = useMemo(() => new Debouncer(), []);
  const [searchTerm, setSearchTerm] = useState('');

  const handleSearch = useCallback((term: string) => {
    debouncer.debounce('search', () => {
      console.log('搜索:', term);
      // 执行实际搜索
    }, 500);
  }, [debouncer]);

  return (
    <input
      value={searchTerm}
      onChange={(e) => {
        setSearchTerm(e.target.value);
        handleSearch(e.target.value);
      }}
      placeholder="搜索（防抖 500ms）"
    />
  );
}

// 内存优化示例
function MemoryOptimizationExample() {
  useEffect(() => {
    const memoryOptimizer = MemoryOptimizer.getInstance();

    // 添加清理任务
    memoryOptimizer.addCleanupTask(() => {
      console.log('清理缓存数据');
      // 清理各种缓存
    });

    // 启动定期清理（5分钟）
    memoryOptimizer.startPeriodicCleanup(5 * 60 * 1000);

    return () => {
      // 组件卸载时进行清理
      memoryOptimizer.runCleanup();
    };
  }, []);

  return <div>内存优化已启用</div>;
}

// 异步性能测量
function AsyncMeasurementExample() {
  const measureApiCall = useCallback(async () => {
    const result = await measureAsync('api-call', async () => {
      const response = await fetch('/api/data');
      return response.json();
    });

    console.log('API 调用结果:', result);
    console.log('耗时:', result.duration, 'ms');
  }, []);

  return (
    <button onClick={measureApiCall}>
      测量 API 调用性能
    </button>
  );
}
```

### 10. 工具函数详细示例

```tsx
import {
  normalizePath,
  parseQuery,
  buildQuery,
  updateQuery,
  debounce,
  throttle,
  deepMerge,
  deepClone,
  unique,
  groupBy,
  isEmpty,
  safeParseInt,
  toCamelCase,
  toKebabCase,
  capitalize,
  truncate,
  safely,
  safelyAsync
} from '@gulibs/vgrove-client';

function UtilityFunctionsExample() {
  // 路径处理
  const normalizedPath = normalizePath('//api//users//profile//');
  console.log(normalizedPath); // '/api/users/profile'

  // 查询参数处理
  const queryParams = parseQuery('?name=john&age=25&active=true');
  console.log(queryParams); // { name: 'john', age: '25', active: 'true' }

  const queryString = buildQuery({ name: 'jane', age: 30, active: false });
  console.log(queryString); // 'name=jane&age=30&active=false'

  const updatedUrl = updateQuery('/users', { page: 2, size: 10 });
  console.log(updatedUrl); // '/users?page=2&size=10'

  // 防抖和节流
  const debouncedSearch = debounce((term: string) => {
    console.log('搜索:', term);
  }, 500);

  const throttledScroll = throttle(() => {
    console.log('滚动事件');
  }, 100);

  // 对象操作
  const original = { a: 1, b: { c: 2 } };
  const cloned = deepClone(original);
  const merged = deepMerge({ x: 1 }, { y: 2, z: { a: 3 } });

  // 数组操作
  const items = [1, 2, 2, 3, 4, 4, 5];
  const uniqueItems = unique(items);
  console.log(uniqueItems); // [1, 2, 3, 4, 5]

  const users = [
    { name: 'Alice', role: 'admin' },
    { name: 'Bob', role: 'user' },
    { name: 'Charlie', role: 'admin' }
  ];
  const groupedUsers = groupBy(users, user => user.role);
  console.log(groupedUsers);
  // { admin: [Alice, Charlie], user: [Bob] }

  // 字符串操作
  const camelCase = toCamelCase('hello-world-example');
  console.log(camelCase); // 'helloWorldExample'

  const kebabCase = toKebabCase('HelloWorldExample');
  console.log(kebabCase); // 'hello-world-example'

  const capitalized = capitalize('hello world');
  console.log(capitalized); // 'Hello world'

  const truncated = truncate('This is a very long text', 10);
  console.log(truncated); // 'This is a...'

  // 安全操作
  const safeValue = safely(() => JSON.parse('invalid json'), null);
  console.log(safeValue); // null

  const safeAsyncValue = safelyAsync(
    async () => {
      const response = await fetch('/api/data');
      return response.json();
    },
    { error: 'Failed to load' }
  );

  // 类型检查和转换
  const emptyCheck = isEmpty(''); // true
  const numberValue = safeParseInt('123abc', 0); // 123

  return (
    <div>
      <h3>工具函数示例</h3>
      <p>标准化路径: {normalizedPath}</p>
      <p>解析查询: {JSON.stringify(queryParams)}</p>
      <p>构建查询: {queryString}</p>
      <p>唯一数组: {JSON.stringify(uniqueItems)}</p>
      <input
        onChange={(e) => debouncedSearch(e.target.value)}
        placeholder="防抖搜索"
      />
      <div
        onScroll={throttledScroll}
        style={{ height: '100px', overflow: 'scroll' }}
      >
        滚动内容...
      </div>
    </div>
  );
}
```

### 11. 国际化路由集成

```tsx
import {
  createI18nClient,
  createI18nRouteLoader,
  createI18nHandle,
  useRouteI18n
} from '@gulibs/vgrove-client';

// 创建国际化客户端
const i18nClient = createI18nClient({
  defaultLocale: 'zh',
  supportedLocales: ['zh', 'en'],
  basePath: '/api/locales'
});

// 创建路由加载器
const i18nLoader = createI18nRouteLoader(i18nClient, {
  preloadAll: false,
  delay: 0
});

// 路由配置
export const route = {
  path: '/products/:id',
  loader: i18nLoader,
  handle: createI18nHandle({
    meta: {
      title: 'products.detail.title',
      description: 'products.detail.description'
    },
    pageExtras: (context) => {
      const { params, query } = context;

      return (
        <div>
          <ProductBreadcrumb productId={params.id} />
          {query.variant && <VariantSelector variant={query.variant} />}
        </div>
      );
    }
  })
};

// 组件使用
function ProductDetailPage() {
  const {
    locale,
    isLoaded,
    getLocalizedUrl,
    waitForI18n
  } = useRouteI18n();

  const { t } = useI18n();
  const { meta, pageExtras } = useHandle();

  // 等待国际化资源加载
  useEffect(() => {
    waitForI18n().then(() => {
      console.log('国际化资源加载完成');
    });
  }, [waitForI18n]);

  if (!isLoaded) {
    return <div>Loading translations...</div>;
  }

  return (
    <div>
      <h1>{t('products.detail.title')}</h1>
      {/* 动态生成的页面额外内容 */}
      {pageExtras}
      {/* 语言切换按钮 */}
      <button onClick={() => window.location.href = getLocalizedUrl('en')}>
        English
      </button>
    </div>
  );
}
```

### 12. 页面配置和 Hooks

```tsx
import {
  useHandle,
  defineHandle,
  usePageMeta,
  useBreadcrumbs,
  useDocumentTitle
} from '@gulibs/vgrove-client';

// 定义页面处理配置
export const handle = defineHandle({
  meta: {
    title: 'page.title',
    description: '页面描述'
  },
  breadcrumbs: {
    href: '/current-page',
    children: '当前页面'
  },
  // pageExtras 可以是静态内容或函数
  pageExtras: (context) => {
    // 可以访问路由上下文信息
    const { path, params, query, matches, handle } = context;

    return (
      <div>
        <p>当前路径: {path}</p>
        <p>路由参数: {JSON.stringify(params)}</p>
        <p>查询参数: {JSON.stringify(query)}</p>
        <p>匹配的路由数量: {matches.length}</p>
        {params.id && <p>商品ID: {params.id}</p>}
        {query.tab && <p>当前标签: {query.tab}</p>}
      </div>
    );
  }
});

function MyPage() {
  // 获取页面配置
  const { meta, breadcrumbs, pageExtras } = useHandle();

  return (
    <div>
      <h1>{meta?.title}</h1>
      {/* 渲染动态生成的额外内容 */}
      {pageExtras}
      {/* 页面内容 */}
    </div>
  );
}

// 使用页面元数据 Hook
function PageWithMeta() {
  const meta = usePageMeta(handle, { enableI18n: true });
  const updateTitle = useDocumentTitle(handle, 'My App', { enableI18n: true });

  useEffect(() => {
    updateTitle(); // 设置文档标题
  }, [updateTitle]);

  return (
    <div>
      <h1>{meta?.title}</h1>
      <p>{meta?.description}</p>
    </div>
  );
}

// 使用面包屑 Hook
function PageWithBreadcrumbs() {
  const breadcrumbs = useBreadcrumbs(handle, {
    enableI18n: true,
    includeMatches: true
  });

  return (
    <div>
      <nav>
        {breadcrumbs.map((breadcrumb, index) => (
          <span key={index}>
            {index > 0 && ' > '}
            <a href={breadcrumb.href}>{breadcrumb.children}</a>
          </span>
        ))}
      </nav>
      {/* 页面内容 */}
    </div>
  );
}
```

### 13. 综合应用示例

```tsx
import {
  RouteProtectionWrapper,
  I18nProvider,
  useUser,
  useI18n,
  I18nMessage,
  createI18nClient,
  defineAuth,
  defineGuard,
  PerformanceCache,
  useStorage
} from '@gulibs/vgrove-client';

// 创建国际化客户端
const i18nClient = createI18nClient({
  defaultLocale: 'zh',
  supportedLocales: ['zh', 'en'],
  persistence: { enabled: true },
  detectBrowserLanguage: true
});

// 创建缓存
const appCache = new PerformanceCache<string, any>(200);

// 定义认证守卫
const authGuard = defineAuth({
  redirectTo: '/login',
  errorMessage: 'auth.required'
});

// 定义VIP守卫
const vipGuard = defineGuard({
  name: 'vip-only',
  condition: (context) => context.user?.membership === 'VIP',
  redirectTo: '/upgrade',
  errorMessage: 'vip.required'
});

// 主应用组件
function App() {
  return (
    <I18nProvider client={i18nClient}>
      <AppContent />
    </I18nProvider>
  );
}

function AppContent() {
  const { isAuthenticated, user } = useUser({
    storagePrefix: 'myapp',
    autoRefreshInterval: 15 * 60 * 1000,
    loginApi: async (credentials) => {
      const response = await fetch('/api/auth/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(credentials)
      });
      return response.json();
    }
  });

  const { locale, setLocale } = useI18n();
  const [userPreferences, setUserPreferences] = useStorage('user_prefs', {
    theme: 'light',
    notifications: true
  });

  return (
    <div>
      {/* 顶部导航 */}
      <header>
        <I18nMessage id="app.title" defaultValue="我的应用" />
        {isAuthenticated && (
          <span>
            <I18nMessage
              id="welcome.user"
              params={{ name: user?.name }}
              defaultValue="欢迎, {name}!"
            />
          </span>
        )}
        <button onClick={() => setLocale(locale === 'zh' ? 'en' : 'zh')}>
          {locale === 'zh' ? 'English' : '中文'}
        </button>
      </header>

      {/* 主内容区 */}
      <main>
        {/* 公开页面 */}
        <PublicPage />

        {/* 需要认证的页面 */}
        <RouteProtectionWrapper
          guards={[authGuard]}
          loadingElement={
            <I18nMessage id="loading.auth" defaultValue="验证中..." />
          }
          component={<ProtectedPage />}
        />

        {/* 需要VIP权限的页面 */}
        <RouteProtectionWrapper
          guards={[authGuard, vipGuard]}
          loadingElement={
            <I18nMessage id="loading.vip" defaultValue="检查VIP权限..." />
          }
          component={<VIPPage />}
        />
      </main>

      {/* 用户偏好设置 */}
      <aside>
        <h3>
          <I18nMessage id="settings.title" defaultValue="设置" />
        </h3>
        <label>
          <input
            type="checkbox"
            checked={userPreferences.notifications}
            onChange={(e) =>
              setUserPreferences({
                ...userPreferences,
                notifications: e.target.checked
              })
            }
          />
          <I18nMessage id="settings.notifications" defaultValue="启用通知" />
        </label>
      </aside>
    </div>
  );
}

// 公开页面
function PublicPage() {
  return (
    <div>
      <I18nMessage id="public.welcome" defaultValue="欢迎访问我们的网站" />
    </div>
  );
}

// 受保护页面
function ProtectedPage() {
  const { user } = useUser();

  return (
    <div>
      <I18nMessage
        id="protected.welcome"
        params={{ name: user?.name }}
        defaultValue="欢迎进入会员区域, {name}!"
      />
    </div>
  );
}

// VIP页面
function VIPPage() {
  const { user } = useUser();

  return (
    <div>
      <I18nMessage
        id="vip.welcome"
        params={{ name: user?.name }}
        defaultValue="欢迎尊贵的VIP用户, {name}!"
      />
    </div>
  );
}
```

## 🎯 高级用法

### 中间件系统

```tsx
import { defineMiddleware } from '@gulibs/vgrove-client';

const loggingMiddleware = defineMiddleware({
  name: 'logging',
  priority: 10,
  handler: async (context, next) => {
    console.log(`访问页面: ${context.path}`);
    const start = Date.now();

    await next();

    const duration = Date.now() - start;
    console.log(`页面处理耗时: ${duration}ms`);
  }
});

// 全局性能监控中间件
const performanceMiddleware = defineMiddleware({
  name: 'performance',
  priority: 1,
  handler: async (context, next) => {
    if (window.performance) {
      const mark = `route-${context.path}-start`;
      performance.mark(mark);
    }

    await next();

    if (window.performance) {
      const endMark = `route-${context.path}-end`;
      performance.mark(endMark);
      performance.measure(`route-${context.path}`, `route-${context.path}-start`, endMark);
    }
  }
});

<RouteProtectionWrapper
  middlewares={[performanceMiddleware, loggingMiddleware]}
  component={<YourComponent />}
/>
```

### 国际化资源加载器

```tsx
import { createI18nLoader, ViteI18nLoader, createI18nClient } from '@gulibs/vgrove-client';

// 1. 基础资源加载器
const loader = createI18nLoader({
  basePath: '/api/locales',
  extensions: ['.json'],
  cache: true,
  debug: true
});

// 2. 自定义获取函数
const customLoader = createI18nLoader({
  fetchResources: async (locale, path) => {
    const response = await fetch(`/api/i18n/${locale}`);
    if (!response.ok) {
      throw new Error(`Failed to load locale: ${response.statusText}`);
    }
    return response.json();
  },
  onLoad: (locale, data) => {
    console.log(`✅ Loaded ${locale}:`, Object.keys(data));
  },
  onError: (locale, error) => {
    console.error(`❌ Failed to load ${locale}:`, error);
  }
});

// 3. 高级加载器实例
const advancedLoader = new ViteI18nLoader({
  basePath: '/locales',
  cache: true,
  cacheTime: 30 * 60 * 1000, // 30分钟
  debug: process.env.NODE_ENV === 'development'
});

// 4. 与国际化客户端集成
const i18nClient = createI18nClient({
  defaultLocale: 'zh',
  supportedLocales: ['zh', 'en'],
  basePath: '/api/locales',
  cache: true,
  detectBrowserLanguage: true,
  persistence: {
    enabled: true,
    key: 'user_locale',
    storage: 'localStorage'
  }
});

// 5. 手动预加载资源
await loader.preloadResources(['zh', 'en']);

// 6. 检查加载器状态
console.log('Available keys:', loader.getAvailableKeys?.());
console.log('Has key "welcome":', loader.hasKey?.('welcome'));
console.log('Using virtual module:', advancedLoader.isUsingVirtualModule?.());
```

### 复杂路由守卫

```tsx
// 角色守卫
const roleGuard = defineAuth({
  roles: ['admin', 'moderator'],
  redirectTo: '/login',
  errorMessage: '需要以下角色之一: admin, moderator'
});

// 权限守卫
const permissionGuard = defineGuard({
  name: 'permission-user:read,user:write',
  condition: (context) => {
    return context.user?.permissions?.includes('user:read') &&
           context.user?.permissions?.includes('user:write');
  },
  redirectTo: '/forbidden',
  errorMessage: '需要以下权限: user:read, user:write'
});

// 自定义复合守卫
const complexGuard = defineGuard({
  name: 'complex-auth',
  condition: async (context) => {
    // 检查用户是否已认证
    if (!context.user) return false;

    // 检查时间限制
    const now = new Date();
    const workingHours = now.getHours() >= 9 && now.getHours() <= 18;

    // 检查用户类型和时间
    return context.user.type === 'employee' ? workingHours : true;
  },
  redirectTo: '/access-denied',
  errorMessage: '当前时间段无法访问'
});

// 环境守卫
const environmentGuard = defineGuard({
  name: 'environment',
  condition: () => {
    return process.env.NODE_ENV === 'development' ||
           localStorage.getItem('feature_flag_enabled') === 'true';
  },
  redirectTo: '/not-available'
});
```

### 性能优化工具

```tsx
import {
  PerformanceCache,
  BatchProcessor,
  PerformanceTracker,
  MemoryOptimizer
} from '@gulibs/vgrove-client';

// 创建缓存实例
const cache = new PerformanceCache<string, any>(100);

// 批处理器
const processor = new BatchProcessor(5, 100);

// 性能追踪
const tracker = new PerformanceTracker();

// 内存优化器
const memoryOptimizer = MemoryOptimizer.getInstance();

function useOptimizedData() {
  useEffect(() => {
    // 启动性能追踪
    tracker.startTimer('data-loading');

    // 批处理数据加载
    const loadData = async () => {
      const items = ['user', 'settings', 'permissions'];
      const results = await processor.processBatch(
        items,
        async (item) => {
          const cached = cache.get(item);
          if (cached) return cached;

          const data = await fetchData(item);
          cache.set(item, data);
          return data;
        }
      );

      return results;
    };

    loadData().finally(() => {
      const duration = tracker.endTimer('data-loading');
      console.log(`数据加载耗时: ${duration}ms`);
    });

    // 注册清理任务
    memoryOptimizer.addCleanupTask(() => {
      cache.clear();
    });

    return () => {
      memoryOptimizer.runCleanup();
    };
  }, []);
}
```

### 工具函数和实用程序

```tsx
import {
  normalizePath,
  parseQuery,
  buildQuery,
  debounce,
  throttle,
  deepMerge,
  safeParseInt,
  isEmpty,
  measureTime
} from '@gulibs/vgrove-client';

// 路径处理
const normalizedPath = normalizePath('//path//to//page//');
// => '/path/to/page'

// 查询参数处理
const params = parseQuery('?name=john&age=25&active=true');
// => { name: 'john', age: '25', active: 'true' }

const query = buildQuery({ name: 'jane', age: 30 });
// => 'name=jane&age=30'

// 防抖和节流
const debouncedSearch = debounce((query: string) => {
  searchAPI(query);
}, 500);

const throttledScroll = throttle(() => {
  updateScrollPosition();
}, 100);

// 性能测量
const timedFunction = measureTime(expensiveFunction, 'expensive-operation');

// 数据处理
const config = deepMerge(defaultConfig, userConfig);
const count = safeParseInt(userInput, 0);
const hasData = !isEmpty(responseData);
```

## 📖 API 参考

### 路由保护

#### `RouteProtectionWrapper`

路由保护包装器组件。

**Props:**

```typescript
interface RouteProtectionWrapperProps {
  guards?: (AuthOptions | GuardOptions | Function)[];
  middlewares?: (MiddlewareOptions | Function)[];
  loadingElement?: React.ReactNode;
  component: React.ReactNode;
  children?: React.ReactNode;
}
```

#### `defineAuth(options: AuthOptions)`

定义认证守卫。

```typescript
interface AuthOptions {
  name?: string;
  redirectTo?: string;
  errorMessage?: string;
  check?: (context: AuthContext) => boolean | Promise<boolean>;
  roles?: string[];
  permissions?: string[];
}
```

#### `defineGuard(options: GuardOptions)`

定义自定义守卫。

```typescript
interface GuardOptions {
  name?: string;
  type?: 'auth' | 'role' | 'permission' | 'custom';
  redirectTo?: string;
  errorMessage?: string;
  condition: (context: GuardContext) => boolean | Promise<boolean>;
}
```

#### `defineMiddleware(options: MiddlewareOptions)`

定义中间件。

```typescript
interface MiddlewareOptions {
  name?: string;
  priority?: number;
  devOnly?: boolean;
  handler: (context: MiddlewareContext, next: () => Promise<void> | void) => Promise<void> | void;
}
```

### 状态管理

#### `useUser<TUser, TCredentials>(options: UseUserOptions)`

用户状态管理 Hook。

**返回值：**

```typescript
interface AuthState<TUser> & AuthActions<TUser, TCredentials> {
  user: TUser | null;
  token: string | null;
  refreshToken: string | null;
  isAuthenticated: boolean;
  isLoading: boolean;
  error: string | null;
  login: (credentials: TCredentials) => Promise<void>;
  logout: () => void;
  refreshUser: () => Promise<void>;
  refreshTokenAction: () => Promise<void>;
  updateUser: (userData: Partial<TUser>) => void;
  setToken: (token: string) => void;
  setRefreshToken: (refreshToken: string) => void;
  clearError: () => void;
}
```

#### `useStorage<T>(key: string, defaultValue: T, options?)`

基于 @gulibs/react-storage 的通用存储 Hook，支持过期时间。

```typescript
interface UseStorageOptions {
  /** 存储类型 */
  storage?: 'local' | 'session';
  /** 过期时间（毫秒），0 表示永不过期 */
  maxAge?: number;
  /** 是否自动清理过期数据 */
  autoCleanup?: boolean;
  /** 清理间隔（毫秒），默认 5 分钟 */
  cleanupInterval?: number;
}

function useStorage<T>(
  key: string,
  defaultValue: T,
  options?: UseStorageOptions
): [
  T,                                    // 当前值
  (value: T) => void,                   // 设置值函数
  () => void,                           // 移除值函数
  (value: T, maxAge?: number) => void,  // 设置值并指定过期时间
  () => boolean,                        // 检查是否过期
  () => void                            // 清理过期数据
]
```

**返回值：**
- `[0]` - 当前值
- `[1]` - 设置值函数（使用默认过期时间）
- `[2]` - 移除值函数
- `[3]` - 设置值并指定过期时间函数
- `[4]` - 检查是否过期函数
- `[5]` - 手动清理过期数据函数

**示例：**

```typescript
// 基础使用
const [userPrefs, setUserPrefs, removeUserPrefs] = useStorage('user_prefs', {
  theme: 'light'
}, { storage: 'local' });

// 带过期时间（1小时）
const [cache, setCache, removeCache, setCacheWithExpiry, isCacheExpired, cleanupCache] = useStorage(
  'api_cache',
  {},
  {
    storage: 'local',
    maxAge: 60 * 60 * 1000, // 1小时过期
    autoCleanup: true       // 自动清理
  }
);

// 使用指定过期时间设置数据
setCacheWithExpiry({ data: 'temp' }, 5 * 60 * 1000); // 5分钟后过期

// 检查数据是否过期
if (isCacheExpired()) {
  console.log('数据已过期');
}

// 手动清理过期数据
cleanupCache();
```

#### `useUserState<TUser>(storagePrefix?, useSessionStorage?)`

只读用户状态 Hook。

```typescript
function useUserState<TUser = any>(
  storagePrefix?: string,
  useSessionStorage?: boolean
): {
  user: TUser | null;
  token: string | null;
  refreshToken: string | null;
  isAuthenticated: boolean;
}
```

#### `useAuthToken(storagePrefix?, useSessionStorage?)`

Token 管理 Hook。

```typescript
function useAuthToken(
  storagePrefix?: string,
  useSessionStorage?: boolean
): {
  token: string | null;
  refreshToken: string | null;
  setToken: (token: string) => void;
  setRefreshToken: (refreshToken: string) => void;
  clearToken: () => void;
  clearRefreshToken: () => void;
  clearAllTokens: () => void;
  hasToken: boolean;
  hasRefreshToken: boolean;
}
```

### 国际化

#### `I18nProvider`

国际化提供者组件。

```typescript
interface I18nProviderProps {
  children: ReactNode;
  client?: I18nClient | I18nClientConfig;
  defaultLocale?: string;
  locales?: string[];
  loadResources?: (locale: string) => Promise<Record<string, any>>;
  resources?: Record<string, Record<string, any>>;
}
```

#### `I18nMessage`

国际化消息组件，修复了刷新时找不到翻译内容的问题。

```typescript
interface I18nMessageProps<Keys extends string = string> {
  /** 翻译键 - 类型安全，与 @gulibs/vgrove-i18n 生成的类型兼容 */
  id: LocalizedType<Keys>;
  /** 插值参数 */
  params?: Record<string, string | number | boolean>;
  /** 默认值（当翻译不存在时使用） */
  defaultValue?: string;
  /** 渲染格式 */
  format?: 'text' | 'html' | 'markdown' | 'component';
  /** 自定义渲染函数 */
  render?: (text: string) => ReactNode;
  /** 包装元素 */
  as?: keyof React.JSX.IntrinsicElements | React.ComponentType<Record<string, unknown>>;
  /** 自定义类名 */
  className?: string;
}
```

#### `I18nSwitch`

语言切换组件。

```typescript
interface I18nSwitchProps {
  /** 自定义类名 */
  className?: string;
  /** 语言选项，如果不提供则使用可用语言列表 */
  locales?: { code: string; label: string }[];
  /** 是否显示语言标签 */
  showLabels?: boolean;
  /** 切换按钮样式 */
  variant?: 'select' | 'button' | 'tabs';
  /** 语言切换回调 */
  onLocaleChange?: (locale: string) => void;
}
```

#### 便捷组件

```typescript
// 国际化标题
function I18nTitle<Keys extends string = string>(
  props: Omit<I18nMessageProps<Keys>, 'as' | 'format'> & { level?: 1 | 2 | 3 | 4 | 5 | 6 }
): JSX.Element

// 国际化段落
function I18nParagraph<Keys extends string = string>(
  props: Omit<I18nMessageProps<Keys>, 'as' | 'format'>
): JSX.Element

// 国际化文本
function I18nText<Keys extends string = string>(
  props: Omit<I18nMessageProps<Keys>, 'as' | 'format'>
): JSX.Element
```

#### 调试和优化 Hooks

```typescript
// I18nMessage 调试 Hook
function useI18nMessageDebug<Keys extends string = string>(): {
  isReady: boolean;
  locale: string;
  debugInfo: {
    totalKeys: number;
    isUsingVirtualModule: boolean;
    hasKeys: boolean;
  };
  validateKey: (key: string) => {
    exists: boolean;
    ready: boolean;
    locale: string;
  };
}

// I18nMessage 性能优化 Hook
function useI18nMessageMemo<Keys extends string = string>(
  id: LocalizedType<Keys>,
  params?: Record<string, string | number | boolean>,
  defaultValue?: string
): string
```

#### `useI18n()`

国际化 Hook。

```typescript
interface I18nContextType {
  locale: string;
  setLocale: (locale: string) => Promise<void>;
  t: (key: string, params?: Record<string, any>) => string;
  isReady: boolean;
  availableLocales: string[];
  availableKeys: string[];
  hasKey: (key: string) => boolean;
  getNamespaceResources: (namespace: string) => Record<string, any> | undefined;
  isUsingVirtualModule: boolean;
}
```

#### `createI18nClient(config: I18nClientConfig)`

创建国际化客户端。

```typescript
interface I18nClientConfig extends I18nLoaderConfig {
  defaultLocale: string;
  supportedLocales?: string[];
  resources?: Record<string, Record<string, any>>;
  fallbackToDefault?: boolean;
  detectBrowserLanguage?: boolean;
  persistence?: {
    enabled?: boolean;
    key?: string;
    storage?: 'localStorage' | 'sessionStorage';
  };
  interpolation?: {
    prefix?: string;
    suffix?: string;
    escape?: (value: any) => string;
  };
}
```

#### `createI18nLoader(config: I18nLoaderConfig)`

创建资源加载器。

```typescript
interface I18nLoaderConfig {
  basePath?: string;
  extensions?: string[];
  localePattern?: 'directory' | 'filename';
  defaultLocale?: string;
  cacheTime?: number;
  cache?: boolean;
  debug?: boolean;
  onLoad?: (locale: string, data: Record<string, any>) => void;
  onError?: (locale: string, error: Error) => void;
  fetchResources?: (locale: string, path: string) => Promise<Record<string, any>>;
}
```

### 页面配置

#### `usePageConfig<Keys>(handle?, options?)`

获取页面配置。

#### `useI18nPageConfig<Keys>(handle?)`

获取国际化页面配置。

#### `useHandle<Keys>()`

获取当前页面的 handle。

#### `PageExtrasContext` 接口

pageExtras 函数的上下文参数接口。

```typescript
interface PageExtrasContext<Keys extends string = string> {
  /** 当前路由路径 */
  path: string;
  /** 路由参数 */
  params: Record<string, string>;
  /** 查询参数 */
  query: Record<string, string>;
  /** 当前路由匹配信息 */
  matches: UIMatch[];
  /** 当前页面的 handle */
  handle: PageHandle<Keys>;
}
```

**使用示例：**

```typescript
export const handle = defineHandle({
  meta: {
    title: 'products.title'
  },
  pageExtras: (context: PageExtrasContext) => {
    const { path, params, query, matches, handle } = context;

    // 根据路由参数动态生成内容
    if (params.productId) {
      return <ProductBanner productId={params.productId} />;
    }

    // 根据查询参数显示不同内容
    if (query.mode === 'debug') {
      return (
        <DebugInfo
          path={path}
          matches={matches.length}
          handleMeta={handle.meta}
        />
      );
    }

    return null;
  }
});
```

#### `useBreadcrumbs<Keys>(handle?, options?)`

获取面包屑配置。

#### `useDocumentTitle<Keys>(handle?, suffix?, options?)`

设置文档标题。

### 国际化路由集成

#### `createI18nRouteLoader(i18nClient, options?)`

创建国际化路由加载器，用于在路由加载时预加载所需的翻译资源。

```typescript
function createI18nRouteLoader(
  i18nClient: I18nClient,
  options?: I18nRouteLoaderOptions
): (args: LoaderFunctionArgs) => Promise<RouteI18nData>

interface I18nRouteLoaderOptions {
  /** 要预加载的语言列表，默认使用当前语言 */
  locales?: string[];
  /** 是否预加载所有支持的语言 */
  preloadAll?: boolean;
  /** 延迟加载时间（毫秒），用于演示加载状态 */
  delay?: number;
}
```

#### `useRouteI18n()`

在组件中使用路由国际化数据的 Hook。

```typescript
function useRouteI18n(): {
  /** 当前语言 */
  locale: string;
  /** 国际化资源是否已加载 */
  isLoaded: boolean;
  /** 获取当前路径的语言参数 */
  getLocaleFromPath: () => string | null;
  /** 切换语言的 URL 生成器 */
  getLocalizedUrl: (newLocale: string) => string;
  /** 等待国际化资源加载完成 */
  waitForI18n: () => Promise<void>;
}
```

#### `createI18nHandle<Keys>(baseHandle?)`

创建支持国际化的页面处理配置。

```typescript
function createI18nHandle<Keys extends string = string>(
  baseHandle?: Partial<PageHandle<Keys>>
): I18nHandle<Keys>

interface I18nHandle<Keys extends string = string> extends PageHandle<Keys> {
  /** 标记为需要国际化处理 */
  i18n: boolean;
  /** 国际化元数据处理器 */
  getI18nMeta?: (t: (key: string) => string) => {
    title?: string;
    description?: string;
    [key: string]: any;
  };
}
```

#### `enhanceRoutesWithI18n(routes, i18nClient, options?)`

为现有路由配置添加国际化支持。

```typescript
function enhanceRoutesWithI18n(
  routes: any[],
  i18nClient: I18nClient,
  options?: EnhanceRoutesI18nOptions
): any[]

interface EnhanceRoutesI18nOptions {
  /** 是否为所有路由添加国际化 loader */
  autoAddLoader?: boolean;
}
```

### 性能优化

#### `PerformanceCache<K, V>`

高性能 LRU 缓存。

```typescript
class PerformanceCache<K, V> {
  constructor(maxSize: number = 100);
  get(key: K): V | undefined;
  set(key: K, value: V): void;
  has(key: K): boolean;
  delete(key: K): boolean;
  clear(): void;
  size(): number;
}
```

#### `BatchProcessor`

批处理器。

```typescript
class BatchProcessor {
  constructor(batchSize: number = 10, delay: number = 50);
  async processBatch<T, R>(
    items: T[],
    processor: (item: T) => Promise<R>
  ): Promise<R[]>;
}
```

#### `PerformanceTracker`

性能追踪器。

```typescript
class PerformanceTracker {
  startTimer(name: string): void;
  endTimer(name: string): number;
  increment(name: string): void;
  getCounter(name: string): number;
  reset(): void;
  getStats(): Record<string, any>;
}
```

#### `MemoryOptimizer`

内存优化器（单例模式）。

```typescript
class MemoryOptimizer {
  static getInstance(): MemoryOptimizer;
  addCleanupTask(task: () => void): void;
  startPeriodicCleanup(intervalMs?: number): void;
  runCleanup(): void;
  dispose(): void;
}
```

#### `Debouncer`

防抖器。

```typescript
class Debouncer {
  debounce(key: string, fn: () => void, delay: number): void;
  cancel(key: string): void;
  cancelAll(): void;
}
```

### 工具函数 API

#### 路径和 URL 工具

```typescript
// 路径标准化
function normalizePath(path: string): string;

// 路径连接
function joinPath(...segments: string[]): string;

// 路径匹配
function matchPath(pattern: string, path: string): boolean;

// 参数提取
function extractParams(pattern: string, path: string): Record<string, string>;

// 查询参数解析
function parseQuery(search: string): Record<string, string>;

// 查询参数构建
function buildQuery(params: Record<string, any>): string;

// URL 查询参数更新
function updateQuery(url: string, params: Record<string, any>): string;
```

#### 数据处理工具

```typescript
// 深拷贝
function deepClone<T>(obj: T): T;

// 深度合并
function deepMerge<T extends Record<string, any>>(target: T, source: Partial<T>): T;

// 数组去重
function unique<T>(array: T[], keyFn?: (item: T) => any): T[];

// 数组分组
function groupBy<T>(array: T[], keyFn: (item: T) => string): Record<string, T[]>;

// 数组映射为数组
function mapToArray<K, V>(map: Map<K, V>): V[];
```

#### 字符串工具

```typescript
// 转换为驼峰命名
function toCamelCase(str: string): string;

// 转换为短横线命名
function toKebabCase(str: string): string;

// 首字母大写
function capitalize(str: string): string;

// 字符串截断
function truncate(str: string, length: number, suffix?: string): string;
```

#### 类型检查和安全工具

```typescript
// 空值检查
function isEmpty(value: any): boolean;

// 函数检查
function isFunction(value: any): value is Function;

// Promise 检查
function isPromise(value: any): value is Promise<any>;

// 记录对象检查
function isRecord(obj: any): obj is Record<string, any>;

// 安全整数解析
function safeParseInt(value: any, defaultValue?: number): number;

// 安全执行
function safely<T>(fn: () => T, fallback: T): T;

// 安全异步执行
function safelyAsync<T>(fn: () => Promise<T>, fallback: T): Promise<T>;
```

#### 性能和缓存工具

```typescript
// 防抖函数
function debounce<T extends (...args: any[]) => void>(
  fn: T,
  delay: number
): T;

// 节流函数
function throttle<T extends (...args: any[]) => void>(
  fn: T,
  delay: number
): T;

// 性能测量
function measureTime<T extends (...args: any[]) => any>(
  fn: T,
  name?: string
): T;

// 异步性能测量
function measureAsync<T>(
  name: string,
  fn: () => Promise<T>
): Promise<T & { duration: number }>;

// 简单缓存类
class SimpleCache<K, V> {
  constructor(maxAge?: number, maxSize?: number);
  set(key: K, value: V): void;
  get(key: K): V | undefined;
  has(key: K): boolean;
  delete(key: K): boolean;
  clear(): void;
}
```

## 🏆 最佳实践

### 1. I18nMessage 组件最佳实践

```tsx

// ✅ 推荐：总是提供默认值
function GoodExample() {
  return (
    <I18nMessage
      id="welcome.title"
      defaultValue="欢迎"
      params={{ name: '用户' }}
    />
  );
}

// ❌ 避免：不提供默认值
function BadExample() {
  return <I18nMessage id="welcome.title" />;
}

// ✅ 推荐：使用调试工具进行开发
function DebugExample() {
  const { validateKey, debugInfo } = useI18nMessageDebug();

  useEffect(() => {
    // 开发环境下验证翻译键
    if (process.env.NODE_ENV === 'development') {
      const validation = validateKey('welcome.title');
      if (!validation.exists) {
        console.warn('翻译键不存在：', 'welcome.title');
      }
    }
  }, [validateKey]);

  return (
    <div>
      <I18nMessage id="welcome.title" defaultValue="欢迎" />
      {process.env.NODE_ENV === 'development' && (
        <pre>{JSON.stringify(debugInfo, null, 2)}</pre>
      )}
    </div>
  );
}

// ✅ 推荐：使用性能优化 Hook 处理复杂逻辑
function OptimizedExample() {
  const translatedText = useI18nMessageMemo(
    'complex.message',
    { count: 100, type: 'items' },
    '默认消息'
  );

  return (
    <div>
      <span>{translatedText}</span>
      {/* 避免在渲染中直接使用 t 函数进行复杂计算 */}
    </div>
  );
}

// ✅ 推荐：组合使用便捷组件
function PageLayout() {
  return (
    <div>
      <I18nTitle id="page.title" level={1} />
      <I18nText id="page.subtitle" className="text-gray-600" />

      <I18nMessage
        id="rich.content"
        format="markdown"
        defaultValue="支持 **粗体** 和 *斜体*"
      />

      <I18nSwitch
        variant="tabs"
        onLocaleChange={(locale) => {
          // 可选：语言切换时的额外逻辑
          console.log(`语言切换到: ${locale}`);
        }}
      />
    </div>
  );
}

```

### 2. 国际化路由集成最佳实践

```tsx

// i18n/routes.ts
import { createI18nClient, createI18nRouteLoader, createI18nHandle } from '@gulibs/vgrove-client';

// 创建国际化客户端
const i18nClient = createI18nClient({
  defaultLocale: 'zh',
  supportedLocales: ['zh', 'en'],
  basePath: '/api/locales',
  cache: true
});

// 创建国际化路由加载器
export const i18nLoader = createI18nRouteLoader(i18nClient, {
  preloadAll: false,
  delay: 0 // 生产环境不需要延迟
});

// 路由配置
export const routes = [
  {
    path: '/dashboard',
    loader: i18nLoader,
    handle: createI18nHandle({
      meta: {
        title: 'dashboard.title',
        description: 'dashboard.description'
      },
      pageExtras: (context) => {
        return <DashboardBreadcrumb path={context.path} />;
      }
    })
  }
];

// 组件中使用
function DashboardPage() {
  const { locale, isLoaded, getLocalizedUrl } = useRouteI18n();
  const { t } = useI18n();

  if (!isLoaded) {
    return <div>加载中。..</div>;
  }

  return (
    <div>
      <h1>{t('dashboard.title')}</h1>
      <button onClick={() => window.location.href = getLocalizedUrl('en')}>
        Switch to English
      </button>
    </div>
  );
}

```

### 3. 路由守卫组织

```tsx

// guards/index.ts
export const authGuard = defineAuth({
  redirectTo: '/login',
  errorMessage: '请先登录'
});

export const adminGuard = defineAuth({
  roles: ['admin'],
  redirectTo: '/forbidden',
  errorMessage: '需要管理员权限'
});

export const premiumGuard = defineGuard({
  name: 'premium',
  condition: (context) => context.user?.isPremium,
  redirectTo: '/upgrade',
  errorMessage: '需要升级到高级版'
});

// guards/factory.ts
export function createRoleGuard(roles: string[], redirectTo = '/forbidden') {
  return defineAuth({
    roles,
    redirectTo,
    errorMessage: `需要以下角色之一: ${roles.join(', ')}`
  });
}

export function createPermissionGuard(permissions: string[], redirectTo = '/forbidden') {
  return defineGuard({
    name: `permission-${permissions.join('-')}`,
    condition: (context) => {
      return permissions.every(permission =>
        context.user?.permissions?.includes(permission)
      );
    },
    redirectTo,
    errorMessage: `需要以下权限: ${permissions.join(', ')}`