在上一篇文章中
👉 《从零打造 AI 全栈应用(一):深度解析 Shadcn UI + Vite + NestJS 的工程化最佳实践》
我们从整体视角拆解了 AI 全栈项目的技术选型与工程结构,重点放在 UI 体系、构建工具与后端框架的协同设计 上。
但真正开始落地一个 AI 应用时,你会很快发现一个问题:
页面越来越多,能力越来越复杂,路由如果一开始没设计好,后期几乎一定要推倒重来。
因此,本文将单独聚焦一个经常被低估、却极其关键的模块 ——
前端路由的工程化设计。
一、为什么 AI 应用对“路由设计”要求更高
与普通信息型网站不同,AI 应用通常具备以下特征:
- 页面模块多(Chat / 订单 / 订阅 / 用户中心 / 历史记录)
- 页面体积大(富交互、状态复杂)
- 强登录态与权限边界
- 高频异步加载(模型调用、流式返回)
如果路由层只是“能跳就行”,常见后果包括:
- 首屏 JS 包过大,加载慢
- 每次加页面都要改一堆路由逻辑
- 登录态判断散落在各个页面
- 布局代码重复、难以维护
👉 结论很明确:路由必须从一开始就工程化设计。
二、路由级懒加载:AI 应用的性能生命线
1. 问题本质:不是所有用户都会访问所有页面
在 AI 应用中:
- 未登录用户只会访问登录页
- 大部分用户高频使用的只有 Chat
- 订单、个人中心访问频率远低于首页
如果一次性加载所有页面代码,本质是在 浪费用户带宽和首屏时间。
2. React 中的路由级懒加载方案
React 官方提供了两块基础能力:
React.lazy:定义异步组件Suspense:处理异步加载期间的 UI 状态
页面组件的声明方式如下:
import { lazy } from 'react';
const Home = lazy(() => import('@/pages/Home'));
const Mine = lazy(() => import('@/pages/Mine'));
const Login = lazy(() => import('@/pages/Login'));
const Chat = lazy(() => import('@/pages/Chat'));
const Order = lazy(() => import('@/pages/Order'));
这段代码背后做了三件非常重要的事:
- 每个页面会被打包成独立的 chunk
- 只有在路由命中时才会下载对应代码
- 极大降低首屏资源体积
📌 面试高频点
React.lazy 返回的是一个异步组件,必须运行在 Suspense 之下。
三、Suspense + Loading:把“等待”当成一等公民
<Suspense fallback={<Loading />}>
<Routes>
{/* 路由表 */}
</Routes>
</Suspense>
1. Suspense 在这里到底解决什么问题
当用户首次进入某个路由时:
- 对应页面 chunk 尚未下载完成
- React 会暂停渲染该组件
- 由
Suspense统一兜底展示fallback
如果没有 Suspense:
- ❌ 页面直接报错
- ❌ 用户看到空白页面
2. 为什么 Loading 一定要抽成组件
在 AI 应用中,“加载中”并不是一个可忽略的瞬间状态:
- 模型响应有真实等待时间
- 页面切换频繁
- 用户对流畅度非常敏感
将 Loading 抽成独立组件,可以:
- 统一加载态视觉风格
- 后期无痛升级为骨架屏
- 区分首屏 Loading / 路由切换 Loading
👉 这不是 UI 细节,而是产品体验的一部分。
四、Layout Route:决定项目能走多远的设计
<Route path="/" element={<MainLayout />}>
<Route path="" element={<Home />} />
<Route path="mine" element={<Mine />} />
<Route path="chat" element={<Chat />} />
<Route path="order" element={<Order />} />
</Route>
这层结构是整个路由设计中最关键的一步。
1. Layout Route 的核心思想
在 SPA 中,有两类组件:
- 结构组件(Layout)
- 内容组件(Page)
MainLayout 通常包含:
- Header / 导航栏
- 公共容器
<Outlet />子路由出口
function MainLayout() {
return (
<>
<Header />
<Outlet />
<TabBar />
</>
);
}
当访问 /chat 时:
- React Router 先渲染
MainLayout - 再将
Chat渲染到Outlet中
👉 页面在变,结构不变。
2. 为什么 AI 应用特别适合这种设计
- Chat、订单、个人中心共享布局
- 新增模块只需添加子路由
- 公共逻辑集中,维护成本低
这是一种 长期友好型架构。
五、路由守卫:登录态与访问边界控制
AI 应用几乎一定存在明确的访问边界:
- 未登录用户只能访问登录页
- 登录后才能使用核心能力
但 React Router 并没有 Vue 那样的“路由守卫 API”。
1. React Router 的官方设计哲学
一切皆组件
因此,所谓“路由守卫”,本质就是 条件渲染。
2. AuthRoute:最清晰、可维护的实现方式
import { Navigate } from 'react-router-dom';
function AuthRoute({ children }: { children: JSX.Element }) {
const { isLogin } = useUserStore();
if (!isLogin) {
return <Navigate to="/login" replace />;
}
return children;
}
使用方式:
<Route
path="order"
element={
<AuthRoute>
<Order />
</AuthRoute>
}
/>
这种设计的优势非常明显:
- 权限逻辑集中
- 路由配置依然清晰
- 与 Zustand / Redux 等状态管理天然契合
📌 面试一句话总结
React Router 的路由守卫,本质是通过组件包裹实现的条件控制。
六、RouterConfig:它是基础设施,不是业务代码
export default function RouterConfig({ children }) {
return (
<Router>
<Suspense fallback={<Loading />}>
<Routes>{/* 路由表 */}</Routes>
</Suspense>
{children}
</Router>
);
}
这个结构体现了一种非常成熟的工程意识:
- Router 是最外层基础设施
- Suspense 统一管理异步边界
children为全局能力预留扩展点(如 Toast、全局弹窗、埋点)
👉 这已经不是“会用路由”,而是在“设计路由系统”。
七、总结:一个合格的 AI 应用路由层应该具备什么
- 路由级懒加载(性能)
- Suspense 统一兜底(稳定性)
- Loading 抽象(体验)
- Layout Route(结构清晰)
- 路由守卫(业务边界)
如果你能把这套设计讲清楚:
面试官听到的不是 API,而是你的架构能力。