JiaJun 54410aaac5 feat(app): 添加应用启动资源预加载功能
- 实现了 AppBootResourceGate 组件用于管理应用启动时的资源加载
- 集成了图片和字体资源的预加载机制
- 添加了启动时的加载进度指示器和动画效果
- 创建了 DataLoadingIndicator 组件用于显示数据加载状态
- 在多个组件中替换原有的加载提示为新的 DataLoadingIndicator
- 更新了样式文件以支持新的加载动画和视觉效果
2026-05-29 17:43:47 +08:00
2026-04-23 16:41:39 +08:00
2026-05-09 17:52:30 +08:00
2026-04-23 16:41:39 +08:00
2026-05-21 13:40:32 +08:00
2026-04-23 16:41:39 +08:00
2026-04-24 18:02:42 +08:00
2026-04-23 16:41:39 +08:00
2026-04-23 16:41:39 +08:00

React SPA Template

这是一个用于后台系统或通用 SPA 项目的前端基础脚手架。它已经接好了以下底座能力:

  • Vite + React 19 + TypeScript
  • TanStack Router 文件路由
  • TanStack Query + ky 请求与缓存
  • Zustand 会话状态基座
  • Tailwind CSS 原子化样式
  • i18next 多语言
  • Head / Metadata 动态标题与元信息
  • Biome + Husky + commitlint 代码规范与提交规范

这个模板现在已经被“净化”为一个空白 scaffold。 你拿到它之后,应该在这个基础上替换成自己的页面、接口、登录逻辑和测试,而不是继续沿用示例业务。

1. 快速开始

pnpm install
pnpm dev

常用命令:

pnpm dev
pnpm build
pnpm lint
pnpm lint:fix
pnpm generate-routes
pnpm commit

2. 目录结构

核心目录说明:

  • src/routes TanStack Router 文件路由目录。你新增页面,优先在这里建文件。
  • src/lib/api 通用请求层。api-client.ts 是所有接口调用的基础入口。
  • src/lib/auth 会话初始化、401 清理、refresh token、受保护路由 helper。
  • src/lib/head 页面标题、description、Open Graph、Twitter metadata。
  • src/lib/query TanStack Query 全局默认配置。
  • src/store 全局状态。目前主要是认证状态。
  • src/styles.css 全局 Tailwind 入口。当前项目只保留这一份样式文件。
  • src/locales 多语言文案。

3. 新项目落地后先改哪里

如果你要基于这个模板开一个新项目,建议按这个顺序改:

第一步:改首页

先改这个文件:

  • src/routes/$lang/index.tsx

这是当前默认首页。通常你会:

  • 改成你的项目欢迎页
  • 或直接改成 dashboard / 工作台入口
  • 或拆成自己的页面布局

同时对应修改多语言文案:

  • src/locales/zh-CN/common.ts
  • src/locales/en-US/common.ts

第二步:改接口基础地址

先看这些文件:

  • .env.development
  • .env.production
  • src/vite-env.d.ts

至少确认这些变量:

  • VITE_APP_ENV
  • VITE_API_BASE_URL
  • VITE_ENABLE_QUERY_DEVTOOLS
  • VITE_ENABLE_REQUEST_LOG

第三步:改全局样式入口

当前模板已经切到 Tailwind CSS并移除了旧的 App.css / index.css

你主要会改:

  • src/styles.css

这里通常只放:

  • @import "tailwindcss";
  • 少量全局 base 样式
  • 你的主题变量

第四步:接你的业务模块

建议按“功能模块”建目录,而不是把所有请求、类型和 hooks 混在一起。

例如:

src/features/user/api/user-api.ts
src/features/user/hooks/use-current-user.ts
src/features/user/types/user.ts
src/routes/$lang/users/index.tsx

第五步:接你的登录体系

优先改这些文件:

  • src/store/auth-store.ts
  • src/lib/auth/auth-session.ts
  • src/lib/api/api-client.ts

4. Head / Metadata 怎么用

模板已经提供了一个通用 hook

  • src/lib/head/document-metadata.ts

在页面组件里直接调用:

import { useDocumentMetadata } from '@/lib/head/document-metadata'

function UserPage() {
  useDocumentMetadata({
    title: '用户管理',
    description: '用户管理页面',
  })

  return <div>User Page</div>
}

它会自动更新:

  • document.title
  • meta[name="description"]
  • meta[name="robots"]
  • og:title
  • og:description
  • twitter:title
  • twitter:description

适用场景:

  • 列表页标题
  • 详情页标题
  • 登录页 / 404 页
  • 分享卡片基础描述

5. 登录怎么接

这个模板的认证层不是“现成登录系统”,而是“认证骨架”。

它已经有:

  • accessToken
  • refreshToken
  • currentUser
  • status
  • 401 后清会话
  • refresh token 的可插拔入口

核心文件:

  • src/store/auth-store.ts
  • src/lib/auth/auth-session.ts
  • src/lib/api/api-client.ts

5.1 登录成功后怎么写入会话

假设你的登录接口返回:

