# 前端页面加载逻辑

## 框架与构建工具

| 项目       | 技术                         |
| ---------- | ---------------------------- |
| 前端框架   | Lit v3.3.2（Web Components） |
| 构建工具   | Vite v8.0.10                 |
| 模块系统   | ES Modules                   |
| 微前端支持 | qiankun（多租户集成）        |

---

## 整体加载流程

```
index.html
  ├── 主题检测脚本（同步，防止闪烁）
  ├── <openclaw-app> 占位标签
  └── <script type="module" src="/src/main.ts">
        ├── 注册 Web Component (app.ts)
        ├── 判断是否 qiankun 微前端模式
        │     ├── qiankun 模式：export bootstrap/mount/unmount
        │     └── 独立模式：直接挂载 <openclaw-app>
        └── 注册 Service Worker（仅生产环境）
```

---

## 1. HTML 入口

**文件：** [ui/index.html](ui/index.html)

页面初始化分三步：

**① 主题预加载脚本（第 12–64 行）**  
在 JS 加载前同步运行，避免白屏/闪烁：

- 从 `localStorage` 读取 `openclaw.control.settings.v1`
- 解析主题：`claw | knot | dash`
- 解析模式：`light | dark | system`
- 将 `data-theme` 和 `data-theme-mode` 写入 `<html>` 标签

**② Web Component 根元素（第 67 行）**

```html
<openclaw-app></openclaw-app>
```

**③ 模块入口（第 68 行）**

```html
<script type="module" src="/src/main.ts"></script>
```

---

## 2. JS 入口

**文件：** [ui/src/main.ts](ui/src/main.ts)（56 行）

```
main.ts
├── import './styles.css'          ← 全局样式
├── import './ui/app.ts'           ← 注册 <openclaw-app> Web Component
├── renderWithQiankun()
│     ├── qiankun 模式 → export { bootstrap, mount, unmount, update }
│     └── 独立模式 → 直接使用已有的 <openclaw-app> 标签
└── setupServiceWorker()           ← 仅生产环境
```

`renderWithQiankun()`（第 28–50 行）兼容两种运行场景：作为独立应用直接访问，或作为微前端子应用被 qiankun 加载。

---

## 3. Web Component 主组件

**文件：** [ui/src/ui/app.ts](ui/src/ui/app.ts)（1348 行）

### 类定义

```typescript
class OpenClawApp extends LitElement { ... }
customElements.define('openclaw-app', OpenClawApp);
```

### 关键状态属性（第 150–462 行）

Lit 的 `@state()` 装饰器标记响应式属性，状态变化自动触发重渲染：

| 状态类别 | 代表字段                                    |
| -------- | ------------------------------------------- |
| 连接状态 | `connected`, `hello`, `lastError`           |
| 聊天     | `chatMessages`, `chatStream`, `chatSending` |
| 导航     | `tab`（当前页面）                           |
| 配置     | `configForm`, `configSnapshot`              |

### 生命周期

| 钩子                   | 位置       | 职责                           |
| ---------------------- | ---------- | ------------------------------ |
| `constructor`          | 第 154 行  | 初始化 UUID 和默认状态         |
| `connectedCallback`    | 第 633 行  | 键盘监听、连接网关、初始化推送 |
| `firstUpdated`         | 第 663 行  | 设置 topbar ResizeObserver     |
| `updated`              | 第 686 行  | 滚动管理、连接状态变化响应     |
| `disconnectedCallback` | 第 667 行  | 清理监听器、断开网关           |
| `render`               | 第 1341 行 | 调用 `renderApp()`             |

---

## 4. 连接与初始化

**文件：** [ui/src/ui/app-lifecycle.ts](ui/src/ui/app-lifecycle.ts)（170 行）

`handleConnected()`（第 61–85 行）的执行顺序：

```
1. 推断 basePath（从 URL）
2. 应用 URL query 参数中的设置
3. 加载 bootstrap config（异步）
4. 同步 tab 与当前 URL
5. 应用已保存的主题设置
6. 注册 popstate 监听（浏览器前进/后退）
7. 连接 Gateway（WebSocket）
8. 开始轮询：nodes、logs（如在 logs tab）、debug（如在 debug tab）
9. 启动响应式 observer
```

---

## 5. 页面路由

**文件：** [ui/src/ui/navigation.ts](ui/src/ui/navigation.ts)（231 行）

不使用传统路由库，使用 Tab → URL 映射：

| Tab      | URL Path  |
| -------- | --------- |
| chat     | /chat     |
| overview | /overview |
| channels | /channels |
| config   | /config   |
| agents   | /agents   |
| logs     | /logs     |
| ...      | ...       |

