尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

24小时用ChatGPT和Next.js开发吸引上万用户的开源项目实战

发布时间:2026/9/19 9:49:57

资讯中心
01
ARTICLE

24小时用ChatGPT和Next.js开发吸引上万用户的开源项目实战

24小时用ChatGPT和Next.js开发吸引上万用户的开源项目实战
1. 24小时倒计时开始前先想清楚这件事到底难在哪很多人看到24小时用ChatGPT和Next.js开发一个吸引上万用户的开源项目这个标题第一反应是这不就是个营销噱头吗。我一开始也这么想但真正动手拆解之后发现这个挑战的难点根本不在写代码本身而在于三个容易被忽略的地方需求判断的准确度、技术栈的熟练度、以及发布节奏的把控。先说需求判断。24小时的时间窗口意味着你没有时间做用户调研、没有时间反复迭代产品方向。你必须在上手写第一行代码之前就已经确定这个东西做出来有人用。这听起来像废话但我见过太多人在黑客松或者限时挑战里花了十几个小时做了一个技术上很酷但没人需要的东西。所以第一步不是打开编辑器而是花30分钟想清楚你要解决的是什么人的什么问题再说技术栈。ChatGPT这里指的是调用OpenAI的API能力加上Next.js这个组合在2024年已经非常成熟了。Next.js的App Router、Server Actions、API Routes可以让你在同一个项目里搞定前端页面和后端逻辑不需要单独搭一个后端服务。TypeScript保证类型安全Tailwind CSS让你不用写自定义CSS就能快速出效果。这套组合的核心优势是减少决策疲劳——你不需要在用哪个状态管理库用哪个UI组件库用哪种样式方案这些问题上纠结直接上手写业务逻辑就行。最后说发布节奏。一个开源项目要吸引用户代码写完之后的工作量其实不比写代码少。README怎么写、Demo怎么部署、在哪些渠道发布、发布时说什么话这些都需要提前规划。我的做法是在写代码的中途就把README的框架搭好把部署流程跑通这样代码一完成就能立刻发布不用再花额外的时间。提示24小时挑战最大的敌人不是技术难度而是决策疲劳。每做一个技术选型决策你的精力就消耗一点。所以能提前定下来的事情绝对不要留到开发过程中再想。具体到技术选型我最终确定的方案是这样的技术层选型选择理由框架Next.js 14 (App Router)前后端一体API Routes直接写后端逻辑语言TypeScript类型提示减少运行时错误重构更安全样式Tailwind CSS不用切换文件写CSS开发速度快AI能力OpenAI API直接调用不需要自己训练模型部署Vercel和Next.js无缝集成推送即部署包管理pnpm安装速度快磁盘占用小这个表格看起来简单但每一个选择背后都有取舍。比如为什么不用Vue或者Svelte因为Next.js的生态最成熟遇到问题最容易找到解决方案。为什么不用CSS Modules或者styled-components因为Tailwind的原子化类名在快速开发场景下效率最高你不需要给每个元素想类名。为什么用pnpm而不是npm因为在24小时的时间压力下每一次npm install节省的几十秒累积起来可能就是十几分钟。2. 从零到可运行项目骨架搭建的每一个关键决策2.1 初始化项目时那些容易踩的坑创建Next.js项目本身只需要一行命令但这里面有几个细节直接影响到后续的开发效率。我用的是pnpm create next-applatest my-project --typescript --tailwind --eslint --app --src-dir --import-alias /*这条命令一次性把TypeScript、Tailwind CSS、ESLint、App Router、src目录结构、路径别名全部配置好。如果你手动一个个选可能要花好几分钟而且容易漏掉某些配置。--src-dir这个选项值得特别说一下它会把你的代码放在src/目录下而不是直接放在根目录。这样做的好处是根目录更干净配置文件、依赖文件、代码文件分得很清楚。--import-alias /*则是设置路径别名让你可以用/components/Button代替../../components/Button在深层嵌套的目录结构里这个差别非常明显。初始化完成之后我做的第一件事不是写代码而是清理模板自带的示例内容。Next.js的默认模板会给你一个带样式和图片的首页这些东西如果不清理掉后面很容易混淆哪些是你自己写的、哪些是模板自带的。我会把page.tsx清空成一个最简结构把globals.css里不需要的样式删掉把public目录下的示例图片删掉。这个过程大概花5分钟但能让后面的开发清爽很多。另一个容易忽略的点是环境变量的配置。调用OpenAI API需要API Key这个Key绝对不能硬编码在代码里也不能提交到Git仓库。正确的做法是在项目根目录创建.env.local文件把Key写进去然后在.gitignore里确保.env.local被忽略。Next.js会自动加载.env.local里的变量在服务端代码里通过process.env.OPENAI_API_KEY访问。注意只有以NEXT_PUBLIC_开头的环境变量才会暴露给浏览器端其他的只能在服务端使用。这个设计是为了安全但也意味着你不能在客户端组件里直接读取API Key。# .env.local OPENAI_API_KEYsk-xxxxxxxxxxxxxxxx注意如果你在开发过程中发现API调用返回401错误第一件事就是检查环境变量有没有正确加载。一个常见的坑是修改了.env.local之后没有重启开发服务器Next.js不会自动热重载环境变量文件。2.2 目录结构怎么设计才不混乱24小时的开发时间意味着你没有机会在后期做大规模重构。所以一开始的目录结构必须清晰让每个文件都有明确的归属。我的做法是按照功能模块来划分而不是按照文件类型来划分。什么意思呢就是不要把所有组件放在components/下面、所有工具函数放在utils/下面而是按照业务功能来组织。比如我这个项目是一个AI对话工具那么目录结构大概是这样src/ app/ page.tsx # 首页 chat/ page.tsx # 对话页面 api/ chat/ route.ts # 对话API接口 components/ ChatInput.tsx # 输入框组件 MessageList.tsx # 消息列表组件 MessageItem.tsx # 单条消息组件 lib/ openai.ts # OpenAI客户端封装 prompts.ts # 提示词模板 types/ chat.ts # 类型定义这个结构的好处是当你需要修改对话相关的逻辑时你知道该去chat/目录下找当你需要调整OpenAI的调用参数时你知道该去lib/openai.ts里改。每个文件的职责是单一的不会出现一个文件里混杂了UI渲染、API调用、数据处理的情况。lib/openai.ts这个文件特别重要它封装了OpenAI客户端的初始化和调用逻辑。为什么要单独封装因为这样你只需要在一个地方配置API Key、Base URL、超时时间等参数其他所有地方调用时只需要引入这个封装好的函数就行。如果以后要换模型或者调整参数也只改这一个文件。// lib/openai.ts import OpenAI from openai; const client new OpenAI({ apiKey: process.env.OPENAI_API_KEY, baseURL: process.env.OPENAI_BASE_URL, // 可选用于自定义接口地址 }); export async function chatCompletion(messages: Message[]) { const response await client.chat.completions.create({ model: gpt-4o-mini, messages, temperature: 0.7, max_tokens: 2000, }); return response.choices[0].message.content; }这里有一个实操经验模型选择不要一上来就用最贵的。gpt-4o-mini在大多数场景下已经够用了而且速度快、成本低。在开发阶段用便宜的模型快速验证功能等到功能稳定之后再根据实际需求决定是否升级模型。另外temperature参数控制输出的随机性0.7是一个比较平衡的值既不会太死板也不会太发散。max_tokens限制单次回复的最大长度设置得太大会导致响应变慢设置得太小又可能截断回复2000是一个比较安全的默认值。2.3 类型定义先行避免后期返工TypeScript的核心价值在于类型安全但前提是你真的把类型定义好了。在24小时的开发中我建议先写类型定义再写业务逻辑。这听起来像是额外的工作量但实际上能帮你节省大量调试时间。以对话功能为例核心的类型定义大概是这样// types/chat.ts export interface Message { id: string; role: user | assistant | system; content: string; timestamp: number; } export interface Conversation { id: string; title: string; messages: Message[]; createdAt: number; updatedAt: number; }role字段用联合类型user | assistant | system而不是string这样当你在代码里写message.role usr的时候TypeScript会立刻报错提醒你拼写错误。timestamp用number而不是Date是因为Date对象在序列化和反序列化时容易出问题用时间戳更简单可靠。这些类型定义看起来很简单但它们是你整个应用的骨架。当你写API接口的时候请求体和响应体的类型可以直接复用这些定义当你写组件的时候props的类型也可以直接引用。类型定义先行后面所有的代码都会受益。3. 核心功能开发AI对话逻辑的实现与调优3.1 API Route的设计为什么不能直接在客户端调用OpenAI很多新手会想既然OpenAI提供了JavaScript SDK那我直接在客户端组件里调用不就行了吗答案是不行而且原因不只是API Key暴露的问题。首先API Key暴露是最直接的安全风险。如果你的Key写在客户端代码里任何人打开浏览器开发者工具就能看到然后就可以用你的Key去调用API消耗你的额度。其次即使不考虑安全问题直接在客户端调用也会遇到跨域限制、请求超时、错误处理不统一等问题。所以正确的做法是在Next.js的API Route里调用OpenAI客户端只负责发送请求到自己的API Route。// app/api/chat/route.ts import { NextRequest, NextResponse } from next/server; import { chatCompletion } from /lib/openai; export async function POST(req: NextRequest) { try { const { messages } await req.json(); if (!messages || !Array.isArray(messages)) { return NextResponse.json( { error: 消息格式不正确 }, { status: 400 } ); } const reply await chatCompletion(messages); return NextResponse.json({ reply }); } catch (error) { console.error(Chat API error:, error); return NextResponse.json( { error: 服务暂时不可用请稍后重试 }, { status: 500 } ); } }这段代码有几个值得注意的地方。第一输入校验不能省。你永远不知道客户端会发什么过来所以必须检查messages是否存在、是否是数组。第二错误处理要区分类型。400错误表示客户端请求有问题500错误表示服务端出了问题这两种情况给用户的提示应该不同。第三日志要打。console.error在Vercel的部署环境里可以在日志面板看到方便排查问题。还有一个进阶技巧流式响应。默认情况下OpenAI的API会等所有内容生成完毕之后一次性返回。如果回复很长用户可能要等好几秒才能看到内容。流式响应可以让内容一个字一个字地显示出来体验好很多。实现方式是把stream: true传给OpenAI然后用ReadableStream把数据转发给客户端。不过流式响应的实现复杂度比普通响应高不少如果你的时间有限可以先做普通响应等核心功能跑通之后再升级。3.2 对话状态管理用React的useState就够了在24小时的开发中不要引入Redux、Zustand、Jotai这些状态管理库。对于对话功能来说React自带的useState和useEffect完全够用。引入额外的状态管理库只会增加学习成本和调试难度。对话状态的核心逻辑是这样的// app/chat/page.tsx use client; import { useState } from react; import { Message } from /types/chat; export default function ChatPage() { const [messages, setMessages] useStateMessage[]([]); const [input, setInput] useState(); const [loading, setLoading] useState(false); async function handleSend() { if (!input.trim() || loading) return; const userMessage: Message { id: crypto.randomUUID(), role: user, content: input.trim(), timestamp: Date.now(), }; const newMessages [...messages, userMessage]; setMessages(newMessages); setInput(); setLoading(true); try { const res await fetch(/api/chat, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ messages: newMessages }), }); const data await res.json(); if (!res.ok) { throw new Error(data.error || 请求失败); } const assistantMessage: Message { id: crypto.randomUUID(), role: assistant, content: data.reply, timestamp: Date.now(), }; setMessages([...newMessages, assistantMessage]); } catch (error) { console.error(发送消息失败:, error); // 这里可以加一个错误提示的UI } finally { setLoading(false); } } return ( div classNameflex flex-col h-screen {/* 消息列表 */} div classNameflex-1 overflow-y-auto p-4 {messages.map((msg) ( div key{msg.id} className{msg.role user ? text-right : text-left} p classNameinline-block bg-gray-100 rounded-lg px-4 py-2 my-1 {msg.content} /p /div ))} {loading p classNametext-gray-400正在思考.../p} /div {/* 输入框 */} div classNameborder-t p-4 flex gap-2 input value{input} onChange{(e) setInput(e.target.value)} onKeyDown{(e) e.key Enter handleSend()} classNameflex-1 border rounded-lg px-4 py-2 placeholder输入你的问题... disabled{loading} / button onClick{handleSend} disabled{loading} classNamebg-blue-500 text-white px-6 py-2 rounded-lg disabled:opacity-50 发送 /button /div /div ); }这段代码里有几个实操细节值得展开说。crypto.randomUUID()是浏览器原生提供的UUID生成方法不需要引入uuid这个npm包省了一个依赖。loading状态不仅用来显示正在思考...的提示还用来禁用输入框和发送按钮防止用户在等待回复的时候重复发送消息。onKeyDown里判断e.key Enter实现回车发送但要注意如果用户想换行就不能用回车发送了所以更完善的做法是判断e.key Enter !e.shiftKey按住ShiftEnter换行。提示在开发阶段把错误信息直接显示在界面上比只打console.log更有效。你可以加一个error状态当请求失败时把错误信息渲染出来这样调试的时候一眼就能看到问题。3.3 提示词工程让AI输出更符合预期调用OpenAI API的时候messages数组里的第一条通常是system角色的消息用来设定AI的行为准则。这条消息写得好不好直接决定了AI的回复质量。很多人忽略这一步直接把用户的问题发给AI结果就是AI的回复风格飘忽不定。一个好的system prompt应该包含这几个要素角色设定、能力边界、输出格式要求。比如// lib/prompts.ts export const SYSTEM_PROMPT 你是一个专业的技术助手擅长回答编程相关的问题。 回答要求 1. 用简洁清晰的中文回答避免冗长的铺垫 2. 涉及代码时给出可运行的示例并标注语言类型 3. 如果不确定答案直接说我不确定不要编造信息 4. 回答长度控制在500字以内除非用户明确要求详细展开;这个prompt看起来简单但每一条都有实际作用。用简洁清晰的中文回答避免了AI用英文回复或者写一堆废话。给出可运行的示例让代码片段更实用。如果不确定答案直接说我不确定这个特别重要因为AI在不确定的时候倾向于编造看起来合理但实际错误的信息明确告诉它可以说不知道能减少这种情况。回答长度控制在500字以内则是防止AI写长篇大论影响用户体验。在实际测试中我发现system prompt的效果不是线性的。不是说你写得越长越好有时候太长的prompt反而会让AI抓不住重点。我的经验是控制在200字以内把最核心的3-5条要求写清楚就行。另外prompt里的要求要具体不要写回答要好这种模糊的表述而要写回答控制在500字以内这种可量化的标准。4. 从能跑到好用UI打磨与部署上线的关键操作4.1 Tailwind CSS的实战技巧快速做出不丑的界面Tailwind CSS最大的优势是让你不用离开JSX就能写样式但它的类名确实很长第一次看到的人会觉得眼花缭乱。我的经验是不要试图记住所有类名只需要掌握最常用的几十个其他的用到时查文档就行。对于对话界面来说核心的样式需求其实就几个消息气泡的左右对齐、输入框的固定底部、消息列表的滚动。这些用Tailwind实现起来很直接!-- 用户消息靠右AI消息靠左 -- div className{flex ${msg.role user ? justify-end : justify-start}} div className{max-w-[80%] rounded-2xl px-4 py-2 ${ msg.role user ? bg-blue-500 text-white : bg-gray-100 text-gray-900 }} {msg.content} /div /divmax-w-[80%]限制消息气泡的最大宽度防止长消息占满整个屏幕宽度。rounded-2xl给气泡加圆角比直角看起来柔和很多。用户消息用蓝色背景白色文字AI消息用灰色背景深色文字这种颜色对比让用户一眼就能区分谁说了什么。有一个容易忽略的细节是暗色模式。Tailwind内置了dark:前缀你只需要在根元素上加一个dark类所有带dark:前缀的样式就会生效。比如bg-white dark:bg-gray-900在亮色模式下背景是白色暗色模式下背景是深灰色。实现暗色模式切换只需要一个状态和一个按钮代码量很少但用户体验提升明显。另一个实操经验是用space-y代替margin。当你有一组垂直排列的元素需要间距时给父元素加space-y-4比给每个子元素加mb-4更简洁而且不会在最后一个元素后面多出多余的间距。这个技巧在消息列表里特别有用。4.2 部署到Vercel推送即上线的完整流程Next.js项目部署到Vercel是最省事的方案没有之一。整个流程可以概括为把代码推到GitHub在Vercel上导入这个仓库配置环境变量然后每次git push都会自动部署。但这里面有几个坑需要注意。第一环境变量要在Vercel的控制台里单独配置。你在本地.env.local里写的变量不会自动同步到Vercel需要在项目的Settings - Environment Variables里手动添加。第二构建时的Node.js版本。Vercel默认的Node版本可能和你本地的不一样如果遇到构建失败检查一下package.json里的engines字段或者Vercel的项目设置。第三API Route的执行时间限制。Vercel的免费版对Serverless Function有执行时间限制一般是10秒如果你的OpenAI请求超过了这个时间会被强制中断。解决办法是尽量用gpt-4o-mini这种响应快的模型或者升级到Pro版获得更长的执行时间。部署完成之后Vercel会给你一个xxx.vercel.app的域名。这个域名在国内的访问速度还可以但如果你想要更好的访问体验可以绑定自己的域名。绑定域名需要在域名注册商那里添加一条CNAME记录指向Vercel提供的地址然后在Vercel的控制台里添加这个域名。整个过程大概10分钟Vercel会自动帮你配置SSL证书。注意部署之后一定要在无痕模式下测试一遍完整流程。因为你在本地开发时浏览器可能缓存了一些资源部署后的实际表现可能和本地不一样。特别是环境变量相关的问题只有在部署环境才会暴露出来。4.3 README和开源发布让项目被更多人看到代码写完、部署上线之后最后一步是让更多人知道这个项目。开源项目的门面就是README一个好的README应该包含一句话介绍、在线Demo链接、功能截图、本地运行步骤、技术栈说明。一句话介绍要直击痛点不要写这是一个基于Next.js和OpenAI的对话应用这种技术导向的描述而要写一个开箱即用的AI对话工具30秒部署你自己的ChatGPT这种用户导向的描述。功能截图比文字描述更有说服力用手机截几张实际使用的界面图放在README里比写一大段功能介绍有效得多。本地运行步骤要尽可能简单最好就是三行命令git clone https://github.com/yourname/your-project.git cd your-project pnpm install cp .env.example .env.local # 然后填入你的API Key pnpm dev同时提供一个.env.example文件里面列出所有需要的环境变量名但不包含实际值。这样别人clone你的项目之后知道需要配置哪些变量不会因为缺少环境变量而运行失败。发布渠道方面GitHub本身是一个渠道但光靠GitHub的自然流量很难获得大量用户。你还需要在技术社区、社交媒体上分享。分享的时候不要只发一个链接要写一段话说明你做了什么、解决了什么问题、用了什么技术。一段好的分享文案应该让读者在30秒内理解这个项目的价值。5. 24小时之后那些只有踩过坑才知道的事5.1 时间分配的真实复盘如果让我重新做一次24小时挑战我会这样分配时间需求确认和项目初始化2小时核心功能开发8小时UI打磨3小时部署和测试2小时README和发布3小时缓冲时间6小时。这个分配和实际执行最大的差别在于缓冲时间。第一次做的时候我以为20小时足够完成所有事情结果遇到了各种意料之外的问题API Key配置错误花了半小时排查、Tailwind的某个类名不生效花了20分钟查文档、Vercel部署时环境变量没配置导致线上报错又花了半小时修复。这些零碎的问题单个看起来不严重但累积起来可能吃掉你三四个小时。所以一定要留缓冲时间不要把日程排满。我的经验是你预估的完成时间乘以1.5才是比较现实的预期。另一个时间相关的经验是不要在深夜做关键决策。我在凌晨两点的时候决定换一个UI布局方案结果改到凌晨四点发现新方案还不如原来的又改回去。这种反复不仅浪费时间还严重影响第二天的状态。如果时间允许把需要做决策的事情安排在精力充沛的时段机械性的工作比如写样式、改文案可以放在精力下降的时候做。5.2 那些让我卡了半小时以上的坑第一个坑OpenAI API返回429错误。429表示请求频率超限或者额度不足。我一开始以为是代码问题排查了半天才发现是免费额度用完了。解决办法是在OpenAI的账单页面充值或者换一个还有额度的API Key。这个坑的教训是开发之前先确认API Key的可用额度不要等到写到一半才发现用不了。第二个坑Next.js的客户端组件和服务端组件混淆。App Router默认所有组件都是服务端组件如果你在服务端组件里用了useState或者onClick会直接报错。解决办法是在文件顶部加use client指令把这个文件标记为客户端组件。但要注意use client会把这个文件及其所有子组件都变成客户端组件所以最好把需要交互的部分拆成独立的客户端组件不要整个页面都加use client。第三个坑Tailwind的类名不生效。有时候你写了一个Tailwind类名但样式没有应用原因可能是这个类名不在Tailwind的默认配置里或者被其他样式覆盖了。排查方法是打开浏览器开发者工具看这个元素的computed style里有没有你期望的样式。如果没有检查tailwind.config.ts里的content字段有没有包含你的文件路径。第四个坑Vercel部署后API Route超时。前面提到过Vercel免费版的Serverless Function有执行时间限制。如果你的OpenAI请求响应很慢就会超时。解决办法除了换更快的模型之外还可以在OpenAI客户端里设置timeout参数让请求在超时之前主动失败并返回错误信息而不是等到Vercel强制中断。5.3 如果再来一次我会怎么做如果再做一次24小时挑战我会在以下几个方面做得更好。第一提前准备好API Key和额度不要在开发过程中才发现Key不能用。第二先做最小可用版本再迭代不要一开始就想着做完整功能。比如对话功能先做一个能发消息能收回复的版本跑通之后再加流式响应、历史记录、多轮对话这些功能。第三部署流程提前跑通不要等到代码写完才第一次部署。在项目初始化之后就部署一次确保部署流程没有问题后面每次推送都能自动部署。第四README在开发过程中同步写不要等到最后再补。你在开发过程中遇到的问题、解决的方案、做的技术选型这些都是README的好素材。如果等到最后再写很多细节已经忘了。第五发布文案提前准备好包括分享到社区的一段话、几张截图、一个简短的Demo视频。这些素材在发布的时候直接就能用不用临时准备。最后分享一个心态上的经验24小时挑战最大的价值不是做出一个完美的产品而是逼自己在有限时间内做出取舍。你会被迫放弃一些锦上添花的功能专注于最核心的价值。这种取舍能力在实际工作中比技术能力更重要。我在这次挑战中砍掉了用户登录、对话历史、多模型切换等功能只保留了最核心的对话能力。结果证明这个决策是对的用户最关心的就是能不能用和好不好用而不是功能多不多。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。