npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@gulibs/vgrove-client

v0.0.170

Published

Client-side utilities for React auto routes

Downloads

250

Readme

@gulibs/vgrove-client

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

✨ 特性

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

📦 安装

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

对等依赖

npm install react react-dom react-router lodash

🚀 快速开始

0. 配置管理(推荐) ⚠️

⚠️ 重要:安全设计

  • 调试功能默认全部关闭,包括开发环境
  • 必须显式启用调试才能看到相关日志
  • 这避免了意外暴露敏感信息到调试日志中

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

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' // 只在开发环境启用
});

使用浏览器开发者工具(开发环境):

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

1. 路由保护

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. 用户状态管理

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 文件为空或无实际保护需求时,系统会自动启用快速通道,避免不必要的状态转换:

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

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

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

3.2 布局抖动解决方案

问题描述:空配置文件导致页面经历 checkingpassed 状态转换,造成布局抖动。

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

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 调试性能监控

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

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

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

3.5 验证修复效果

// 验证工具:检查页面是否使用了快速通道
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. 国际化支持

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. 存储管理

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

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. 路由保护的不同形式

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

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

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;
    }
});

❌ 常见错误:

// 错误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
}

✅ 正确用法:

// 同步检查
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 ⭐

推荐使用!自动处理循环重定向,防止常见错误

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;
    }
});

内置公共路径列表:

// 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

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

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

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

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

基于用户角色的访问控制

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

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

3. 权限守卫 - definePermissionGuard

基于具体权限的访问控制

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

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

4. 守卫工厂函数

快速创建常用的守卫

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

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

完整示例:

// 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:循环重定向死循环

症状: 页面不断重定向,浏览器显示"重定向次数过多"

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

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

解决方案:

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

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

错误 2:守卫执行顺序混乱

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

// ❌ 错误:在需要认证的页面只设置守卫
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. 认证状态管理

// 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. 调试和开发工具

// 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;
    }
});

🔧 调试指南

浏览器控制台调试命令

// 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
  • ✅ 错误处理要提供用户友好的提示

💡 提示: 对于初学者,建议先使用 defineSmartAuthdefineRoleGuard,它们内置了大部分常见错误的处理逻辑。

7. 高级国际化 Hooks

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 组件

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. 性能优化工具详细示例

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. 工具函数详细示例

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. 国际化路由集成

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

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. 综合应用示例

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>
  );
}

🎯 高级用法

中间件系统

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 />}
/>

国际化资源加载器

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?.());

复杂路由守卫

// 角色守卫
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'
});

性能优化工具

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();
    };
  }, []);
}

工具函数和实用程序

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:

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

defineAuth(options: AuthOptions)

定义认证守卫。

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

defineGuard(options: GuardOptions)

定义自定义守卫。

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

defineMiddleware(options: MiddlewareOptions)

定义中间件。

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

状态管理

useUser<TUser, TCredentials>(options: UseUserOptions)

用户状态管理 Hook。

返回值:

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,支持过期时间。

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] - 手动清理过期数据函数

示例:

// 基础使用
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。

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

useAuthToken(storagePrefix?, useSessionStorage?)

Token 管理 Hook。

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

国际化提供者组件。

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

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

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

语言切换组件。

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

便捷组件

// 国际化标题
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

// 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。

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)

创建国际化客户端。

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)

创建资源加载器。

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 函数的上下文参数接口。

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

使用示例:

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?)

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

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

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

useRouteI18n()

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

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

createI18nHandle<Keys>(baseHandle?)

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

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?)

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

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

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

性能优化

PerformanceCache<K, V>

高性能 LRU 缓存。

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

批处理器。

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

PerformanceTracker

性能追踪器。

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

内存优化器(单例模式)。

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

Debouncer

防抖器。

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

工具函数 API

路径和 URL 工具

// 路径标准化
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;

数据处理工具

// 深拷贝
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[];

字符串工具

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

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

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

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

类型检查和安全工具

// 空值检查
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>;

性能和缓存工具

// 防抖函数
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 组件最佳实践


// ✅ 推荐:总是提供默认值
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. 国际化路由集成最佳实践


// 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. 路由守卫组织


// 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(', ')}`