**关键函数：**

- `pathForTab(tab, basePath)` — 生成 URL
- `tabFromPath(pathname, basePath)` — 从 URL 解析当前 tab
- `setTab()` — 更新 `state.tab` 并调用 `history.pushState()`
- `onPopState()` — 处理浏览器前进/后退

---

## 6. 主渲染逻辑

**文件：** [ui/src/ui/app-render.ts](ui/src/ui/app-render.ts)（2759 行）

`renderApp()` 的渲染结构：

```
renderApp(state)
  │
  ├── 未连接？→ renderLoginGate()（登录/鉴权页）
  │
  └── 已连接 → 主布局
        ├── Header（Topbar）
        ├── Sidebar 导航
        └── 主内容区（按 state.tab 分支）
              ├── "chat"     → renderChat(props)
              ├── "overview" → renderOverview(props)
              ├── "channels" → renderLazyView(lazyChannels, ...)  ← 懒加载
              ├── "sessions" → renderLazyView(lazySessions, ...)  ← 懒加载
              ├── "agents"   → renderLazyView(lazyAgents, ...)    ← 懒加载
              ├── "config"   → renderConfig(props)
              ├── "logs"     → renderLazyView(lazyLogs, ...)      ← 懒加载
              └── ...（共 18 个 tab）
```

---

## 7. 懒加载机制

**文件：** [ui/src/ui/lazy-view.ts](ui/src/ui/lazy-view.ts)（107 行）

非首屏 tab 使用动态 `import()` 懒加载，减少初始包体积：

```typescript
// 创建懒加载包装器
const lazyChannels = createLazyView(() => import("./views/channels.ts"), notifyLazyViewChanged);

// 渲染时按需加载
renderLazyView(lazyChannels, (m) => m.renderChannels({ ...props }));
```

- 首次访问该 tab 时才加载模块
- 加载中显示骨架屏/loading 状态
- 加载失败显示重试按钮

---

## 8. 样式与主题

**文件：** [ui/src/styles.css](ui/src/styles.css)

```css
@import "./styles/base.css"; /* Reset + CSS 变量 */
@import "./styles/layout.css"; /* Flex 布局 */
@import "./styles/layout.mobile.css"; /* 移动端响应式 */
@import "./styles/components.css"; /* 通用组件 */
@import "./styles/chat.css"; /* 聊天页 */
@import "./styles/config.css"; /* 配置面板 */
/* ... 更多页面级样式 */
```

主题通过 HTML 属性驱动，无需 JS 运行时切换：

```html
<html data-theme="claw" data-theme-mode="dark"></html>
```

CSS 自定义属性（如 `--mono`, `--accent`, `--info`）在不同主题下取不同值。

---

## 9. 数据流示例：切换到 Chat 页

```
用户点击 Chat tab
  ↓
setTab("chat") 被调用
  ↓
history.pushState → URL 变为 /sealclaw/chat
  ↓
state.tab = "chat"（触发 Lit 重渲染）
  ↓
renderApp() → 进入 "chat" 分支 → renderChat(props)
  ↓
Gateway WebSocket 推送新消息
  ↓
state.chatMessages 更新 → 再次重渲染
```

---

## 关键文件速查

| 文件                                                     | 职责                       | 行数 |
| -------------------------------------------------------- | -------------------------- | ---- |
| [ui/index.html](ui/index.html)                           | HTML 入口 + 主题预加载     | 70   |
| [ui/src/main.ts](ui/src/main.ts)                         | JS 入口，qiankun + SW      | 56   |
| [ui/src/ui/app.ts](ui/src/ui/app.ts)                     | 主组件，状态定义，生命周期 | 1348 |
| [ui/src/ui/app-render.ts](ui/src/ui/app-render.ts)       | 所有页面的渲染逻辑         | 2759 |
| [ui/src/ui/app-lifecycle.ts](ui/src/ui/app-lifecycle.ts) | 连接/断连逻辑              | 170  |
| [ui/src/ui/app-settings.ts](ui/src/ui/app-settings.ts)   | 主题、tab 导航、URL 同步   | 600+ |
| [ui/src/ui/navigation.ts](ui/src/ui/navigation.ts)       | Tab 路由定义               | 231  |
| [ui/src/ui/lazy-view.ts](ui/src/ui/lazy-view.ts)         | 懒加载封装                 | 107  |
| [ui/vite.config.ts](ui/vite.config.ts)                   | 构建配置                   | 69   |