{
  accessToken: string
  refreshToken: string
  user: {
    id: string
    name: string
  }
}

那么登录成功后可以这样写:

import { useAuthStore } from '@/store/auth-store'

useAuthStore.getState().startSession({
  accessToken: response.accessToken,
  refreshToken: response.refreshToken,
  currentUser: response.user,
})

5.2 刷新 token 怎么接

模板里预留了 refresh 的注册入口:

import { registerRefreshSessionHandler } from '@/lib/auth/auth-session'

registerRefreshSessionHandler(async (refreshToken) => {
  const response = await fetch('/auth/refresh', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ refreshToken }),
  }).then((result) => result.json())

  return {
    accessToken: response.accessToken,
    refreshToken: response.refreshToken,
    currentUser: response.user ?? null,
  }
})

当请求返回 401 时,请求层会:

  1. 尝试执行这个 refresh handler
  2. 如果 refresh 成功,则自动重试原请求一次
  3. 如果 refresh 失败,则清空本地会话

5.3 当前用户初始化怎么接

如果你的项目在刷新页面后,需要根据已有 token 主动请求一次“当前用户信息”,可以注册:

import { registerCurrentUserInitializer } from '@/lib/auth/auth-session'

registerCurrentUserInitializer(async () => {
  const response = await fetch('/auth/me').then((result) => result.json())

  return response.user
})

这样在应用启动时,模板会在已有 token 且尚未拿到 currentUser 的情况下,自动初始化一次用户信息。

6. 怎么加受保护路由

模板已经提供了路由保护 helper

  • src/lib/auth/require-auth.ts

用法是,在路由的 beforeLoad 里调用它。

示例:

import { createFileRoute } from '@tanstack/react-router'

import { requireAuthenticatedSession } from '@/lib/auth/require-auth'

export const Route = createFileRoute('/$lang/dashboard')({
  beforeLoad: async () => {
    await requireAuthenticatedSession()
  },
  component: DashboardPage,
})

function DashboardPage() {
  return <div>Dashboard</div>
}

它的行为是:

  • 如果当前已经登录,正常进入页面
  • 如果当前未登录,重定向到 /$lang

如果你想把未登录用户导向专门的登录页,可以直接修改:

  • src/lib/auth/require-auth.ts

把重定向目标从 /$lang 改成你的登录页路由,例如 /$lang/login

7. 怎么写第一个接口模块

推荐模式是:

  1. src/features/.../types 定义类型
  2. src/features/.../api 写请求函数
  3. src/features/.../hooks 写 query / mutation hook
  4. src/routes/... 页面里消费

示例:

// src/features/user/api/user-api.ts
import { api } from '@/lib/api/api-client'

export interface CurrentUser {
  id: string
  name: string
}

export function getCurrentUser() {
  return api.get<CurrentUser>('users/me').then((response) => response.data)
}
// src/features/user/hooks/use-current-user.ts
import { useQuery } from '@tanstack/react-query'

import { getCurrentUser } from '@/features/user/api/user-api'
import type { ApiError } from '@/lib/api/api-error'

export function useCurrentUserQuery() {
  return useQuery<Awaited<ReturnType<typeof getCurrentUser>>, ApiError>({
    queryKey: ['current-user'],
    queryFn: getCurrentUser,
  })
}

8. 路由相关说明

这个模板使用 TanStack Router 文件路由。

路由目录:

  • src/routes

生成文件:

  • src/routeTree.gen.ts

你通常不需要手改 src/routeTree.gen.ts。 新增、删除、修改路由文件后,执行:

pnpm generate-routes

pnpm devpnpm build 也都会自动先生成一次路由树。

9. 代码规范和提交流程

9.1 Tailwind 说明

当前模板使用的是官方 Vite 接法:

  • tailwindcss
  • @tailwindcss/vite

核心文件:

  • vite.config.ts
  • src/styles.css

新增页面时,优先直接写 Tailwind utility class而不是再恢复成多个分散的 CSS 文件。

格式化与 lint

pnpm lint
pnpm lint:fix
pnpm format

提交规范:

pnpm commit

仓库已经包含:

  • Biome
  • Husky
  • lint-staged
  • commitlint
  • Commitizen

10. 你后续最可能改动的文件

如果你刚接手这个模板,优先关注这几个文件:

  • src/routes/$lang/index.tsx
  • src/routes/$lang/route.tsx
  • src/lib/api/api-client.ts
  • src/lib/auth/auth-session.ts
  • src/lib/auth/require-auth.ts
  • src/store/auth-store.ts
  • src/lib/head/document-metadata.ts
  • src/locales/zh-CN/common.ts
  • src/locales/en-US/common.ts

11. 当前状态

当前模板已经验证通过:

  • pnpm lint
  • pnpm build

如果你继续往前整理,下一步通常就是:

  1. 接入真实登录接口
  2. 增加 logindashboard403 等实际页面
  3. 按业务模块拆分 features
  4. 按项目实际需要补充测试方案
Description
36字花
Readme 47 MiB
Languages
TypeScript 97.5%
CSS 2.4%
HTML 0.1%