•
阅读时长 2 分钟

AI 生成代码的预览方案:HTML、React 组件和完整项目

目录

让 AI 生成页面代码之后,通常还希望直接看到页面,并且能够点击按钮、修改内容。预览功能看起来只是右侧放一个窗口,实际需要处理的事情取决于生成了什么代码。

完整 HTML 可以交给浏览器解析;React 组件中的 JSX 需要转换;多文件项目还涉及文件、依赖和开发服务。这三种输入适合的实现方式不同。

HTML 单文件:iframe srcdoc

如果生成结果包含 HTML、内联样式和脚本,可以用 iframe 的 srcdoc 加载。下面是一个独立页面,保存为 preview.html 后通过本地 HTTP 服务打开:

<!doctype html>
<html lang="zh-CN">
<meta charset="utf-8">
<title>HTML 预览</title>
<iframe id="preview" title="页面预览" sandbox="allow-scripts"
  style="width:100%;height:240px;border:1px solid #ccc"></iframe>
<script>
  document.querySelector('#preview').srcdoc = `
    <!doctype html><meta charset="utf-8">
    <style>button { padding: 12px; color: #145; }</style>
    <h1>生成的页面</h1>
    <button onclick="this.textContent = '已点击'">点击按钮</button>
  `;
</script>
</html>

浏览器负责解析 HTML、应用 CSS 和执行脚本,不需要 JSX 编译器。点击按钮后文字变化,也能确认预览里执行了交互代码,而不是只显示截图。

sandbox 允许脚本,但没有给 allow-same-origin。不要为了方便操作子页面,把生成代码和父页面放进可以互相访问的同源环境。实际接收未知代码时还要限制网络等权限;这个固定内容示例不是完整的代码执行平台。

更新 srcdoc 会重新加载 iframe 文档。频繁替换可能出现白屏,更新时的切换方式可以参考 iframe 双缓冲实现。双缓冲处理显示切换,不负责 JSX 编译或执行隔离。

React 单文件:转换 JSX,再渲染

浏览器不能直接执行下面这种 JSX:

function App() {
  const [count, setCount] = React.useState(0);
  return <button onClick={() => setCount(count + 1)}>计数 {count}</button>;
}

这类输入可以通过 Babel Standalone 转换,再在 iframe 内加载 React 和 ReactDOM。执行过程是:

组件源码 → JSX 转换 → 子页面执行 JavaScript → React 渲染

适合这个方案的输入范围需要约定清楚。例如只支持一个 App 函数,React 由预览器提供,没有 import/export。

一旦允许 import './style.css',就要知道这个文件在哪里;允许 npm 包时,还要处理包版本、下载、模块解析和浏览器兼容性。Babel 转换 JSX,并不会自动完成这些事情。完整的单文件实现见 React 组件预览器。

完整项目:需要文件和运行环境

如果生成结果是一份项目,例如 package.json、多个组件、样式文件和 Vite 配置,仅靠 srcdoc 不够。需要把文件组织起来、安装依赖,再启动构建或开发服务。

WebContainers 提供在浏览器中运行 Node.js 项目的环境,可以挂载文件、运行命令并启动服务。能力和环境要求见 官方介绍及 运行所需响应头。

另一种方式是在服务端的独立运行环境中启动项目,再把预览地址提供给前端。它增加了服务端计算、隔离和生命周期管理的工作,不能直接在博客或主应用所在进程中执行任意生成项目。

这里只比较完整项目需要的能力,没有运行 WebContainer 或服务端项目沙箱,也没有测量它们的启动速度。环境支持和资源消耗需要根据实际目标浏览器、项目依赖继续检查。

按输入范围选择

输入可用方式主要需要处理的事情
完整 HTMLiframe srcdoc样式、脚本权限、资源加载、更新闪烁
无模块依赖的 React 组件Babel + React + iframeJSX 转换、组件入口、编译与执行错误
多文件项目浏览器或服务端项目运行环境文件、安装依赖、启动服务、资源和权限限制

如果功能只要求生成一张落地页,约定完整 HTML 可以减少模块和依赖处理。如果需要 React 组件交互,单文件预览能覆盖较小范围。生成结果需要真实项目结构时,才需要项目运行环境。

代码能显示,也要考虑它能做什么

生成的代码可能请求网络、读取它能够访问的数据,也可能包含无限循环。iframe sandbox 和 CSP 能限制一部分访问,但不能据此保证任意代码不会卡住页面或消耗大量内存。

还要区分不同错误:语法错误在编译阶段出现,组件报错在运行阶段出现,外部资源失败则需要查看请求。只显示“预览失败”,会把这些问题混在一起。

输入范围、运行方式和权限一起确定,后面才容易解释一个生成结果为什么可以运行,另一个为什么需要补充文件或修改代码。