
本文详解如何在 Next.js(App Router)中正确嵌入 Chaindesk 提供的模块化聊天机器人脚本与自定义元素,解决 type="module" 脚本加载、JSX 与 HTML 混合渲染及样式绑定等常见问题。
本文详解如何在 next.js(app router)中正确嵌入 chaindesk 提供的模块化聊天机器人脚本与自定义元素,解决 `type="module"` 脚本加载、jsx 与 html 混合渲染及样式绑定等常见问题。
在 Next.js(尤其是 App Router)中直接嵌入第三方模块化 <script type="module"></script> 并初始化自定义 Web Component(如 <chaindesk-chatbox-standard></chaindesk-chatbox-standard>),需兼顾 React 的 JSX 渲染规则与浏览器原生模块加载机制。直接在组件中写 <script></script> 标签会导致 SSR/SSG 阶段执行失败或被忽略;而 next/script 不支持 type="module" 的内联动态导入,因此需采用更可控的方式。
✅ 推荐方案:使用 dangerouslySetInnerHTML 动态注入模块脚本
React 提供 dangerouslySetInnerHTML 作为安全边界内的 HTML 注入方式,适用于必须运行的第三方模块脚本。关键点在于:
- 脚本内容必须为纯字符串(不可含 JSX 表达式或变量插值,除非已转义);
-
type="module"属性必须显式声明; - 初始化逻辑应确保 DOM 已就绪(Chaindesk 的
initStandard()内部已处理,无需额外useEffect); - 自定义元素
<chaindesk-chatbox-standard></chaindesk-chatbox-standard>是标准 Web Component,可直接作为 JSX 元素使用,但style必须传入对象而非字符串。
示例代码(app/page.tsx):
'use client'; // 必须标记为客户端组件,因涉及 DOM 操作和模块加载
export default function ChatPage() {
const chatboxScript = `
import Chatbox from 'https://cdn.jsdelivr.net/npm/@chaindesk/embeds@latest/dist/chatbox/index.js';
Chatbox.initStandard({
agentId: 'your-agent-id-here', // 替换为真实 ID
contact: {
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
userId: '42424242',
},
initialMessages: ['Hello! How can I help you today?'],
context: 'You are assisting John. Greet him by name.',
});
`;
return (
<div className="flex flex-col lg:flex-row h-screen gap-4 p-4">
{/* 左侧:PDF 查看区域(示例占位) */}
<div className="flex-1 bg-gray-50 rounded-lg border border-gray-200 flex items-center justify-center">
<p className="text-gray-500">PDF Viewer (e.g., using react-pdf)</p>
</div>
{/* 右侧:Chaindesk 聊天窗口 */}
<div className="flex-1 flex flex-col">
{/* 动态注入模块脚本 */}
<script type="module" dangerouslySetInnerHTML={{ __html: chatboxScript }} />
{/* Web Component 容器 — 注意 style 是对象,非字符串 */}
<chaindesk-chatbox-standard
style={{ width: '100%', height: '650px' }}
/>
</div>
</div>
);
}⚠️ 重要注意事项
-
必须添加
'use client':所有涉及dangerouslySetInnerHTML、DOM 操作或第三方脚本初始化的组件都需明确声明为客户端组件,否则会在服务端渲染时报错。 -
避免敏感信息硬编码:
agentId、邮箱、用户 ID 等应通过环境变量(如process.env.NEXT_PUBLIC_AGENT_ID)注入,切勿暴露在前端源码中。 -
CDN 版本稳定性:
@chaindesk/embeds@latest可能引入不兼容更新,建议锁定版本(如@latest-dist或具体语义化版本)以保障生产稳定性。 -
样式与响应式:
<chaindesk-chatbox-standard></chaindesk-chatbox-standard>支持 CSS 自定义属性(如--cd-primary-color),可通过全局 CSS 或style属性进一步定制外观。 -
错误兜底与加载状态:可在组件内添加
useEffect监听customElements.get('chaindesk-chatbox-standard')是否注册成功,并显示加载提示或降级 UI。
✅ 替代方案对比(不推荐)
| 方案 | 问题 |
|---|---|
放入 /public/chat.html 并用 iframe 加载 |
失去 React 状态联动能力,跨域限制、SEO 友好性差,无法共享用户上下文(如登录态) |
使用 next/script + strategy="afterInteractive"
|
不支持 type="module" 内联代码,且无法保证 initStandard() 在自定义元素挂载前执行 |
useEffect 动态 import() + appendChild
|
过度复杂,易触发重复初始化,且绕过 React 渲染生命周期 |
综上,dangerouslySetInnerHTML 是当前最简洁、可靠且符合 Chaindesk 官方嵌入规范的集成方式。只要严格遵循客户端组件约束与安全实践,即可在 Next.js 中无缝融合 PDF 查看器与 Chaindesk 智能代理,构建专业级文档问答界面。


















