📋 概述
layout.tsx
是 Coze Studio 应用的根布局组件,虽然代码简洁(仅 24 行),但承载着整个应用的基础架构初始化和全局布局渲染的重要职责。它通过组合模式将应用初始化逻辑和全局布局渲染分离,体现了良好的架构设计原则。
typescript
// frontend/apps/coze-studio/src/layout.tsx
import { GlobalLayout, useAppInit } from '@coze-foundation/global-adapter';
export const Layout = () => {
useAppInit(); // 应用初始化逻辑
return <GlobalLayout />; // 全局布局渲染
};
主要做了两件事情初始化应用配置和加载页面布局。
1. useAppInit Hook
useAppInit
是整个应用初始化的核心,主要包含以下功能:
获取页面配置
typescript
const { requireAuth, requireAuthOptional, loginFallbackPath } =
useRouteConfig();
useRouteConfig
主要是通过 react-router
的 useMatches
去获取路由配置。路由的配置就是在之前的 routes/index.tsx
文件中。 通过 useMatches 获取到当前 url 对应的路由信息之后,会把路由的 loader 和 data 属性 merge 在一起返回,就得到了上面requireAuth
, requireAuthOptional
, loginFallbackPath
这些属性。 这里取一个具体的路由配置作为 demo,方便理解useRouteConfig
。
typescript
{
path: 'sign',
Component: LoginPage,
errorElement: <GlobalError />,
loader: () => ({
hasSider: false,
requireAuth: false,
}),
}
上面是一 LoginPage 的路由配置,requireAuth
就配置在 loader 方法中。loader 中大致的一些配置项如下:
requireAuth: boolean
- 是否需要认证requireAuthOptional: boolean
- 认证是否可选loginFallbackPath: string
- 登录失败回退路径hasSider: boolean
- 是否显示侧边栏showMobileTips: boolean
- 是否显示移动端提示showAssistant: boolean
- 是否显示助手pageModeByQuery: boolean
- 页面模式由查询参数控制
这个地方取名叫 loader 有些不合理,通常 loader 在前端应该是用来定义和组件相关的方法,不清楚这里为什么要起名叫 loader。或者就是乱起,又或者有其他原因,且往后再看看。
检查登录信息
通过useRouteConfig
拿到路由配置之后,就知道了当前路由是否需要登陆的信息,之后通过useCheckLogin
去检查登录信息
typescript
useCheckLogin({
needLogin: !!(requireAuth && !requireAuthOptional),
loginFallbackPath,
});
useSyncLocalStorageUid(); // 同步用户ID到本地存储
useCheckLogin
大概有两个逻辑:
- useGoLogin
- useCheckLoginBase
useGoLogin
就是构造了一个跳转方法。
核心逻辑useCheckLoginBase
主要是做了一些检查是否登录以及登录异常处理的事情,整体也没什么好说的。
checkLogin 之后,执行useSyncLocalStorageUid
保存用户信息。这里 coze 内部实现了一套基于localStorage
的存储逻辑,可以基于用户信息去保存状态,代码就不展开了。
useSyncLocalStorageUid
会有一个信息上报逻辑,也不展开了。
监控以及页面状态设置
接着就来到了一些监控和页面设置的环境。
大概的逻辑我一次性先贴上来。
typescript
useErrorCatch(slardar);
useInitCommonConfig();
useResetStoreOnLogout();
useSetResponsiveBodyStyle();
useAlertOnLogout();
useErrorCatch
初始化 slardar(字节内部的监控系统)设置,里面通过unhandledrejection
事件做了异步异常的监听。
useInitCommonConfig
将DEFAULT_COMMON_CONFIG_STATE
的initialized
置为 true,大概是后面有用。
useResetStoreOnLogout
监听用户登出时重置状态。
useSetResponsiveBodyStyle
设置响应式状态。
useAlertOnLogout()
退出提醒。
都没什么好说的,继续,下一步。
2. GlobalLayout 组件
GlobalLayout
提供了完整的应用布局框架:
typescript
return (
<I18nProvider i18n={I18n}> {/* 国际化Provider */}
<CDLocaleProvider locale={currentLocale === 'en-US' ? en_US : zh_CN}> {/*Coze Design 语言 Provider */}
<LocaleProvider locale={currentLocale === 'en-US' ? enUS : zhCN}> {/* Semi Design语言Provider */}
<ThemeProvider {/* 主题Provider */}
defaultTheme="light"
changeSemiTheme={true}
changeBySystem={IS_BOE}
>
<BrowserUpgradeWrap> {/* 浏览器升级提示 */}
<GlobalLayoutComposed> {/* 组合布局组件 */}
<Outlet /> {/* 路由内容出口 */}
</GlobalLayoutComposed>
</BrowserUpgradeWrap>
</ThemeProvider>
</LocaleProvider>
</CDLocaleProvider>
</I18nProvider>
);
通过多个 Provider 管理一些公共数据,已经加了注释,没什么好说的。
BrowserUpgradeWrap
检测浏览器版本信息,低版本会给一些提示。
GlobalLayoutComposed
是实际的布局实现组件,大概有以下几个组件嵌套实现:
RequireAuthContainer
: 登录信息异常的时候会渲染一个提示弹框,引导用户去登录。GlobalLayout
:定义了页面大致的布局,例如菜单按钮,大致有几个区域,actions
、menus
、extras
都是不同位置的按钮信息。createBotModal
:就是创建机器人时候的弹框。
以上就是Layout.tsx
全部内容。