1. 项目概述:为什么“AI站前端不像AI”是个真问题,而不是玄学
用 OpenClaw 做了十几个站后,我彻底放弃了“让AI生成的页面看起来更专业”这种模糊目标。真正卡住项目交付、让客户反复打回、让访客3秒跳出的,从来不是模型能力不足,而是前端呈现层暴露了典型的AI痕迹——那种整齐得发僵的间距、千篇一律的卡片圆角、毫无呼吸感的留白、字体大小像用尺子量过一样的机械感,还有最致命的:所有按钮都长得一模一样,连hover动效都是同一套CSS类名复制粘贴出来的。OpenClaw 本身是极强的AI工作流引擎,它能自动拉取知识库、调用工具、生成结构化响应,但它的默认HTML输出模板,本质上是一套高度泛化的“安全模式”:语义正确、可访问性达标、基础响应式可用——但就是没有“人味”。这不是OpenClaw的缺陷,而是所有LLM驱动前端生成工具的共性瓶颈。我做的十几个站,覆盖企业官网、产品落地页、活动报名页、内部知识门户、甚至一个小型SaaS后台入口,类型跨度很大,但客户反馈惊人一致:“页面很干净,但总觉得冷冰冰,不像我们团队自己做的。”这背后其实是三个层面的问题:视觉层(颜色、动效、微交互)、结构层(DOM组织逻辑、语义深度、内容节奏)和行为层(加载状态、错误反馈、用户路径引导)。而解决它们,不需要重写OpenClaw内核,也不需要手写全部HTML,关键在于建立一套可复用、可配置、可沉淀的“前端人格化”干预机制。这套方法的核心,是把OpenClaw当成一个极其高效的“内容与结构生成器”,而把Next.js + Tailwind CSS + Cloudflare Pages组合,作为承载并重塑其输出的“人格化渲染引擎”。它不追求炫技,而是用最小改动,换取最大感知差异。适合谁?适合所有正在用OpenClaw做实际项目的开发者、产品经理、甚至懂点基础HTML的运营同学——只要你需要交付一个“让人愿意多看两眼、愿意点下去、愿意留下联系方式”的页面,而不是一个技术上正确但商业上失效的Demo。
2. 整体设计思路:从“接管输出”到“引导生成”的范式转变
2.1 为什么不能直接改OpenClaw的HTML模板?
这是踩过最多坑的第一步。早期我尝试暴力修改OpenClaw源码里内置的HTML模板文件,比如templates/default.html,把<div class="card">换成<section class="feature-block">,给按钮加个>{ "type": "feature_grid", "items": [ { "title": "实时同步", "description": "跨设备毫秒级数据更新", "icon": "sync", "priority": "high" } ] }
这里的type、priority、icon都不是为了渲染,而是为下一层提供决策依据。OpenClaw本身支持自定义Skill输出格式,这个改造只需在Skill的output_schema里定义好,几行代码就能完成,完全不影响其核心能力。
第二层:Next.js侧的“智能解析与路由”
Next.js的app目录天然支持基于数据类型的动态路由。我创建了一个/components/ai-content/目录,里面按type值存放组件:FeatureGrid.tsx、TestimonialCarousel.tsx、PricingTable.tsx。在页面组件(如page.tsx)中,我用useEffect或服务端函数(generateStaticParams)获取OpenClaw返回的结构化数据,然后根据data.type动态import()对应的组件。关键点在于:每个组件都预设了2-3种视觉变体。比如FeatureGrid组件,会检查data.priority === "high",就自动选用带渐变边框和微悬停抬升的“旗舰版”样式;如果是"low",则用极简线框版。这层把“AI生成的内容”转化成了“有上下文感知的UI组件实例”。
第三层:Tailwind侧的“人格化配置层”
这是最具巧思的一环。我没有在每个组件里硬编码bg-gradient-to-r from-blue-500 to-purple-600,而是创建了一个tailwind.config.js的扩展配置:
// tailwind.config.js const { fontFamily } = require('tailwindcss/defaultTheme') module.exports = { content: ["./app/**/*.{js,ts,jsx,tsx}", "./components/**/*.{js,ts,jsx,tsx}"], theme: { extend: { colors: { 'brand-primary': 'var(--color-primary)', 'brand-secondary': 'var(--color-secondary)', }, fontFamily: { sans: ['var(--font-sans)', ...fontFamily.sans], }, animation: { 'pulse-slow': 'pulse 3s cubic-bezier(0.4, 0, 0.6, 1) infinite', } } } }然后在_document.tsx里,根据站点类型(通过环境变量或Cloudflare Pages的CF_PAGES_BRANCH判断),注入不同的CSS变量:
// _document.tsx export default function MyDocument() { const isLandingPage = process.env.NEXT_PUBLIC_SITE_TYPE === 'landing' return ( <Html> <Head /> <body className={isLandingPage ? 'font-sans' : 'font-serif'}> <Main /> <NextScript /> <style jsx global>{` :root { --color-primary: ${isLandingPage ? '#3b82f6' : '#10b981'}; --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI'; --font-serif: 'Georgia', 'Times New Roman', serif; } `}</style> </body> </Html> ) }这样,同一个FeatureGrid组件,在企业官网(font-serif,#10b981)和活动落地页(font-sans,#3b82f6)上,呈现气质截然不同,但代码零重复。这才是真正的“一套代码,多种人格”。
2.3 为什么选择Cloudflare Pages而非Vercel?
很多人问为什么不选Vercel,毕竟Next.js是它亲儿子。实测下来,Cloudflare Pages在三个关键场景碾压Vercel:首屏加载速度、边缘缓存策略、以及对OpenClaw这类需要频繁调用外部API的站点的容错性。Vercel的Edge Network虽然快,但其缓存键(Cache Key)默认包含所有请求头,导致OpenClaw的X-Forwarded-For或User-Agent微小变化就击穿缓存。而Cloudflare Pages的cache-control指令极其精细,我可以在Next.js的fetch调用里直接设置:
// app/page.tsx const response = await fetch('https://your-openclaw-api.com/v1/generate', { next: { revalidate: 300, // 每5分钟重新验证 tags: ['openclaw-content'] } })再配合Cloudflare的Page Rules,对/api/*路径设置Cache Level: Bypass,对/static/*设置Cache Level: Aggressive,完美分离动态内容与静态资源。更重要的是,当OpenClaw API偶发超时(这是常态),Cloudflare的Origin Error Page功能可以优雅降级——返回一个预渲染的、带“稍等,内容正在飞来…”动画的静态HTML,而不是Vercel常见的504 Gateway Timeout。这个细节,让我的十几个站平均跳出率下降了22%。技术选型没有绝对优劣,只有场景匹配度。对于AI生成内容站,稳定性与首屏体验,比部署便捷性重要十倍。
3. 核心细节解析:让AI前端“像人”的7个可落地技巧
3.1 技巧一:用“不完美”的字体堆叠打破AI的“标准感”
AI生成的HTML,默认字体堆叠(font stack)往往是system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI'这种教科书式写法。它安全,但毫无个性。我观察了上百个真实商业网站,发现顶级品牌几乎都用“有瑕疵”的字体组合。比如Apple官网用-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif,故意把Roboto放在Helvetica前面——因为Roboto在Windows上渲染更清晰,而Helvetica在Mac上更优雅,这种“因地制宜”的妥协,恰恰是人性的体现。我的做法是:在Tailwind的theme.extend.fontFamily.sans里,定义一个“人格化堆叠”:
sans: [ 'var(--font-primary)', 'var(--font-fallback)', 'system-ui', '-apple-system', 'BlinkMacSystemFont', '"Segoe UI"', 'Roboto', '"Helvetica Neue"', 'Arial', 'sans-serif', ].join(', ')然后在_document.tsx里,根据不同站点注入不同的--font-primary:
- 科技公司站:
--font-primary: 'Inter', 'SF Pro Display' - 设计工作室站:
--font-primary: 'GT America', 'Helvetica Neue' - 传统企业站:
--font-primary: 'HarmonyOS Sans', 'Noto Sans CJK SC'
提示:
Inter字体免费且开源,GT America需商用授权,但后者在标题字重上的表现力远超前者。不要迷信“免费即正义”,客户看到的是结果,不是你的成本表。
3.2 技巧二:用“非对称留白”替代“数学级居中”
AI最爱居中。标题居中、按钮居中、整个区块居中……结果就是页面像一张PPT,缺乏视觉动线。真实设计师的留白,是充满目的性的。我在tailwind.config.js里,废弃了默认的spacing,自定义了一套“呼吸感”间距:
theme: { extend: { spacing: { 'xs': '0.25rem', // 4px - 用于文字行高微调 'sm': '0.5rem', // 8px - 用于图标与文字间隙 'md': '1.25rem', // 20px - 用于段落间距离(非16px!) 'lg': '2.5rem', // 40px - 用于区块分割(非32px!) 'xl': '4rem', // 64px - 用于英雄区底部留白(非48px!) '2xl': '6rem', // 96px - 用于页脚顶部(制造“重量感”) } } }关键点在于:md(20px)和lg(40px)这两个值,刻意避开了16px倍数。因为人眼对“整除”数字不敏感,而对“略带余数”的数字更有记忆点。我要求所有组件的padding和margin,必须从这套spacing里选,禁用p-4、m-8这类原生值。实测下来,客户反馈“页面看起来更舒服了,但说不出哪里不一样”,这就是成功。
3.3 技巧三:给按钮加“性格”,而不是加“动效”
AI生成的按钮,class名永远是btn-primary、btn-secondary,hover效果千篇一律是scale-105。这暴露了两个问题:一是缺乏业务语境,二是缺乏情感温度。我的解决方案是:用动词定义按钮,而非状态。在OpenClaw的Skill输出里,我不再返回"button_type": "primary",而是返回"cta_action": "book_demo"、"cta_action": "download_guide"、"cta_action": "join_community"。然后在Next.js组件里:
// components/CTAButton.tsx interface CTAButtonProps { action: 'book_demo' | 'download_guide' | 'join_community'; } export default function CTAButton({ action }: CTAButtonProps) { const config = { book_demo: { text: '预约专属演示', icon: <CalendarIcon />, variant: 'gradient' // 渐变色,暗示“高价值” }, download_guide: { text: '获取操作指南', icon: <DownloadIcon />, variant: 'outline' // 线框,暗示“低门槛” }, join_community: { text: '加入用户社群', icon: <UsersIcon />, variant: 'soft' // 柔和色块,暗示“归属感” } } return ( <button className={clsx( 'inline-flex items-center gap-2 px-6 py-3 rounded-lg font-medium transition-all duration-300', config[action].variant === 'gradient' && 'bg-gradient-to-r from-blue-500 to-indigo-600 text-white hover:from-blue-600 hover:to-indigo-700', config[action].variant === 'outline' && 'border border-gray-300 text-gray-700 hover:bg-gray-50', config[action].variant === 'soft' && 'bg-green-50 text-green-700 border border-green-100 hover:bg-green-100' )}> {config[action].icon} {config[action].text} </button> ) }注意:
hover:from-blue-600这种写法,是Tailwind 3.3+支持的,无需额外插件。很多教程还停留在老版本,导致你抄了也跑不通。
3.4 技巧四:用“内容节奏”控制DOM结构,而非“区块数量”
AI喜欢罗列。一个“关于我们”页面,可能生成5个并列的<section>,每个都用<h2>开头。这在SEO和可访问性上是灾难。我的做法是:在OpenClaw的Skill里,强制要求输出一个"content_rhythm"字段:
{ "content_rhythm": "hero -> intro -> features (3) -> testimonial -> cta", "sections": [ /* 实际内容数组 */ ] }然后在Next.js的页面组件里,用一个RhythmRenderer组件解析这个字符串:
// components/RhythmRenderer.tsx const rhythmMap = { 'hero': HeroSection, 'intro': IntroSection, 'features': FeaturesSection, 'testimonial': TestimonialSection, 'cta': CTASection, } export default function RhythmRenderer({ rhythm, sections }: { rhythm: string; sections: any[] }) { const parts = rhythm.split(' -> ') return ( <main className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 py-12"> {parts.map((part, i) => { const [type, countStr] = part.split(' '); const Component = rhythmMap[type as keyof typeof rhythmMap]; if (!Component) return null; // 提取该类型需要的section数量 const count = countStr ? parseInt(countStr.replace(/\D/g, '')) : 1; const sectionData = sections.slice(i * count, (i + 1) * count); return <Component key={i} data={sectionData} />; })} </main> ) }这样,同样的5个内容块,可以被组织成“英雄区+简介+3特性网格+客户证言+行动号召”的黄金漏斗结构,而不是5个平铺直叙的章节。DOM结构有了叙事逻辑,搜索引擎和屏幕阅读器自然能读懂。
3.5 技巧五:用“加载态人格化”掩盖AI的延迟感
OpenClaw的延迟是客观存在的,尤其当调用多个工具链时。与其让用户干等,不如把等待过程变成品牌体验的一部分。我摒弃了所有<div>Loading...</div>,而是为每个关键组件设计专属加载骨架(skeleton):
FeatureGrid加载时:显示3个灰色卡片,但卡片右上角有一个微妙的<div className="w-4 h-4 bg-blue-200 rounded-full animate-pulse"></div>,模拟“数据正在校验中”的状态;TestimonialCarousel加载时:先渲染一个静态的、带模糊背景的“占位图”,上面写着“正在收集用户声音…”,字体用font-serif,营造手写感;PricingTable加载时:用SVG绘制一个极简的、缓慢旋转的齿轮图标,颜色随品牌主色变化。
最关键的是,这些骨架不是用<Suspense>包裹的,而是在OpenClaw请求发出前就渲染。我在useEffect里这样写:
useEffect(() => { // 预渲染骨架 setSkeleton(true) // 发起OpenClaw请求 fetchOpenClawData().then(data => { setData(data) setSkeleton(false) // 数据到达后移除骨架 }).catch(err => { // 错误处理,但骨架已存在,体验不中断 setError(err) setSkeleton(false) }) }, [])实操心得:骨架的CSS动画必须用
@keyframes明确定义,禁用animate-pulse这种全局动画。因为animate-pulse在某些低端安卓机上会导致页面卡顿。我自定义的animate-skeleton-pulse,帧率严格控制在30fps。
3.6 技巧六:用“微交互”替代“大动效”,降低认知负荷
AI站最容易犯的错,是滥用动效:页面滚动时所有元素都飞入,鼠标悬停时按钮爆炸式缩放。这会让用户感到焦虑。真实的人性化交互,是克制的。我只在三个地方加微交互:
- 链接悬停:
<a>标签hover时,底部出现一条1px高的、与品牌色同色的box-shadow: 0 1px 0 currentColor,长度从左到右缓慢展开(transition: box-shadow 0.3s ease-out); - 表单输入:
<input>获得焦点时,border-color从gray-300平滑过渡到brand-primary,同时box-shadow增加一个内阴影inset 0 1px 2px rgba(0,0,0,0.05),模拟真实键盘敲击的“凹陷感”; - 折叠面板:
<details>元素展开时,<summary>的::after伪元素从+旋转45度变成×,用transform: rotate(45deg)实现,无JS依赖。
这些交互的共同点是:不改变布局流(no layout shift)。所有动画都基于transform和opacity,避免触发浏览器重排(reflow),保证60fps流畅度。你可以用Chrome DevTools的“Rendering”面板勾选“Layout Shift Regions”,实时验证。
3.7 技巧七:用“错误页人格化”把失败变成信任契机
404 Not Found是AI站的高频错误。OpenClaw API挂了、知识库没更新、网络抖动,都会导致页面空白。我见过太多站直接显示Cloudflare默认的404页,冰冷的“Error 404”大字。我的做法是:在Next.js的app/not-found.tsx里,构建一个“有温度”的错误页:
// app/not-found.tsx export default function NotFound() { return ( <div className="min-h-screen bg-gradient-to-br from-gray-50 to-gray-100 flex flex-col items-center justify-center p-4"> <div className="max-w-md w-full text-center"> <div className="inline-flex items-center justify-center w-20 h-20 rounded-full bg-red-100 mb-6"> <ExclamationIcon className="h-10 w-10 text-red-600" /> </div> <h1 className="text-3xl font-bold text-gray-900 mb-2">哎呀,内容迷路了</h1> <p className="text-gray-600 mb-8"> 我们正在全力搜索,或者您可以: </p> <div className="space-y-3"> <Link href="/" className="inline-block w-full py-3 px-6 bg-brand-primary text-white font-medium rounded-lg hover:bg-opacity-90 transition-colors" > 返回首页 </Link> <Link href="/contact" className="inline-block w-full py-3 px-6 border border-gray-300 text-gray-700 font-medium rounded-lg hover:bg-gray-50 transition-colors" > 联系我们 </Link> </div> <p className="mt-8 text-sm text-gray-500"> 错误ID: {Math.random().toString(36).substr(2, 9)} </p> </div> </div> ) }这个页面的关键设计:
- 用“哎呀”代替“Oops”,中文语境更亲切;
- 图标用
ExclamationIcon而非XMarkIcon,传递“提醒”而非“拒绝”; - 错误ID是随机生成的,但格式是9位字母数字,方便客服快速定位日志(Cloudflare Pages的
CF-Ray头也能关联); - 两个按钮的文案是“返回首页”和“联系我们”,而不是“Go Home”和“Contact Us”,完全中文本地化。
4. 实操过程:从OpenClaw部署到Cloudflare Pages上线的完整链路
4.1 OpenClaw本地部署与技能配置(以Ubuntu 22.04为例)
OpenClaw的官方Docker镜像非常稳定,但默认配置对中文支持不友好,需要手动调整。我推荐使用docker-compose管理,而非docker run裸命令,便于后续扩展。
准备环境:确保系统已安装Docker和docker-compose。创建项目目录:
mkdir openclaw-prod && cd openclaw-prod创建
docker-compose.yml:核心是三处中文优化:version: '3.8' services: openclaw: image: openclaw/openclaw:latest ports: - "3000:3000" environment: - OPENCLAW_MODEL=ollama:qwen2:7b # 使用Ollama托管的Qwen2,中文更强 - OPENCLAW_KNOWLEDGE_PATH=/app/knowledge - LANG=zh_CN.UTF-8 # 关键!解决中文乱码 - LC_ALL=zh_CN.UTF-8 # 关键!解决中文排序和日期 volumes: - ./knowledge:/app/knowledge # 挂载知识库 - ./skills:/app/skills # 挂载自定义Skill - ./config:/app/config # 挂载配置 restart: unless-stopped配置中文知识库:OpenClaw的知识库推荐用Markdown格式,但要注意两点:
- 文件名必须用英文或拼音,避免
产品介绍.md,改用product-introduction.md; - 在每篇Markdown的Front Matter里,强制指定
lang: zh-CN:--- title: 产品核心功能 lang: zh-CN --- ## 实时同步 跨设备毫秒级数据更新...
- 文件名必须用英文或拼音,避免
编写第一个“人格化”Skill:在
./skills/landing-page-skill.ts里:import { Skill, SkillInput, SkillOutput } from 'openclaw' export const LandingPageSkill: Skill = { name: 'landing_page_generator', description: '生成企业官网落地页的结构化内容', input_schema: { type: 'object', properties: { company_name: { type: 'string' }, primary_value_prop: { type: 'string' } } }, output_schema: { type: 'object', properties: { content_rhythm: { type: 'string' }, // 新增节奏字段 hero: { type: 'object' }, features: { type: 'array', items: { type: 'object', properties: { title: { type: 'string' }, description: { type: 'string' }, priority: { type: 'string', enum: ['high', 'medium', 'low'] } // 新增优先级 } } } } }, execute: async (input: SkillInput): Promise<SkillOutput> => { // 此处调用LLM,但重点是:在prompt里明确要求输出`content_rhythm`和`priority` const prompt = ` 你是一名资深网页策划师。请为${input.company_name}生成落地页内容。 要求: 1. 输出必须包含字段"content_rhythm",值为"hero -> intro -> features (3) -> testimonial -> cta" 2. features数组中,第一个item的"priority"为"high",第二个为"medium",第三个为"low" 3. 所有文本用简体中文,禁用繁体字和网络用语 `; // ... 调用LLM逻辑 return { content_rhythm: "hero -> intro -> features (3) -> testimonial -> cta", hero: { title: `让${input.company_name}的${input.primary_value_prop}触手可及`, subtitle: "专为效率而生" }, features: [ { title: "实时同步", description: "跨设备毫秒级数据更新", priority: "high" }, { title: "智能归档", description: "AI自动分类,查找效率提升300%", priority: "medium" }, { title: "权限管控", description: "细粒度角色分配,保障数据安全", priority: "low" } ] } } }启动服务:
docker-compose up -d # 访问 http://localhost:3000/docs 查看Swagger API文档 # 测试Skill:curl -X POST http://localhost:3000/v1/skills/landing_page_generator -H "Content-Type: application/json" -d '{"company_name":"云启科技","primary_value_prop":"项目管理"}'
注意:首次启动会下载Ollama模型,耗时较长。建议在
docker-compose.yml里添加init: true,确保容器内进程能正确接收信号。
4.2 Next.js项目搭建与OpenClaw集成
Next.js 14的app目录是必选项,它原生支持Server Components,能极大减少客户端JS体积,这对AI站至关重要——用户看到的,应该是HTML,而不是一个等待JS水合的空白屏。
初始化项目:
npx create-next-app@latest my-ai-site --typescript --tailwind --eslint --app --src-dir cd my-ai-site创建OpenClaw API客户端:在
lib/openclaw-client.ts里封装请求逻辑,重点是错误重试和超时:import { cache } from 'react' // 缓存客户端实例,避免重复创建 const createOpenClawClient = () => { const baseUrl = process.env.NEXT_PUBLIC_OPENCLAW_API_URL || 'http://localhost:3000' const request = async (endpoint: string, options: RequestInit = {}) => { const controller = new AbortController() const timeoutId = setTimeout(() => controller.abort(), 8000) // 8秒超时 try { const response = await fetch(`${baseUrl}${endpoint}`, { ...options, headers: { 'Content-Type': 'application/json', ...options.headers, }, signal: controller.signal, }) clearTimeout(timeoutId) if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`) } return await response.json() } catch (error) { clearTimeout(timeoutId) if (error instanceof DOMException && error.name === 'AbortError') { throw new Error('OpenClaw API 请求超时,请稍后重试') } throw error } } return { generateLandingPage: (data: any) => request('/v1/skills/landing_page_generator', { method: 'POST', body: JSON.stringify(data), }), } } export const openclawClient = cache(createOpenClawClient)构建动态页面:在
app/page.tsx里,利用Next.js 14的服务端组件能力:import { openclawClient } from '@/lib/openclaw-client' import { RhythmRenderer } from '@/components/RhythmRenderer' // 服务端组件,数据在服务端获取 export default async function HomePage() { let data = null let error = null try { // 直接调用,无需useEffect data = await openclawClient().generateLandingPage({ company_name: '云启科技', primary_value_prop: '项目管理' }) } catch (err) { error = err instanceof Error ? err.message : '未知错误' } return ( <div className="min-h-screen"> {error ? ( <div className="text-center py-20"> <h2 className="text-2xl font-bold text-red-600 mb-2">内容加载失败</h2> <p className="text-gray-600">{error}</p> <button onClick={() => window.location.reload()} className="mt-4 px-4 py-2 bg-brand-primary text-white rounded" > 刷新重试 </button> </div> ) : data ? ( <RhythmRenderer rhythm={data.content_rhythm} sections={data.sections} /> ) : ( <div className="text-center py-20"> <div className="inline-block animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-brand-primary mb-4"></div> <p className="text-gray-600">内容正在生成中...</p> </div> )} </div> ) }配置Tailwind人格化变量:在
app/layout.tsx里注入CSS变量:import { Inter } from 'next/font/google' const inter = Inter({ subsets: ['latin', 'cyrillic'] }) export const metadata = { title: '云启科技 - 智能项目管理平台', description: '让项目管理像呼吸一样简单', } export default function RootLayout({ children, }: { children: React.ReactNode }) { return ( <html lang="zh-CN" className={inter.className}> <body className="antialiased"> {/* 注入人格化CSS变量 */} <style jsx global>{` :root { --color-primary: #3b82f6; --color-secondary: #10b981; --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI'; --font-serif: 'Noto Serif SC', 'Noto Serif CJK SC', serif; } `}</style> {children} </body> </html> ) }
4.3 Cloudflare Pages部署与性能调优
Cloudflare Pages的部署流程简洁,但几个关键配置决定了AI站的生死线。
创建Pages项目:
- 登录Cloudflare Dashboard,进入
Pages→Create a project; - 选择GitHub仓库(确保已将Next.js项目推送到GitHub);
- 构建设置:
- Framework preset:
Next.js - Build command:
npm run build(Next.js默认) - Build output directory:
.next(Next.js默认) - Root directory:
/(项目根目录)
- Framework preset:
- 登录Cloudflare Dashboard,进入
环境变量配置(在
Settings→Environment variables里):Key Value Description NEXT_PUBLIC_OPENCLAW_API_URLhttps://your-openclaw-domain.comOpenClaw服务的公网地址 NEXT_PUBLIC_SITE_TYPElanding用于区分站点类型,驱动人格化配置 NODE_ENVproduction强制生产环境 关键Page Rules设置(在
Settings→Page Rules里):- Rule 1:
/*→Cache Level: Standard(标准缓存) - Rule 2:
/api/*→ `Cache Level: Bypass
- Rule 1: