npm package: @gulibs/vite-plugin-react-auto-routes
Description: 一个基于文件系统的自动路由生成 Vite 插件，为 React 应用程序提供基于文件系统的自动路由生成功能
Author: HectorGu
Latest version: 0.2.8
Deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.

# @gulibs/vite-plugin-react-auto-routes

一个基于文件系统的自动路由生成 Vite 插件，为 React 应用程序提供基于文件系统的自动路由生成功能，支持路由守卫、中间件、性能优化等高级特性。

[![npm version](https://badge.fury.io/js/@gulibs%2Fvite-plugin-react-auto-routes.svg)](https://badge.fury.io/js/@gulibs%2Fvite-plugin-react-auto-routes)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## 📚 目录

- [功能特性](#-功能特性)
- [性能表现](#-性能表现)
- [快速开始](#-快速开始)
- [应用程序入口配置](#-应用程序入口配置)
- [文件系统路由](#-文件系统路由)
- [路由守卫](#-路由守卫)
- [中间件](#-中间件)
- [性能监控](#-性能监控)
- [React Hooks](#-react-hooks)
- [用户状态管理](#用户状态管理)
- [配置选项](#-配置选项)
- [示例项目](#-示例项目)
- [调试和开发](#-调试和开发)
- [高级用法](#-高级用法)
- [导出模块](#-导出模块)
- [许可证](#-许可证)

## ✨ 功能特性

### 🚀 核心功能

- **基于文件系统的路由生成**：根据文件结构自动生成路由，零配置即可使用
- **动态路由支持**：支持 `[param]`（单参数）和 `[...slug]`（通配符）语法
- **嵌套路由**：支持布局组件和多层嵌套路由结构
- **TypeScript 支持**：完整的类型定义和 IntelliSense 支持，开发体验更佳

### 🛡️ 高级功能

- **路由守卫**：基于角色和权限的访问控制，支持自定义守卫条件
- **中间件支持**：路由级中间件处理，支持全局和局部中间件
- **用户认证**：内置认证守卫和用户状态管理，支持双 Token 机制
- **错误处理**：优雅的错误边界和 404 页面处理，提升用户体验

### ⚡ 性能优化

- **智能缓存**：LRU 缓存策略，自动检测文件变更
- **并行处理**：多目录并行路由生成，大幅提升构建速度
- **防抖节流**：避免频繁重新构建，优化开发体验
- **内存优化**：自动垃圾回收和清理机制
- **性能监控**：内置性能追踪器，实时监控执行时间

### 🎯 开发体验

- **热重载**：文件变更自动更新路由，无需重启开发服务器
- **调试模式**：详细的路由生成日志和性能统计
- **错误提示**：友好的错误信息和修复建议
- **IDE 支持**：完整的代码补全和类型检查

## 📊 性能表现

基于文件系统的路由生成，具有以下优势：

- **快速构建**：增量式路由生成，只处理变更文件
- **智能缓存**：自动缓存路由配置，减少重复解析
- **并行处理**：多文件并行解析，提升大项目构建速度
- **内存优化**：按需加载路由组件，减少内存占用

## 🚀 快速开始

### 安装

```bash
npm install @gulibs/vite-plugin-react-auto-routes
# 或
yarn add @gulibs/vite-plugin-react-auto-routes
# 或
pnpm add @gulibs/vite-plugin-react-auto-routes
```

> **注意**：从 v0.2.5 开始，客户端功能（如 `RouteProtectionWrapper`、hooks 等）已分离到独立的包 `@gulibs/auto-routes-client`。如果您需要使用路由保护、中间件或其他客户端功能，请同时安装：

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

### 基础配置

在`vite.config.ts`中配置插件：

```typescript
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import reactAutoRoutes from '@gulibs/vite-plugin-react-auto-routes'

export default defineConfig({
  plugins: [
    react(),
    reactAutoRoutes({
      dirs: [
        {
          dir: 'src/pages',
          baseRoute: '/'
        }
      ]
    })
  ]
})
```

在`vite-env.d.ts`中配置

```typescript
/// <reference types="vite/client" />
/// <reference types="@gulibs/vite-plugin-react-auto-routes/react-routes" />
```

### 高级配置

```typescript
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import reactAutoRoutes from '@gulibs/vite-plugin-react-auto-routes'

export default defineConfig({
  plugins: [
    react(),
    reactAutoRoutes({
      dirs: [
        {
          dir: 'src/pages',
          baseRoute: '/',
          include: ['**/*.tsx', '**/*.ts'],
          exclude: ['**/components/**', '**/*.test.*']
        }
      ],
      // 基础配置
      cache: true,
      cacheTime: 60000, // 1分钟缓存
      debug: true,
      dynamic: false,
      routeMode: 'flat' // 'flat' | 'nested'
    })
  ]
})
```

### 使用路由

```typescript
// src/App.tsx
import { Routes, Route } from 'react-router'
import { routes } from 'virtual:react-routes'

function App() {
  return (
    <Routes>
      {routes.map((route, index) => (
        <Route key={index} {...route} />
      ))}
    </Routes>
  )
}
```

## 🎯 应用程序入口配置

### 基础配置

在应用程序的主入口文件（通常是 `src/main.tsx`）中，您需要导入自动生成的路由并配置 React Router。

```typescript
// src/main.tsx
import { createRoot } from 'react-dom/client';
import { createBrowserRouter, RouterProvider } from 'react-router';
import { routes } from "~react-auto-pages";
import './index.css';

// 创建浏览器路由器
const router = createBrowserRouter(routes);

const root = createRoot(document.getElementById('root')!)

root.render(
  <RouterProvider router={router} />
)
```

### 不同路由器类型配置

根据您的应用需求，可以选择不同类型的路由器：

#### 浏览器路由器（推荐）

```typescript
// src/main.tsx
import { createRoot } from 'react-dom/client';
import { createBrowserRouter, RouterProvider } from 'react-router';
import { routes } from "~react-auto-pages";

const router = createBrowserRouter(routes);

const root = createRoot(document.getElementById('root')!)
root.render(<RouterProvider router={router} />)
```

#### 哈希路由器

适用于不支持 HTML5 History API 的环境：

```typescript
// src/main.tsx
import { createRoot } from 'react-dom/client';
import { createHashRouter, RouterProvider } from 'react-router';
import { routes } from "~react-auto-pages";

const router = createHashRouter(routes);

const root = createRoot(document.getElementById('root')!)
root.render(<RouterProvider router={router} />)
```

#### 内存路由器

适用于测试环境或非浏览器环境：

```typescript
// src/main.tsx
import { createRoot } from 'react-dom/client';
import { createMemoryRouter, RouterProvider } from 'react-router';
import { routes } from "~react-auto-pages";

const router = createMemoryRouter(routes, {
  initialEntries: ['/'], // 初始路由
  initialIndex: 0
});

const root = createRoot(document.getElementById('root')!)
root.render(<RouterProvider router={router} />)
```

### 完整配置示例

结合状态管理、SEO 优化等功能的完整配置：

```typescript
// src/main.tsx
import { createRoot } from 'react-dom/client';
import { HelmetProvider } from 'react-helmet-async';
import { createHashRouter, RouterProvider } from 'react-router';
import { RecoilRoot } from 'recoil';

import { routes } from "~react-auto-pages";
import './index.css';

// 创建路由器
const router = createHashRouter(routes);

const root = createRoot(document.getElementById('root')!)

root.render(
  <RecoilRoot>
    <HelmetProvider>
      <RouterProvider router={router} />
    </HelmetProvider>
  </RecoilRoot>
)
```

### 添加全局错误边界

为了更好的用户体验，建议添加全局错误边界：

```typescript
// src/main.tsx
import { createRoot } from 'react-dom/client';
import { createBrowserRouter, RouterProvider } from 'react-router';
import { ErrorBoundary } from 'react-error-boundary';
import { routes } from "~react-auto-pages";

const router = createBrowserRouter(routes);

function ErrorFallback({error, resetErrorBoundary}) {
  return (
    <div className="error-fallback">
      <h2>出现了错误</h2>
      <pre>{error.message}</pre>
      <button onClick={resetErrorBoundary}>重试</button>
    </div>
  )
}

const root = createRoot(document.getElementById('root')!)

root.render(
  <ErrorBoundary
    FallbackComponent={ErrorFallback}
    onError={(error) => console.error('Application error:', error)}
  >
    <RouterProvider router={router} />
  </ErrorBoundary>
)
```

### 路由器配置选项

您可以为路由器添加额外的配置选项：

```typescript
// src/main.tsx
import { createBrowserRouter, RouterProvider } from 'react-router';
import { routes } from "~react-auto-pages";

const router = createBrowserRouter(routes, {
  // 基础路径配置
  basename: process.env.NODE_ENV === 'production' ? '/my-app' : '/',

  // 未来路由配置
  future: {
    v7_startTransition: true,
    v7_normalizeFormMethod: true
  }
});

// 添加路由监听器
router.subscribe((state) => {
  console.log('Route changed:', state.location.pathname);
});

const root = createRoot(document.getElementById('root')!)
root.render(<RouterProvider router={router} />)
```

### 开发环境调试

在开发环境中，您可以添加一些调试功能：

main.tsx

```typescript
// src/main.tsx
import { createRoot } from 'react-dom/client';
import { createBrowserRouter, RouterProvider } from 'react-router';
import { routes } from "~react-auto-pages";

const router = createBrowserRouter(routes);

// 开发环境路由调试
if (process.env.NODE_ENV === 'development') {
  console.log('Generated routes:', routes);

  // 监听路由变化
  router.subscribe((state) => {
    console.log('Navigation:', {
      pathname: state.location.pathname,
      search: state.location.search,
      hash: state.location.hash
    });
  });
}

const root = createRoot(document.getElementById('root')!)
root.render(<RouterProvider router={router} />)
```

```typescript

```

## 📁 文件系统路由

### 约定式路由规则

React Auto Routes 遵循以下文件系统路由约定：

#### 支持的文件类型

| 文件类型 | 文件名约定 | 说明 |
|---------|------------|------|
| **页面组件** | `page.tsx`, `page.ts`, `index.tsx`, `index.ts` | 定义路由页面组件 |
| **布局组件** | `layout.tsx`, `layout.ts`, `_layout.tsx`, `_layout.ts` | 定义嵌套布局 |
| **错误页面** | `error.tsx`, `404.tsx`, `_error.tsx` | 错误边界和 404 页面 |
| **加载组件** | `loading.tsx`, `_loading.tsx` | 加载状态组件 |
| **路由处理器** | `handle.ts`, `_handle.ts` | 路由数据处理 |
| **中间件** | `middleware.ts`, `_middleware.ts` | 路由中间件 |
| **路由守卫** | `guard.ts`, `_guard.ts` | 路由守卫 |
| **认证守卫** | `auth.ts`, `_auth.ts` | 认证检查 |

#### 动态路由约定

| 路由模式 | 文件路径 | 生成路由 | 说明 |
|---------|----------|----------|------|
| **基础路由** | `src/pages/about/page.tsx` | `/about` | 静态路由 |
| **单参数路由** | `src/pages/users/[id]/page.tsx` | `/users/:id` | 动态参数 |
| **多参数路由** | `src/pages/blog/[year]/[month]/page.tsx` | `/blog/:year/:month` | 多个参数 |
| **通配符路由** | `src/pages/docs/[...slug]/page.tsx` | `/docs/*` | 捕获所有 |

#### 文件优先级

当同一目录下存在多个文件时，按以下优先级处理：

1. `page.tsx` > `index.tsx` > `page.ts` > `index.ts`
2. `layout.tsx` > `_layout.tsx` > `layout.ts` > `_layout.ts`
3. `error.tsx` > `404.tsx` > `_error.tsx`

### 基本路由

```
src/pages/
├── page.tsx          # / (首页)
├── about/
│   └── page.tsx      # /about
├── contact/
│   └── page.tsx      # /contact
└── 404.tsx           # 404 页面
```

### 动态路由

```
src/pages/
├── users/
│   ├── page.tsx      # /users
│   └── [id]/
│       └── page.tsx  # /users/:id
├── blog/
│   ├── page.tsx      # /blog
│   └── [slug]/
│       └── page.tsx  # /blog/:slug
└── docs/
    └── [...path]/
        └── page.tsx  # /docs/* (通配符路由)
```

### 嵌套路由和布局

```
src/pages/
├── layout.tsx        # 根布局
├── page.tsx          # /
├── admin/
│   ├── layout.tsx    # 管理布局
│   ├── page.tsx      # /admin
│   ├── users/
│   │   └── page.tsx  # /admin/users
│   └── settings/
│       └── page.tsx  # /admin/settings
```

### 特殊文件

```
src/pages/
├── layout.tsx        # 布局组件
├── error.tsx         # 错误边界
├── loading.tsx       # 加载组件
├── handle.ts         # 路由处理器
├── middleware.ts     # 中间件
├── guard.ts          # 路由守卫
└── auth.ts           # 认证守卫
```

## 🛡️ 路由守卫

### 定义守卫

```typescript
// src/pages/admin/guard.ts
import { defineGuard } from '@gulibs/auto-routes-client'

export default defineGuard({
  name: 'admin-guard',
  type: 'role',
  redirectTo: '/403',
  errorMessage: '需要管理员权限',
  condition: (context) => {
    return context.user?.role === 'admin'
  }
})
```

### 认证守卫

```typescript
// src/pages/profile/auth.ts
import { defineAuth } from '@gulibs/auto-routes-client'

export default defineAuth({
  name: 'auth-check',
  redirectTo: '/login',
  errorMessage: '请先登录',
  check: (context) => !!context.user,
  roles: ['user', 'admin'],
  permissions: ['read']
})
```

### GuardOptions 接口

```typescript
interface GuardOptions {
  /** 守卫名称 */
  name?: string;
  /** 守卫类型 */
  type?: 'auth' | 'role' | 'permission' | 'custom';
  /** 访问被拒绝时的重定向路径 */
  redirectTo?: string;
  /** 错误信息 */
  errorMessage?: string;
  /** 守卫条件函数 */
  condition: (context: GuardContext) => boolean | Promise<boolean>;
}
```

## 🔧 中间件

### 定义中间件

```typescript
// src/pages/blog/middleware.ts
import { defineMiddleware } from '@gulibs/auto-routes-client'

export default defineMiddleware({
  name: 'blog-logger',
  handler: async (context, next) => {
    console.log(`访问博客: ${context.path}`)

    // 执行下一个中间件
    await next()
  }
})
```

### MiddlewareOptions 接口

```typescript
interface MiddlewareOptions {
  /** 中间件名称 */
  name?: string;
  /** 执行优先级（数字越小越先执行）*/
  priority?: number;
  /** 是否仅在开发环境执行 */
  devOnly?: boolean;
  /** 中间件处理函数 */
  handler: (context: MiddlewareContext, next: () => Promise<void> | void) => Promise<void> | void;
}
```

### 全局中间件

```typescript
// src/middleware/logger.ts
export default defineMiddleware({
  name: 'global-logger',
  handler: async (context, next) => {
    const start = Date.now()

    try {
      await next()
    } finally {
      const duration = Date.now() - start
      console.log(`[${context.path}] ${duration}ms`)
    }
  },
  priority: 0
})
```

## 📈 性能监控

### 使用性能追踪

```typescript
import { globalPerformanceTracker } from '@gulibs/vite-plugin-react-auto-routes/performance'

// 启动性能监控
globalPerformanceTracker.startTimer('route_generation')

// 结束监控
const duration = globalPerformanceTracker.endTimer('route_generation')

// 获取统计数据
const stats = globalPerformanceTracker.getStats()
console.log('性能统计:', stats)
```

### 性能优化建议

```typescript
// 开发环境配置
{
  cache: true,
  cacheTime: 10000, // 10秒快速响应
  debug: true,
  performance: {
    enableRouteCache: true,
    routeCacheSize: 50,
    debounceDelay: 200,
    enablePerformanceTracking: true
  }
}

// 生产环境配置
{
  cache: true,
  cacheTime: 300000, // 5分钟长缓存
  debug: false,
  performance: {
    enableRouteCache: true,
    routeCacheSize: 500,
    enableGuardCache: true,
    guardCacheSize: 200,
    enableParallelProcessing: true,
    enableMemoryOptimization: true
  }
}
```

## 🎯 React Hooks

### useRouteProtection

综合的路由保护 Hook：

```typescript
import { useRouteProtection } from '@gulibs/vite-plugin-react-auto-routes/hooks'

function MyComponent() {
  const { isLoading, guardError, user, hasAccess, performanceStats } = useRouteProtection(
    guards,
    middlewares
  )

  return (
    <div>
      {isLoading && <div>加载中...</div>}
      {guardError && <div>错误: {guardError}</div>}
      {hasAccess && <div>欢迎, {user?.name}!</div>}
    </div>
  )
}
```

### useRouteGuards

专门的守卫 Hook：

```typescript
import { useRouteGuards } from '@gulibs/vite-plugin-react-auto-routes/hooks'

function GuardedComponent({ guards }: { guards: any[] }) {
  const { isChecking, guardError, hasAccess, retryCheck } = useRouteGuards(guards)

  if (isChecking) return <div>检查权限...</div>
  if (!hasAccess) return <div>访问被拒绝: {guardError}</div>

  return <div>内容</div>
}
```

### useRouteMiddleware

中间件执行 Hook：

```typescript
import { useRouteMiddleware } from '@gulibs/vite-plugin-react-auto-routes/hooks'

function MiddlewareComponent({ middlewares }: { middlewares: any[] }) {
  const { isExecuting, executionTime, middlewareError, executeAgain } = useRouteMiddleware(middlewares)

  return (
    <div>
      {isExecuting && <div>执行中间件...</div>}
      {executionTime && <div>执行时间: {executionTime}ms</div>}
      {middlewareError && (
        <div>
          中间件错误: {middlewareError}
          <button onClick={executeAgain}>重试</button>
        </div>
      )}
    </div>
  )
}
```

### usePageConfig

页面配置综合 Hook：

```typescript
import { usePageConfig } from '@gulibs/vite-plugin-react-auto-routes/hooks'

function PageLayout() {
  const { breadcrumbs, meta, layoutSettings, handle } = usePageConfig()

  return (
    <div>
      {/* 面包屑导航 */}
      <nav className="breadcrumbs">
        {breadcrumbs.map((item, index) => (
          <a key={index} href={item.href} className={item.className}>
            {item.startContent}
            {item.children}
            {item.endContent}
          </a>
        ))}
      </nav>

      {/* 页面标题 */}
      <h1>{meta?.title}</h1>
      <p>{meta?.description}</p>

      {/* 根据布局设置调整页面 */}
      <main className={layoutSettings?.layout ? 'with-layout' : 'no-layout'}>
        {/* 页面内容 */}
      </main>

      {/* 页脚 */}
      {layoutSettings?.footer && <footer>页脚内容</footer>}
    </div>
  )
}
```

### useHandle

获取页面 Handle 配置：

```typescript
import { useHandle } from '@gulibs/vite-plugin-react-auto-routes/hooks'

function PageComponent() {
  const { meta, extras, layoutSettings, breadcrumbs, matches } = useHandle()

  return (
    <div>
      <h1>{meta?.title}</h1>

      {/* 渲染额外内容 */}
      {extras}

      {/* 显示当前匹配的路由信息 */}
      <div>
        当前路由层级: {matches?.length}
      </div>
    </div>
  )
}
```

### useBreadcrumbs

面包屑导航 Hook：

```typescript
import { useBreadcrumbs } from '@gulibs/vite-plugin-react-auto-routes/hooks'

function BreadcrumbNav({ handle }) {
  const breadcrumbs = useBreadcrumbs(handle)

  if (breadcrumbs.length === 0) return null

  return (
    <nav className="breadcrumb-nav">
      {breadcrumbs.map((crumb, index) => (
        <div key={index} className="breadcrumb-item">
          {crumb.startContent}
          <a
            href={crumb.href}
            className={crumb.className}
            aria-disabled={crumb.isDisabled}
            aria-current={crumb.isCurrent ? 'page' : undefined}
          >
            {crumb.children}
          </a>
          {crumb.endContent}
        </div>
      ))}
    </nav>
  )
}
```

### usePageMeta 和 useLayoutSettings

单独使用元数据和布局设置：

```typescript
import { usePageMeta, useLayoutSettings } from '@gulibs/vite-plugin-react-auto-routes/hooks'

function DocumentHead() {
  const meta = usePageMeta()

  useEffect(() => {
    if (meta?.title) {
      document.title = meta.title
    }

    if (meta?.description) {
      const metaDesc = document.querySelector('meta[name="description"]')
      if (metaDesc) {
        metaDesc.setAttribute('content', meta.description)
      }
    }
  }, [meta])

  return null
}

function LayoutController() {
  const layoutSettings = useLayoutSettings()

  return (
    <div className={`page-container ${layoutSettings?.layout ? 'with-layout' : 'simple-layout'}`}>
      {/* 根据布局设置渲染不同的结构 */}
    </div>
  )
}
```

### 用户状态管理

基于 `@gulibs/react-storage` 的持久化用户状态管理，支持浏览器刷新后状态保持。

#### 快速开始

```typescript
import { useUser } from '@gulibs/auto-routes-client';

function App() {
    const { user, isAuthenticated, login, logout } = useUser({
        loginApi: async ({ username, password }) => {
            // 调用你的登录 API
            const response = await fetch('/api/login', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ username, password })
            });
            const data = await response.json();
            return { user: data.user, token: data.token };
        }
    });

    if (!isAuthenticated) {
        return <LoginPage onLogin={login} />;
    }

    return (
        <div>
            <h1>欢迎，{user?.username}!</h1>
            <button onClick={logout}>退出登录</button>
        </div>
    );
}
```

#### 完整配置

```typescript
import { useUser, useUserState, useAuthToken } from '@gulibs/auto-routes-client';

function App() {
    // 完整的用户状态管理
    const {
        user,
        token,
        refreshToken,
        isAuthenticated,
        isLoading,
        error,
        login,
        logout,
        refreshUser,
        refreshTokenAction,
        updateUser,
        setToken,
        setRefreshToken,
        clearError
    } = useUser({
        // 可选配置
        storagePrefix: 'myapp',  // 存储键前缀，默认 'auth'
        useSessionStorage: false, // 是否使用 sessionStorage，默认 false（使用 localStorage）

        // 登录 API 函数
        loginApi: async (credentials) => {
            const response = await fetch('/api/login', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(credentials)
            });

            if (!response.ok) throw new Error('Login failed');

            const data = await response.json();
            return { user: data.user, token: data.token, refreshToken: data.refreshToken };
        },

        // 刷新Token API
        refreshTokenApi: async (refreshToken) => {
            const response = await fetch('/api/refresh', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${refreshToken}`
                }
            });

            if (!response.ok) throw new Error('Token refresh failed');

            const data = await response.json();
            return {
                token: data.newToken,
                refreshToken: data.newRefreshToken,
                user: data.user
            };
        },

        // 获取用户信息函数
        fetchUser: async (token) => {
            const response = await fetch('/api/user', {
                headers: { 'Authorization': `Bearer ${token}` }
            });

            if (!response.ok) throw new Error('Failed to fetch user');

            return response.json();
        },

        // 自动刷新用户信息间隔（毫秒，0表示禁用）
        autoRefreshInterval: 300000, // 5分钟

        // Token 过期检查函数
        isTokenExpired: (token) => {
            try {
                const payload = JSON.parse(atob(token.split('.')[1]));
                return Date.now() >= payload.exp * 1000;
            } catch {
                return true;
            }
        },

        // RefreshToken 过期检查函数
        isRefreshTokenExpired: (refreshToken) => {
            try {
                const payload = JSON.parse(atob(refreshToken.split('.')[1]));
                return Date.now() >= payload.exp * 1000;
            } catch {
                return true;
            }
        }
    });

    // 手动刷新Token示例
    const handleRefreshToken = async () => {
        try {
            await refreshTokenAction();
            console.log('Token刷新成功');
        } catch (error) {
            console.error('Token刷新失败:', error);
            // Token刷新失败，通常意味着需要重新登录
        }
    };

    return (
        <div>
            {isLoading && <div>加载中...</div>}
            {error && (
                <div style={{ color: 'red' }}>
                    错误：{error}
                    <button onClick={clearError}>清除错误</button>
                </div>
            )}

            {isAuthenticated ? (
                <div>
                    <h1>欢迎，{user?.username}!</h1>
                    <p>当前Token: {token?.substring(0, 20)}...</p>
                    <p>RefreshToken: {refreshToken ? '已设置' : '未设置'}</p>

                    <div>
                        <button onClick={logout}>登出</button>
                        <button onClick={refreshUser}>刷新用户信息</button>
                        <button onClick={handleRefreshToken}>刷新Token</button>
                        <button onClick={() => updateUser({ lastActive: new Date().toISOString() })}>
                            更新用户信息
                        </button>
                    </div>
                </div>
            ) : (
                <LoginForm onLogin={login} />
            )}
        </div>
    );
}

function LoginForm({ onLogin }) {
    const [credentials, setCredentials] = useState({ username: '', password: '' });

    const handleSubmit = async (e) => {
        e.preventDefault();
        try {
            await onLogin(credentials);
        } catch (error) {
            console.error('Login failed:', error);
        }
    };

    return (
        <form onSubmit={handleSubmit}>
            <input
                type="text"
                placeholder="用户名"
                value={credentials.username}
                onChange={(e) => setCredentials(prev => ({ ...prev, username: e.target.value }))}
            />
            <input
                type="password"
                placeholder="密码"
                value={credentials.password}
                onChange={(e) => setCredentials(prev => ({ ...prev, password: e.target.value }))}
            />
            <button type="submit">登录</button>
        </form>
    );
}
```

#### 只读用户状态

如果只需要读取用户状态，不需要登录等操作：

```typescript
import { useUserState } from '@gulibs/auto-routes-client';

function UserProfile() {
    const { user, token, refreshToken, isAuthenticated } = useUserState('myapp');

    if (!isAuthenticated) {
        return <div>请先登录</div>;
    }

    return (
        <div>
            <h2>{user?.username}</h2>
            <p>邮箱：{user?.email}</p>
            <p>角色：{user?.roles?.join(', ')}</p>
            <p>Token状态：{token ? '有效' : '无效'}</p>
            <p>RefreshToken状态：{refreshToken ? '有效' : '无效'}</p>
        </div>
    );
}
```

#### Token 管理

单独管理 Token：

```typescript
import { useAuthToken } from '@gulibs/auto-routes-client';

function ApiService() {
    const {
        token,
        refreshToken,
        setToken,
        setRefreshToken,
        clearToken,
        clearRefreshToken,
        clearAllTokens,
        hasToken,
        hasRefreshToken
    } = useAuthToken('myapp');

    const apiCall = async () => {
        if (!hasToken) {
            throw new Error('No token available');
        }

        const response = await fetch('/api/data', {
            headers: {
                'Authorization': `Bearer ${token}`
            }
        });

        return response.json();
    };

    const handleTokenRotation = async () => {
        if (!hasRefreshToken) {
            throw new Error('No refresh token available');
        }

        try {
            const response = await fetch('/api/refresh', {
                method: 'POST',
                headers: { 'Authorization': `Bearer ${refreshToken}` }
            });

            const data = await response.json();
            setToken(data.newToken);
            setRefreshToken(data.newRefreshToken);
        } catch (error) {
            // 刷新失败，清除所有Token
            clearAllTokens();
            throw error;
        }
    };

    return {
        apiCall,
        handleTokenRotation,
        hasValidTokens: hasToken && hasRefreshToken,
        clearAllTokens
    };
}
```

## ⚙️ 配置选项

### 基础选项

```typescript
interface UserOptions {
  dirs: RouteOption[]           // 路由目录配置
  cache?: boolean              // 启用缓存
  cacheTime?: number           // 缓存时间(ms)
  debug?: boolean              // 调试模式
  dynamic?: boolean            // 动态导入
  routeMode?: 'nested' | 'flat' // 路由模式
}
```

### 路由目录配置

```typescript
interface RouteOption {
  dir: string                  // 目录路径
  baseRoute: string            // 基础路由
  include?: string[]           // 包含文件模式
  exclude?: string[]           // 排除文件模式
}
```

## 📚 示例项目

### 完整演示项目

查看 `examples/auto-routes-demo/` 目录中的完整示例项目，包含：

#### 📁 项目结构

```
src/pages/
├── page.tsx                    # 首页
├── layout.tsx                  # 根布局
├── loading.tsx                 # 全局加载组件
├── 404.tsx                     # 404 错误页面
├── getting-started/            # 快速开始指南
├── file-system-routing/        # 文件系统路由说明
├── dynamic-routes/             # 动态路由示例
├── route-guards/               # 路由守卫演示
├── middleware/                 # 中间件使用
├── performance/                # 性能优化展示
├── hooks/                      # React Hooks 示例
├── user-management/            # 用户状态管理
├── users/                      # 用户列表和详情（动态路由）
│   ├── page.tsx               # 用户列表页
│   └── [id]/page.tsx          # 用户详情页
├── blog/                       # 博客文章（动态路由）
│   ├── page.tsx               # 文章列表页
│   └── [slug]/page.tsx        # 文章详情页
└── test-nested/                # 嵌套路由测试
    ├── layout.tsx             # 嵌套布局
    ├── page.tsx               # 嵌套首页
    ├── loading.tsx            # 嵌套加载
    ├── middleware.ts          # 嵌套中间件
    ├── guard.ts               # 嵌套守卫
    └── admin/                 # 管理员子路由
        └── auth.ts            # 认证配置
```

#### 🚀 运行示例

```bash
cd examples/auto-routes-demo
npm install
npm run dev
```

#### 🎮 功能演示

- ✅ **基础路由**：文件系统自动路由生成
- ✅ **动态路由**：用户详情页 `/users/:id` 和博客文章 `/blog/:slug`
- ✅ **嵌套路由**：多层布局和子路由结构
- ✅ **路由守卫**：基于角色的访问控制
- ✅ **中间件**：路由级数据预处理
- ✅ **性能监控**：实时性能数据展示
- ✅ **用户状态**：持久化用户认证状态
- ✅ **错误处理**：优雅的 404 和错误边界
- ✅ **TypeScript 支持**：完整的类型定义

## 🔍 调试和开发

### 开启调试模式

```typescript
reactAutoRoutes({
  debug: true, // 开启调试输出
  dirs: [...]
})
```

调试输出示例：

```
[react-auto-routes] Generated 12 route(s) with 8 import(s) in 45ms
[react-auto-routes] Cache hit rate: 85%
[react-auto-routes] Guard execution: 0.02ms
[react-auto-routes] Middleware execution: 1.15ms
[react-auto-routes] Using cached routes (12 routes, 8 imports)
```

### 性能分析

```bash
# 运行性能测试
npm run performance-test

# 查看构建分析
npm run build -- --analyze
```

## 🛠️ 高级用法

### 自定义路由处理器

```typescript
// src/pages/api/users/handle.ts
export default {
  loader: async ({ params, request }) => {
    // 数据加载逻辑
    return await fetchUsers()
  },
  action: async ({ params, request }) => {
    // 表单处理逻辑
    return await createUser(await request.formData())
  },
  shouldRevalidate: ({ currentParams, nextParams }) => {
    // 重新验证条件
    return currentParams.id !== nextParams.id
  }
}
```

### 元数据和面包屑

```typescript
// src/pages/blog/[slug]/handle.ts
export default {
  meta: {
    title: '博客详情',
    description: '查看博客文章详情',
    keywords: ['博客', '文章']
  },
  breadcrumbs: {
    href: '/blog',
    className: 'breadcrumb-item',
    startContent: <HomeIcon />,
    endContent: <ChevronRightIcon />
  }
}
```

### 错误边界

```typescript
// src/pages/error.tsx
import { useRouteError } from 'react-router'

export default function ErrorBoundary() {
  const error = useRouteError()

  return (
    <div className="error-page">
      <h1>出错了！</h1>
      <p>{error?.message || '发生了未知错误'}</p>
    </div>
  )
}
```

## 📦 导出模块

### 主模块

```typescript
import reactAutoRoutes from '@gulibs/vite-plugin-react-auto-routes'
```

### 客户端工具

```typescript
import {
  defineHandle,
  defineGuard,
  defineAuth,
  defineMiddleware,
  defineRoleGuard,
  definePermissionGuard,
  defineCustomGuard
} from '@gulibs/auto-routes-client'
```

### React Hooks

> **注意**：从 v0.2.5 开始，所有 React Hooks 已迁移到 `@gulibs/auto-routes-client` 包中。

```typescript
import {
  useRouteProtection,
  useRouteGuards,
  useRouteMiddleware,
  useUser,
  useUserState,
  useAuthToken,
  useHandle,
  useBreadcrumbs,
  usePageMeta,
  useLayoutSettings,
  usePageConfig
} from '@gulibs/auto-routes-client'
```

### 工具函数

> **注意**：从 v0.2.5 开始，所有工具函数已迁移到 `@gulibs/auto-routes-client` 包中。

```typescript
import {
  // 路由相关
  normalizePath,
  joinPath,
  matchPath,
  extractParams,

  // 字符串处理
  toCamelCase,
  toKebabCase,
  capitalize,
  truncate,

  // 对象和数组操作
  deepClone,
  deepMerge,
  unique,
  groupBy,

  // 缓存
  SimpleCache,

  // 性能相关
  debounce,
  throttle,
  measureTime,

  // URL处理
  parseQuery,
  buildQuery,
  updateQuery,

  // 错误处理
  safely,
  safelyAsync
} from '@gulibs/auto-routes-client'
```

### 性能工具

> **注意**：从 v0.2.5 开始，所有性能工具已迁移到 `@gulibs/auto-routes-client` 包中。

```typescript
import {
  PerformanceCache,
  PerformanceTracker,
  BatchProcessor,
  Debouncer,
  MemoryOptimizer,
  globalPerformanceTracker,
  globalMemoryOptimizer,
  measureAsync,
  throttle
} from '@gulibs/auto-routes-client'
```

### 运行时

> **注意**：从 v0.2.5 开始，所有运行时功能已迁移到 `@gulibs/auto-routes-client` 包中。

```typescript
import {
  RuntimeExecutor,
  createRuntimeContext
} from '@gulibs/auto-routes-client'
```

### 错误处理

```typescript
import {
  AutoRouteError,
  ErrorBuilder,
  logError,
  logWarning,
  logInfo,
  logSuccess
} from '@gulibs/vite-plugin-react-auto-routes/errors'
```

## 📄 许可证

[MIT](LICENSE) © GuLibs

## 🙏 致谢

感谢所有贡献者和用户的支持！

---

## 📞 支持

- 📖 [文档](https://github.com/gulibs/vite-plugin-react-auto-routes/blob/main/README.md)
- 🐛 [问题反馈](https://github.com/gulibs/vite-plugin-react-auto-routes/issues)
- 💬 [讨论](https://github.com/gulibs/vite-plugin-react-auto-routes/discussions)
- 📧 [邮件支持](mailto:support@gulibs.com)

**如果这个项目对你有帮助，请给我们一个 ⭐️ ！**

### 功能特性

- ✅ **持久化存储**：基于 localStorage/sessionStorage，刷新浏览器状态不丢失
- ✅ **跨标签页同步**：多个标签页状态自动同步
- ✅ **完全灵活的泛型支持**：无强制字段约束，用户可以定义任意类型结构
- ✅ **智能字段映射**：支持任意 API 响应格式，自动映射字段名
- ✅ **强大的数据转换**：登录前 / 后、存储前 / 后的完整数据转换链
- ✅ **双 Token 机制**：支持 access token 和 refresh token 的完整认证流程
- ✅ **自动 Token 刷新**：检测 token 过期并自动使用 refresh token 刷新
- ✅ **自动用户信息刷新**：可配置定时刷新用户数据
- ✅ **完善的错误处理**：全面的错误捕获和处理机制
- ✅ **完整的 TypeScript 支持**：提供完整的类型定义和智能提示
- ✅ **多场景适配**：支持微服务、第三方认证（Firebase、Auth0）等各种架构

### 最佳实践

1. **合理设置存储类型**：
   - 敏感应用使用 `sessionStorage`（关闭浏览器后清除）
   - 一般应用使用 `localStorage`（持久保存）

2. **Token 安全**：
   - 设置合理的过期时间
   - 实现自动刷新机制
   - 敏感操作时重新验证

3. **错误处理**：
   - 监听 `error` 状态
   - 提供用户友好的错误提示
   - 实现重试机制

4. **性能优化**：
   - 使用 `useUserState` 进行只读访问
   - 合理设置自动刷新间隔
   - 避免不必要的 API 调用

## ⚙️ 配置选项

#### 完全自定义的用户类型

```typescript
import { useUser, FieldMapping, DataTransformers } from '@gulibs/auto-routes-client';

// 完全自定义的用户类型（无需继承任何基础接口）
interface MyCustomUser {
    userId: string;
    fullName: string;
    email: string;
    department: {
        id: number;
        name: string;
    };
    settings: {
        theme: 'light' | 'dark';
        notifications: boolean;
    };
}

// 完全自定义的登录凭据
interface MyLoginData {
    email: string;
    password: string;
    captcha: string;
    rememberMe: boolean;
}

function App() {
    const { user, login, logout } = useUser<MyCustomUser, MyLoginData>({
        loginApi: async (credentials) => {
            const response = await fetch('/api/auth/login', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(credentials)
            });
            const data = await response.json();

            // 你的API返回什么格式都可以，无需遵循任何规则
            return data; // 例如: { userData: {...}, accessToken: "...", refreshToken: "..." }
        },

        // 字段映射：告诉hook你的API字段名
        fieldMapping: {
            userField: 'userData',        // 你的API用户数据字段名
            tokenField: 'accessToken',    // 你的API token字段名
            refreshTokenField: 'refreshToken'
        },

        // 数据转换：完全控制数据的转换过程
        transformers: {
            // 登录前转换凭据（例如加密密码）
            transformCredentials: (credentials) => ({
                ...credentials,
                password: btoa(credentials.password), // base64编码密码
                deviceInfo: navigator.userAgent
            }),

            // 从API响应转换用户数据
            transformUser: (apiUserData) => ({
                userId: apiUserData.id,
                fullName: `${apiUserData.firstName} ${apiUserData.lastName}`,
                email: apiUserData.emailAddress,
                department: apiUserData.dept,
                settings: apiUserData.userSettings
            }),

            // 存储前转换（例如数据压缩、敏感信息移除）
            beforeStore: (userData) => ({
                ...userData,
                // 移除敏感信息，只存储必要数据
                department: { ...userData.department },
                settings: { ...userData.settings }
            }),

            // 读取后转换（例如数据恢复、默认值设置）
            afterRestore: (storedData) => ({
                ...storedData,
                // 添加默认值或计算属性
                settings: {
                    theme: 'light',
                    notifications: true,
                    ...storedData.settings
                }
            })
        }
    });

    return (
        <div>
            {user ? (
                <div>
                    <h1>欢迎，{user.fullName}!</h1>
                    <p>部门：{user.department.name}</p>
                    <p>主题：{user.settings.theme}</p>
                    <button onClick={logout}>登出</button>
                </div>
            ) : (
                <LoginForm onLogin={login} />
            )}
        </div>
    );
}

function LoginForm({ onLogin }) {
    const [credentials, setCredentials] = useState<MyLoginData>({
        email: '',
        password: '',
        captcha: '',
        rememberMe: false
    });

    const handleSubmit = async (e) => {
        e.preventDefault();
        await onLogin(credentials);
    };

    return (
        <form onSubmit={handleSubmit}>
            <input
                type="email"
                value={credentials.email}
                onChange={(e) => setCredentials(prev => ({ ...prev, email: e.target.value }))}
            />
            <input
                type="password"
                value={credentials.password}
                onChange={(e) => setCredentials(prev => ({ ...prev, password: e.target.value }))}
            />
            <input
                type="text"
                placeholder="验证码"
                value={credentials.captcha}
                onChange={(e) => setCredentials(prev => ({ ...prev, captcha: e.target.value }))}
            />
            <label>
                <input
                    type="checkbox"
                    checked={credentials.rememberMe}
                    onChange={(e) => setCredentials(prev => ({ ...prev, rememberMe: e.target.checked }))}
                />
                记住我
            </label>
            <button type="submit">登录</button>
        </form>
    );
}
```

#### 字段映射和数据转换

```typescript
// 场景1：API返回的字段名与标准不同
const { user } = useUser<CustomUser, CustomCredentials>({
    fieldMapping: {
        userField: 'profile',           // API返回 { profile: {...}, token: "...", refresh_token: "..." }
        tokenField: 'token',
        refreshTokenField: 'refresh_token'
    }
});

// 场景2：复杂的数据转换
const { user } = useUser<CustomUser, CustomCredentials>({
    transformers: {
        // 转换API响应的用户数据
        transformUser: (apiData) => ({
            id: apiData.user_id,
            name: `${apiData.first_name} ${apiData.last_name}`,
            email: apiData.email_address,
            roles: apiData.permissions.map(p => p.role),
            avatar: apiData.profile_image_url || '/default-avatar.png'
        }),

        // 存储前数据处理
        beforeStore: (userData) => {
            // 移除大对象，只存储关键信息
            const { avatar, ...essentialData } = userData;
            return essentialData;
        },

        // 读取后数据恢复
        afterRestore: (storedData) => ({
            ...storedData,
            // 恢复默认头像
            avatar: storedData.avatar || '/default-avatar.png',
            // 添加计算属性
            displayName: storedData.name || storedData.email
        })
    }
});

// 场景3：第三方API集成（例如Firebase、Auth0等）
const { user } = useUser<FirebaseUser, FirebaseCredentials>({
    loginApi: async (credentials) => {
        const firebaseResponse = await signInWithEmailAndPassword(auth, credentials.email, credentials.password);
        const token = await firebaseResponse.user.getIdToken();

        return {
            user: firebaseResponse.user,
            token: token,
            refreshToken: firebaseResponse.user.refreshToken
        };
    },

    transformers: {
        transformUser: (firebaseUser) => ({
            uid: firebaseUser.uid,
            email: firebaseUser.email,
            displayName: firebaseUser.displayName,
            photoURL: firebaseUser.photoURL,
            emailVerified: firebaseUser.emailVerified
        })
    }
});
```

#### 微服务架构场景

```typescript
// 适配不同微服务的响应格式
interface UserServiceResponse {
    success: boolean;
    data: {
        userInfo: CustomUser;
        authToken: string;
        refreshToken: string;
    };
    message: string;
}

const { user } = useUser<CustomUser, CustomCredentials>({
    loginApi: async (credentials) => {
        const response = await fetch('/api/user-service/login', {
            method: 'POST',
            body: JSON.stringify(credentials)
        });
        const result: UserServiceResponse = await response.json();

        if (!result.success) {
            throw new Error(result.message);
        }

        // 返回标准格式
        return {
            user: result.data.userInfo,
            token: result.data.authToken,
            refreshToken: result.data.refreshToken
        };
    },

    // 或者使用字段映射
    fieldMapping: {
        userField: 'data.userInfo',
        tokenField: 'data.authToken',
        refreshTokenField: 'data.refreshToken'
    }
});
```