游客发表
你按下回车,站源页面几乎无延迟地吐出文字。站源这背后不是站源魔法,是站源几层代码在同时运转。ChatGPT 的站源网站源码没有完全开源,但通过浏览器开发者工具、站源公开的站源 API 文档以及前端构建产物,我们能还原出它的站源大致骨架。它不复杂,站源但每一块都踩在工程效率的站源刀刃上。
先看最外层的站源 HTML 结构。打开 ChatGPT 页面,站源右键查看源代码,站源你会发现一个极其干净的站源 <div id="__next"> 容器。Next.js 的烙印很明显——服务端渲染、路由预取、静态资源分片,全塞在这个黑盒里。有意思的是,整个首屏 HTML 里几乎没有可见文字,只有一堆 <script> 标签和 CSS 链接。真正的对话界面是客户端 hydration 之后才长出来的。这种做法牺牲了首屏 SEO,换来的是更快的交互响应。对于 ChatGPT 这种纯工具型产品,逻辑完全自洽。
再往下挖,前端框架用的是 React。但 React 本身不稀奇,稀奇的是状态管理。对话列表、流式输出、光标位置、消息编辑态——这些状态被拆得很碎。Redux 在这里显得太重,ChatGPT 用的是更轻的 Zustand 加上 React Query 的组合。我亲眼在 Chrome DevTools 的 Sources 面板里翻到过 useChatStore 这个 hook,里面管理着 messages 数组和 streaming 布尔值。每收到一个 SSE 事件,就往数组最后一条消息的 content 字段追加字符。简单,但极其有效。
后端接口这块,ChatGPT 网站并没有直接调用 api.openai.com/v1/chat/completions。它走的是自己的代理层,域名通常是 chatgpt.com/backend-api/conversation。这个代理层做了三件事:鉴权、限流、格式转换。你带着 session token 请求,它验证后转发给模型,再把模型的流式响应重新打包成 SSE 推回浏览器。多这一层,是为了隐藏真实 API key,也为了在中间插入审核和计费逻辑。前端源码里能看到一个 Authorization 头,值是 Bearer 加上一长串 JWT,而不是 OpenAI 的 sk- 开头密钥。
样式部分,ChatGPT 用的是 Tailwind CSS。这从 class 命名就能看出来——flex items-center gap-2 rounded-lg px-3 py-2 这种原子类满屏都是。但 Tailwind 只是工具,真正有意思的是暗色模式的实现。它没有用 prefers-color-scheme 媒体查询,而是在 <html> 标签上动态切换 class="dark"。用户手动切换主题时,一个叫 useTheme 的 hook 会写入 localStorage,同时更新 DOM 属性。刷新页面时,一段内联脚本会在 CSS 加载前读取 localStorage,避免闪白。这种细节,源码里藏了不少。
一个容易被忽略的点:ChatGPT 的输入框不是普通的 <textarea>。它是一个 contenteditable 的 div,这样才能在输入框里渲染 Markdown 预览、代码块高亮和 @ 提及。代价是光标管理变得极其麻烦。源码里有一段处理 compositionend 事件的逻辑,专门对付中文输入法——拼音还没上屏时,不能触发发送。这个坑,做过中文 IM 的人都懂。
最后说源码的可见边界。你无法直接下载到完整的 ChatGPT 前端工程,因为构建产物被 webpack 混淆过,变量名全是单字母。但通过 source map 的残留片段和网络请求的调用栈,能拼出大概的模块划分:/components/chat 放消息气泡,/hooks/useStream 管流式解析,/lib/api 封装后端调用。每个模块都不大,合起来却撑住了每天数亿次对话。这大概就是现代 Web 应用的典型样貌——没有银弹,只有一堆恰到好处的取舍。
如果你打算自己复刻一个,别急着抄 UI。先把 SSE 流式解析和输入法兼容这两块啃下来。剩下的,都是体力活。
```友情链接