- 删除 src/locales/en-US/common.ts 文件中的所有国际化文案 - 删除 src/locales/id-ID/common.ts 文件中的所有国际化文案 - 移除与游戏、认证、UI组件相关的多语言配置项 - 清理导航、游戏大厅、语言选择等界面的翻译内容 - 移除登录注册表单、验证规则等认证相关文案 - 删除支付、提款、钱包记录等财务功能翻译项
React SPA Template
这是一个用于后台系统或通用 SPA 项目的前端基础脚手架。它已经接好了以下底座能力:
Vite + React 19 + TypeScriptTanStack 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/routesTanStack Router 文件路由目录。你新增页面,优先在这里建文件。src/lib/api通用请求层。api-client.ts是所有接口调用的基础入口。src/lib/auth会话初始化、401 清理、refresh token、受保护路由 helper。src/lib/head页面标题、description、Open Graph、Twitter metadata。src/lib/queryTanStack Query 全局默认配置。src/store全局状态。目前主要是认证状态。src/styles.css全局 Tailwind 入口。当前项目只保留这一份样式文件。src/locales多语言文案。
3. 新项目落地后先改哪里
如果你要基于这个模板开一个新项目,建议按这个顺序改:
第一步:改首页
先改这个文件:
src/routes/$lang/index.tsx
这是当前默认首页。通常你会:
- 改成你的项目欢迎页
- 或直接改成 dashboard / 工作台入口
- 或拆成自己的页面布局
同时对应修改多语言文案:
src/locales/zh-CN/common.tssrc/locales/en-US/common.ts
第二步:改接口基础地址
先看这些文件:
.env.development.env.productionsrc/vite-env.d.ts
至少确认这些变量:
VITE_APP_ENVVITE_API_BASE_URLVITE_ENABLE_QUERY_DEVTOOLSVITE_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.tssrc/lib/auth/auth-session.tssrc/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.titlemeta[name="description"]meta[name="robots"]og:titleog:descriptiontwitter:titletwitter:description
适用场景:
- 列表页标题
- 详情页标题
- 登录页 / 404 页
- 分享卡片基础描述
5. 登录怎么接
这个模板的认证层不是“现成登录系统”,而是“认证骨架”。
它已经有:
accessTokenrefreshTokencurrentUserstatus401后清会话- refresh token 的可插拔入口
核心文件:
src/store/auth-store.tssrc/lib/auth/auth-session.tssrc/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 时,请求层会:
- 尝试执行这个 refresh handler
- 如果 refresh 成功,则自动重试原请求一次
- 如果 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. 怎么写第一个接口模块
推荐模式是:
- 在
src/features/.../types定义类型 - 在
src/features/.../api写请求函数 - 在
src/features/.../hooks写 query / mutation hook - 在
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 dev 和 pnpm build 也都会自动先生成一次路由树。
9. 代码规范和提交流程
9.1 Tailwind 说明
当前模板使用的是官方 Vite 接法:
tailwindcss@tailwindcss/vite
核心文件:
vite.config.tssrc/styles.css
新增页面时,优先直接写 Tailwind utility class,而不是再恢复成多个分散的 CSS 文件。
格式化与 lint:
pnpm lint
pnpm lint:fix
pnpm format
提交规范:
pnpm commit
仓库已经包含:
BiomeHuskylint-stagedcommitlintCommitizen
10. 你后续最可能改动的文件
如果你刚接手这个模板,优先关注这几个文件:
src/routes/$lang/index.tsxsrc/routes/$lang/route.tsxsrc/lib/api/api-client.tssrc/lib/auth/auth-session.tssrc/lib/auth/require-auth.tssrc/store/auth-store.tssrc/lib/head/document-metadata.tssrc/locales/zh-CN/common.tssrc/locales/en-US/common.ts
11. 当前状态
当前模板已经验证通过:
pnpm lintpnpm build
如果你继续往前整理,下一步通常就是:
- 接入真实登录接口
- 增加
login、dashboard、403等实际页面 - 按业务模块拆分
features - 按项目实际需要补充测试方案