鼎享会 | OpenClaw Control UI 前端架构全解析:自研 UI 对接 Server 实操指南

这份文档的目标,是把当前 OpenClaw Control UI 的前端结构讲清楚,并结合鼎道智联 DingVerse 服务的实践场景,回答核心问题:

DingOS 部分产品页面已尝试基于该架构思路开发,并应用于 DingVerse 服务中。在此背景下,若为 DingVerse 服务开发自研 UI 页面、后端仍对接 OpenClaw Server,前端应从哪里接入、哪些层可复用、哪些层需适配改造。

这份文档重点解决以下问题:

  • 当前 OpenClaw 前端主架构是什么?
  • 用户操作如何从页面流转至后端?
  • WebSocket 客户端如何与页面状态联动?
  • 鼎道智联 DingVerse 服务自研 UI 对接 OpenClaw Server,需完成哪些适配与开发工作?

架构图

当前前端可以先粗略理解成下面这张图:

text 复制代码
浏览器入口
  -> ui/src/main.ts
  -> ui/src/ui/app.ts (根组件 / 全局状态容器)
  -> ui/src/ui/app-render.ts (把状态装配成各个 view 的 props)
  -> ui/src/ui/views/*.ts (页面/视图)
       -> 调用 props 回调
  -> ui/src/ui/app-*.ts (功能逻辑层)
       -> 编排状态、队列、连接、生命周期行为
  -> ui/src/ui/controllers/*.ts (请求/响应动作层)
       -> 调用 client.request(...)
  -> ui/src/ui/gateway.ts (GatewayBrowserClient)
       -> WebSocket
       -> OpenClaw Server

如果想把它看成更清晰的分层关系,可以用下面这张图理解:
ui/src/main.ts

前端入口
ui/src/ui/app.ts

根组件 / 全局状态容器
ui/src/ui/app-render.ts

渲染装配层
ui/src/ui/views/*.ts

页面 / 视图层
ui/src/ui/components/*.ts

可复用组件层
ui/src/ui/app-*.ts

功能逻辑层
ui/src/ui/controllers/*.ts

请求 / 数据动作层
ui/src/ui/gateway.ts

GatewayBrowserClient
OpenClaw Server

再换一种方式,按"谁负责什么"来看:

text 复制代码
view
  负责:展示 UI、绑定点击事件、触发 props 回调

app-render
  负责:把根状态装配成视图 props

app-*
  负责:功能逻辑、队列、连接、状态编排

controllers
  负责:调用后端方法、组织请求参数

gateway client
  负责:WebSocket、握手、req/res/event 协议

架构分析

1. 入口层

  • ui/src/main.ts

这个文件非常薄,只做两件事:

  • 引入全局样式
  • 引入根组件 openclaw-app

这说明真正的应用不是从 main.ts 开始写逻辑的,而是从根组件开始。

在 DingVerse 服务中的部分页面和交互已沿用该轻量入口设计,降低初始包体积,适配产品迭代期的快速调整需求。

2. 根组件层

  • ui/src/ui/app.ts

这是整个前端最核心的对象。

它的职责是:

  • 持有大量 @state() 状态
  • 暴露应用级方法,比如 handleSendChat()connect()handleAbortChat()
  • 在生命周期里做初始化、连接、同步
  • 把自身状态交给渲染层

重要特点:

  • 它不是只负责"渲染"
  • 它更像"全局应用实例 + 状态容器 + 方法门面"

在这个项目里,很多地方的:

  • this
  • host
  • state

本质上都经常指向这个根组件实例,只是不同文件里的命名不同。

3. 渲染装配层

  • ui/src/ui/app-render.ts

这个文件的职责是把根状态翻译成 UI。

它主要做:

  • 判断当前 tab 渲染什么页面
  • 给各个页面组装 props
  • 把 app.ts 暴露的方法作为回调传给 view
  • 做页面级懒加载,减少初始包体积

它不是某一个页面,而是整个页面结构的装配中心。

比如聊天页的 onSendonAbortdraftqueuemessages 等,都是在这里传给 chat view 的。

4. 视图层

  • ui/src/ui/views/chat.ts
  • ui/src/ui/views/overview.ts
  • ui/src/ui/views/config.ts
  • ui/src/ui/views/agents.ts
  • 以及 ui/src/ui/views/ 下的其他文件

这些文件主要负责:

  • 视图结构
  • 页面布局
  • 按钮、输入框、列表等 UI 细节
  • 调用 props 回调

它们通常不直接承载复杂业务逻辑。

例如聊天发送按钮只会调用 props.onSend(),它不会自己判断:

  • 当前是否 busy
  • 该直接发送还是入队
  • 是否是 slash command
  • 发送失败后是否恢复草稿

这些都不是 view 层该做的。

5. 功能逻辑层

  • ui/src/ui/app-chat.ts
  • ui/src/ui/app-gateway.ts
  • ui/src/ui/app-settings.ts
  • ui/src/ui/app-scroll.ts
  • ui/src/ui/app-tool-stream.ts

这层是当前 UI 很关键的一层。

可以把它理解成:

  • 某个功能域的应用逻辑
  • 对根状态对象的读写编排
  • 视图层和 controller 层之间的"中间大脑"

举例:

  • app-chat.ts 负责聊天发送、排队、出队、abort、slash command
  • app-gateway.ts 负责连接 Gateway、处理 hello / event / close 回调,并把事件同步回 app 状态
  • app-settings.ts 负责 settings、tab 切换和相关加载

所以 app-* 不是"页面本身",而是"页面的功能逻辑"。

6. Controller 层

  • ui/src/ui/controllers/chat.ts
  • ui/src/ui/controllers/config.ts
  • ui/src/ui/controllers/agents.ts
  • ui/src/ui/controllers/channels.ts
  • 等等

这层主要负责:

  • 和后端通信
  • 组织请求参数
  • 调用 client.request(...)
  • 将返回结果映射到前端状态变化

举例:

  • 聊天真正发给后端是在 controllers/chat.ts
  • 配置的读取和保存是在 controllers/config.ts

所以它更接近"数据动作层"。

7. WS 封装层

  • ui/src/ui/gateway.ts

这个文件里有当前前端最重要的 WebSocket 客户端封装:

  • GatewayBrowserClient

它主要负责:

  • 建立 WebSocket 连接
  • 处理 open/message/close/error
  • connect 握手
  • req/res/event 帧收发
  • pending 请求 promise 管理
  • 重连和回退

这是当前前端和 Gateway 协议绑定最深的地方之一,同时 WS Client 可参考该封装逻辑,预留协议扩展空间,适配产品后续优化需求。

用 Chat 发送流程举例

聊天发送是理解整个架构最好的例子。

先看一张完整时序图:
OpenClaw Server GatewayBrowserClient controllers/chat.ts app-chat.ts app.ts app-render.ts views/chat.ts 用户 OpenClaw Server GatewayBrowserClient controllers/chat.ts app-chat.ts app.ts app-render.ts views/chat.ts 用户 alt [当前 busy] [直接发送] 点击发送按钮 调用 props.onSend() state.handleSendChat() handleSendChatInternal(...) 判断 busy / slash / stop / queue enqueueChatMessage() sendChatMessage() client.request("chat.send", ...) 发送 WS req 帧 返回 res / event 终态事件最终触发 flushChatQueue

第一步:根组件开始渲染

ui/src/ui/app.ts 里:

  • render() 调用 renderApp(this as AppViewState)

这里把根组件当前状态交给渲染层。

第二步:渲染层把回调传给聊天视图

ui/src/ui/app-render.ts 里,渲染 chat view 时会传:

  • onSend: () => state.handleSendChat()

这里的 state 实际就是 OpenClawApp 实例。

所以聊天页拿到的 props.onSend,本质上就是根组件方法。

第三步:聊天视图点击按钮

ui/src/ui/views/chat.ts 里,发送按钮点击时会调用:

  • props.onSend()

这一步只是"触发动作",不是"处理发送逻辑"。

也就是说:

  • 点击按钮时,view 调的是 prop
  • 但这个 prop 是上层传下来的

第四步:进入根组件方法

ui/src/ui/app.ts 里:

  • handleSendChat(...)

它内部再调用:

  • handleSendChatInternal(...)

这个 handleSendChatInternal 实际来自 ui/src/ui/app-chat.ts

所以 app.ts 在这里扮演的是方法门面角色。

第五步:进入 app-chat.ts

ui/src/ui/app-chat.ts 是聊天功能真正的应用逻辑层。

这里会决定:

  • 是否已连接
  • 是否为空消息
  • 是否是 stop
  • 是否是 slash command
  • 当前是否 busy
  • 是直接发送还是排队
  • 发送完成后是否继续 flush 队列

因此更准确地说:

  • view 负责"点发送"
  • app-chat.ts 负责"怎么发送"

第六步:如果 busy,则先入队

app-chat.ts 里有:

  • isChatBusy(host)
  • enqueueChatMessage(...)

如果当前有正在执行的 run,发送逻辑不会直接继续发,而是把消息写进:

  • host.chatQueue

这个队列是前端内存状态,不是本地持久化存储。

第七步:如果不 busy,则立即发送

app-chat.ts 会走:

  • sendChatMessageNow(...)

这个函数会先处理一些发送前动作,比如:

  • reset tool stream
  • reset scroll
  • 清理/恢复草稿与附件的状态逻辑

然后调用:

  • sendChatMessage(...)

第八步:controller 真正发请求

ui/src/ui/controllers/chat.ts 里,真正会调用:

  • state.client.request("chat.send", ...)

这说明:

  • app-chat.ts 负责发送决策和流程编排
  • controllers/chat.ts 负责真正发给后端

同时 controller 会更新前端状态,例如:

  • 立即插入一条 user message
  • 设定 chatSending = true
  • 生成并写入 chatRunId
  • 初始化 chatStream

所以用户在 UI 上会立刻看到"我发出去了",即使后端结果还没回来。

第九步:后端事件通过 WS 回流

后端返回的运行中事件、完成事件、错误事件,不是通过按钮链路回来的,而是通过 WebSocket 回流到前端。

这些事件会先经过:

  • GatewayBrowserClient.handleMessage(...)

再通过回调交给:

  • app-gateway.ts

第十步:终态事件触发队列继续发送

当一个 run 到达终态后,app-gateway.ts 会:

  • 清理该 run 的 pending queue items
  • 调用 flushChatQueue(...)

这个函数在 app-chat.ts 中,会把队列里的下一条拿出来继续发送。

这样队列机制才能闭环。

这一段也可以单独看成"回流图":
OpenClaw Server

event / res
gateway.ts

handleMessage()
this.opts.onEvent?.(...)
app-gateway.ts

事件协调层
更新根状态

chatRunId / messages / queue / errors
app-render.ts
views/chat.ts

界面重新渲染

hoststatethis 到底是什么

这是这个前端特别容易绕的一个点。

在很多地方:

  • this 指向 OpenClawApp 根组件实例
  • host 是把这个根组件实例作为参数传给 app-* 模块时的命名
  • state 是渲染层或 controller 层里对这个状态对象的命名

所以从工程上讲,它们常常是"同一个根对象"的不同叫法。

这意味着当前前端没有单独再做一个 Redux 风格的 store。

它的"共享状态容器"就是根组件实例本身。

WebSocket 客户端在哪里封装

WebSocket 客户端封装在:

  • ui/src/ui/gateway.ts

核心类是:

  • GatewayBrowserClient

它内部维护:

  • ws
  • pending 请求映射
  • connect 握手状态
  • seq 状态
  • 重连状态

它对外最关键的方法是:

  • start()
  • stop()
  • request<T>(method, params)

其中:

  • request(...) 会发送 type: "req"
  • handleMessage(...) 会解析 eventres

handleMessage() 怎么和 app-gateway.ts 关联

这不是直接 import 关联,而是通过"构造时注入回调"关联的。

流程是:

  1. app-gateway.ts 创建客户端:
    • new GatewayBrowserClient({ onHello, onEvent, onClose, onGap, ... })
  2. gateway.ts 构造函数把这些回调保存到 this.opts
  3. handleMessage() 收到消息后,根据帧类型执行:
    • this.opts.onEvent?.(evt)
    • this.opts.onHello?.(hello)
    • this.opts.onClose?.(...)
    • this.opts.onGap?.(...)

所以关系不是:

  • gateway.ts 知道 app-gateway.ts

而是:

  • app-gateway.ts 在创建 client 时把回调注入进去
  • gateway.ts 在合适的时机调用这些回调

这是一种典型的"底层传输层回调上浮到应用层"的设计。

如果只看这部分关系,可以把它简化成:
app-gateway.ts

new GatewayBrowserClient({ onEvent, onHello, onClose, onGap })
gateway.ts

constructor(private opts)
handleMessage()
this.opts.onEvent?.(evt)
app-gateway.ts

处理 event -> 改状态

client 是怎么注入到全局状态里的

这里的"全局状态"并不是单独的 store,而是根组件实例。

app.ts 里,this.connect() 会调用:

  • connectGatewayInternal(this)

也就是说,整个 OpenClawApp 实例被作为 host 传给了 app-gateway.ts

然后 app-gateway.ts 里会:

  1. new GatewayBrowserClient(...)
  2. 把它挂回 host.client
  3. 用这个实例继续维护连接和事件

所以 controller 后面才能直接使用:

  • state.client.request(...)

因为这个 client 已经被绑定到根 app 状态对象上了。

为什么要这样分层

从工程角度,这样拆有几个好处。

1. view 层变轻

如果 view 直接做聊天发送逻辑,那 views/chat.ts 就必须自己处理:

  • busy 判断
  • stop 逻辑
  • slash command
  • queue
  • 草稿恢复
  • 网络失败恢复

这样页面会非常重,也很难维护。

2. 功能逻辑集中

把聊天行为放在 app-chat.ts,就能让"聊天这个功能"的逻辑集中在一个地方。

这比散落在:

  • view
  • app.ts
  • controller

里更容易维护。

3. 传输层可替换

把 WS 封装在 gateway.ts,可以让应用层不直接依赖原生 WebSocket

虽然当前实现仍然与 OpenClaw Gateway 协议强耦合,但至少耦合点集中在少数文件中。

4. 根对象作为共享状态容器,开发速度快

虽然这种方式没有独立 store 那么严格,但对当前这类工具型控制台前端来说,开发和改动会更直接。

如果我们做自己的 UI,但仍然接 OpenClaw Server,需要做什么

这里的前提要说清楚:

  • 页面是我们自己的
  • 后端仍然是 OpenClaw Server
  • 前端不复用 OpenClaw 现有 UI 代码
  • 我们会自己写 client

在这个前提下,这一节的重点就不是"复用哪些前端文件",而是"我们自己需要补齐哪些能力,才能和 OpenClaw Server 正常通信"。

换句话说,现有前端代码在这里更多是参考实现,而不是直接复用对象。

如果把"我们自己的实现"画成结构图,大概应该长这样:
我们自己的页面 / 组件
我们自己的状态层
我们自己的事件协调层
我们自己的 OpenClaw WS Client
OpenClaw Server
我们自己的动作封装层

sendMessage / abort / loadSessions / loadConfig

1. 首先要明确:我们要对接的是 OpenClaw Gateway 协议

既然后端还是 OpenClaw Server,那么我们自己的前端无论页面长什么样,本质上还是要接它当前暴露出来的通信协议。

这意味着我们自己必须实现或理解这些能力:

  • WebSocket 建连
  • connect 握手
  • req / res / event 帧模型
  • 认证信息的组织方式
  • 请求与响应的对应关系
  • 服务端事件的分发
  • 断线重连和异常处理

也就是说,虽然我们"不复用代码",但不能"不理解协议"。

2. 我们自己的前端,至少要自己实现哪些模块

如果不复用 OpenClaw 现有前端代码,建议把自己的前端拆成下面几块。

2.1 自己的 WS client

这是最核心的一层。

当前 OpenClaw 前端的 GatewayBrowserClient 给了一个很清楚的参考:一个浏览器端的 WS client 至少要支持:

  • start()
  • stop()
  • request(method, params)
  • 收到服务端 event 后触发回调
  • 收到 response 后 resolve/reject 对应 promise
  • close 后做错误处理和重连

即使我们完全自己写,也建议保留类似抽象。

自己写这个 client 时,至少要实现:

  1. 连接状态管理
  2. 请求 ID 生成
  3. pending request 映射表
  4. req 帧发送
  5. res 帧解析
  6. event 帧解析
  7. connect 握手
  8. close / error / reconnect 策略
2.2 自己的应用状态层

即使页面是我们自己写,也仍然需要一个"状态中枢"。

不一定要像 OpenClaw 这样用一个根组件实例承载所有状态,但你至少要有一层统一状态来管理:

  • 当前是否已连接
  • 当前 sessionKey
  • 当前消息列表
  • 当前 stream 内容
  • 当前 runId
  • 当前错误信息
  • 当前等待中的请求状态

如果没有这一层,view 很快就会和 WS 处理逻辑缠在一起。

2.3 自己的事件协调层

当前 OpenClaw 的 app-gateway.ts 本质上是一个"连接和事件协调层"。

我们自己写 UI 时,也最好单独做这一层,而不要让 view 直接吃 WS event。

这一层建议负责:

  • 初始化 client
  • 注册 onHello / onEvent / onClose / onGap 之类的回调
  • 把 event 转换成页面状态变化
  • 做 run 生命周期处理
  • 做重连恢复

简单说:

  • client 负责"收到消息"
  • 事件协调层负责"这条消息对页面意味着什么"
2.4 自己的 action / controller 层

如果你的页面上有"发送消息""停止生成""加载配置""加载 agent 列表"这些动作,建议仍然保留一个类似 controller 的层。

原因是:

  • view 不应该知道具体方法名
  • view 不应该自己拼请求参数
  • view 不应该直接知道 WS 帧结构

这一层建议做的事:

  • 对 OpenClaw Server 方法做封装
  • 例如封装 chat.sendchat.abortsessions.reset
  • 把业务参数转成 OpenClaw 要的协议参数
  • 处理错误映射

3. 如果只是做一个最小可用页面,需要先打通哪些能力

如果目标是"先做一个最小可用 UI",建议不要一开始就做完整控制台,而是先打通一个最小闭环。

这个最小闭环通常是聊天链路:

  1. WS 建连成功
  2. 完成 OpenClaw 的 connect 握手
  3. 可以发 chat.send
  4. 可以接收聊天事件
  5. 可以在终态时收尾
  6. 可以发 chat.abort

因为一旦这条链路通了,说明下面几层都基本通了:

  • 连接
  • 协议
  • 请求
  • 响应
  • 事件
  • 页面状态回流

4. 我们自己写 client 时,需要重点参考现有前端的哪些设计

虽然不复用代码,但下面这些设计思想非常值得保留。

4.1 请求-响应映射

当前前端通过请求 ID 和 pending map 来把 res 帧回填到对应 promise。

自己写 client 时,这个机制几乎一定要有。

否则你无法优雅地写:

  • await request("chat.send", ...)
4.2 event 和 response 分流

当前协议是明显双轨的:

  • res 负责某个 request 的结果
  • event 负责服务端主动推送

自己写的时候,不要把这两类消息混在一起处理。

4.3 运行状态与页面状态解耦

当前实现里,真正决定"队列是否继续""run 是否结束"的,不是 view,而是 app 层和事件协调层。

这个思路建议保留。

否则页面会很快出现:

  • 一个按钮管太多事情
  • 一个组件维护太多隐式状态
4.4 transport 和 UI 分离

即使你是自己写页面,也不要让 UI 组件直接 new WebSocket

更好的做法仍然是:

  • transport 层单独封装
  • 状态层单独封装
  • 页面只通过回调和状态工作

5. 针对 OpenClaw Server,自研前端需要完成的实际工作清单

下面这份清单更接近真正要做的事。

5.1 协议理解

需要先确认并验证:

  • 建连 URL
  • 握手流程
  • connect challenge 是否存在
  • 请求帧格式
  • 响应帧格式
  • 事件帧格式
  • 认证参数需要哪些字段
5.2 client 实现

需要自己完成:

  • WS 封装
  • 请求 ID 管理
  • pending promise 管理
  • 消息解析
  • 重连策略
  • 错误处理策略
5.3 页面状态模型设计

需要定义自己的状态结构,例如:

  • connectionState
  • currentSessionKey
  • messages
  • streamText
  • activeRunId
  • lastError
  • queuedMessages
5.4 事件到状态的映射

需要自己规定:

  • 收到 hello 后怎么更新状态
  • 收到 chat 相关 event 后怎么更新消息列表
  • 收到 final/error/aborted 后怎么清理 run 状态
  • 断线时页面显示什么
  • 重连后是否恢复某些状态
5.5 动作封装

至少要实现你页面需要的动作封装,例如:

  • sendMessage()
  • abortMessage()
  • loadSessions()
  • resetSession()

这些方法内部再去调 OpenClaw Server 对应的方法。

5.6 页面实现

最后才是页面本身:

  • 聊天输入框
  • 消息列表
  • 发送按钮
  • 停止按钮
  • 连接状态 UI
  • 错误提示 UI

也就是说,UI 最后做,但不是最先做。

6. 推荐实施顺序

在"自己写 client、自己写 UI、后端仍然是 OpenClaw Server"的前提下,建议按这个顺序推进:

  1. 先读懂并验证 OpenClaw Server 的 WS 协议
  2. 先写最小 client,能连、能发 request、能收 response/event
  3. 再写最小状态层
  4. 再打通 chat.send / chat.abort / chat event 的闭环
  5. 再补会话、配置、agents 等功能
  6. 最后再做完整页面整理和 UI 体验优化

原因很简单:

  • 协议没打通,页面做得再好也只是壳
  • 状态没设计好,事件一多 UI 就会乱
  • chat 链路打通后,再扩展别的功能会稳很多

用路线图表示会更直观:

  1. 读懂协议
  2. 写最小 WS client
  3. 写最小状态层
  4. 打通 chat.send / chat.abort / chat event
  5. 扩展 sessions / config / agents
  6. 完整 UI 和交互优化

当前架构的强耦合点

如果要接自己的后端,这几个地方耦合最深,要重点注意。

1. Gateway 协议帧格式

GatewayBrowserClient 假定了固定的协议结构:

  • type: "req"
  • type: "res"
  • type: "event"

如果你的服务不是这个格式,gateway.ts 一定要改。

2. connect 握手逻辑

当前客户端不是普通一连就发消息,它有 challenge、device identity、token、role、scopes 等流程。

这部分如果你的后端没有,就需要简化。

3. 聊天 run 生命周期

聊天队列依赖:

  • chatRunId
  • run 终态事件
  • 最终事件后 flush 队列

如果你的后端没有这一套,不能直接照搬当前 chat queue 逻辑。

4. controller 的方法名约定

目前 controller 强依赖方法名,例如:

  • chat.send
  • chat.abort
  • sessions.reset

如果你的后端方法名和参数结构不同,controller 必须改。

总结

当前 OpenClaw 前端的核心流转逻辑为:

  • view 负责交互触发
  • app.ts 暴露方法
  • app-* 负责功能逻辑
  • controllers/* 负责后端调用
  • gateway.ts 负责 WS 封装
  • app-gateway.ts 负责把 WS 事件回流到 UI 状态

在DingOS的自研产品体系中,如果我们的目标是"自己做 UI,但接 OpenClaw Server,而且前端代码自己写",最重要的结论是:

  • 现有前端代码最重要的价值是参考架构和协议实现思路
  • 我们真正要自己补的是 client、状态层、事件协调层、动作封装层
  • 不应该从 view 开始做,而应该先从协议和 client 开始打通
  • chat 是最适合做第一阶段验证的最小闭环

从实施角度看,最小可行路径通常是:

  1. 先写自己的 WS client
  2. 先接通 OpenClaw Server 协议
  3. 再写自己的状态层和事件协调层
  4. 再做聊天最小页面
  5. 最后再扩展更多管理能力

如果你已经理解下面这些文件,基本就理解了这个前端的主干:

  • ui/src/ui/app.ts
  • ui/src/ui/app-render.ts
  • ui/src/ui/app-chat.ts
  • ui/src/ui/app-gateway.ts
  • ui/src/ui/controllers/chat.ts
  • ui/src/ui/gateway.ts

后面无论是:

  • 复用当前 UI 改成自己的 WS
  • 还是自己重做一个页面参考这套结构

这几个文件都是最值得先读懂的部分。

综上,OpenClaw 前端架构的核心价值在于分层解耦的设计思路,这也是鼎道智联 DingVerse 服务自研 UI 对接 OpenClaw Server 的关键参考。针对仍在优化、暂未上线的 DingVerse 产品,自研 UI 无需拘泥于复用现有代码,优先打通 WS 协议与 chat 链路的最小闭环,再逐步扩展功能更高效。

若你在对接过程中遇到协议理解、client 开发、状态层设计等问题,或是有适配 DingVerse 场景的优化思路想要交流,欢迎在评论区留言,我们一起探讨解决方案,助力产品迭代优化与上线。

相关推荐
尘世中一位迷途小书童2 小时前
一套完整的给予ceium封装的组件库,可满足企业级开发
前端
vivo互联网技术2 小时前
深度解析 vivo 活动系统全球化实践
架构
Z_Wonderful2 小时前
微前端:Webpack 配置 vs Vite 配置 超清晰对比
前端·webpack·node.js
码云数智-园园2 小时前
HTTPS是如何工作的?从HTTP到HTTPS的加密演进
前端
隔窗听雨眠2 小时前
HTML头部元信息避坑指南
前端·html
愚公搬代码2 小时前
【愚公系列】《OpenClaw实战指南》012-分析与展示:一句话生成可发给老板的报表与 PPT(Excel/WPS 表格自动化处理)
人工智能·自动化·powerpoint·excel·飞书·wps·openclaw
Gauss松鼠会2 小时前
【openGauss】openGauss 磁盘引擎之 ustore
java·服务器·开发语言·前端·数据库·经验分享·gaussdb
LIO2 小时前
前端响应式页面开发全攻略:核心技术 + 实现效果 + 实战指南
前端·响应式设计
得物技术2 小时前
AI驱动:从运营行为到自动化用例的智能化实践|得物技术
前端·ai编程·全栈