/ Notes
First Technical Blog: Vibe Coding a Personal Site with Codex
From outgrowing a resume to building a dynamic personal showcase with Next.js, MDX, Tailwind, and GitHub Pages.
我开始做这个网站,并不是因为“我需要一个更好看的简历”。恰恰相反,是因为我越来越觉得,简历太像一个压缩包:它必须短、必须规整、必须把经历塞进几行 bullet 里。项目里真正困难的地方、一次调试背后的判断、一个系统从想法到落地的路径,往往都被压缩成了几个动词:负责、参与、实现、优化。
但人的经历不是这样展开的。
比如一次实习,不只是公司名和岗位名;一次科研,也不只是论文标题和作者顺序;一个工程项目,更不只是“使用某某框架完成某某功能”。它们背后有问题意识、有取舍、有失败、有复盘,也有很多很小但很能说明能力的细节。所以我需要一个比简历更丰富、更动态、也更像“长期工作台”的载体。
于是我决定做一个个人网站。
更准确地说,我用 Codex vibe coding 了一个个人网站。
1. 从“简历页面”到“个人系统”#
一开始,我想象中的页面很简单:头像、教育经历、项目、论文、联系方式。这样的页面当然可以用模板很快搭出来,但我很快意识到,如果只是把简历搬到网页上,它并没有解决我的问题。
我真正想要的是一个可以持续生长的系统:
- 首页负责让别人快速理解“我是谁、我关注什么、我适合做什么”。
- 经历页面负责展开项目背景、技术栈、方法和结果。
- 论文页面负责记录研究问题和学术产出。
- 博客页面负责保存更过程化的内容:我怎么搭建、怎么调试、怎么思考。
- 中英文页面负责面向不同读者,而不是只做一次性的翻译。
这也是为什么我没有把它做成一个静态海报,而是选择了更工程化的方式:用 Next.js 组织页面,用数据文件管理内容,用 MDX 写博客,用 Tailwind CSS 控制视觉和响应式布局,最后通过 GitHub Pages 做静态部署。
2. 技术选型:为什么是 Next.js + MDX + Tailwind#
这个网站目前看起来像一个展示页,但它的底层更像一个小型内容系统。
Next.js:把页面拆成可维护的模块#
Next.js 的好处是,它既能写 React 组件,又能做静态站点导出。对于个人网站来说,这一点很合适:页面不需要复杂后端,但需要清晰的路由、组件复用和构建流程。
我把页面拆成了几个层次:
src/app/:负责路由结构,比如首页、博客、经历、论文等页面。src/features/:负责具体页面的组合逻辑,比如home-page.tsx、blog-post-page.tsx。src/components/:负责可复用组件,比如站点外壳、章节标题、经历卡片、论文条目。src/data/:负责结构化内容,比如个人信息、项目经历、论文列表、兴趣爱好。content/blog/:负责用 MDX 存放博客文章。
这样做的好处是,当我想改某段经历,不需要去 JSX 里到处找文案;当我想改页面样式,也不用动数据源。内容和呈现被拆开,网站就更容易长期维护。
MDX:让博客既像文章,也像代码#
技术博客最怕变成纯文本存档。纯 Markdown 足够写文章,但如果以后想插入组件、代码演示、实验结果卡片,MDX 会更灵活。
这篇文章本身就是一个 .mdx 文件。它顶部有一段 frontmatter:
title:
zh: "第一篇技术博客:用 Codex vibe coding 一个个人网站"
en: "First Technical Blog: Vibe Coding a Personal Site with Codex"
date: "2026-06-26"
tags:
- Personal Site
- Codex
- Next.js这些元信息会被 gray-matter 解析出来,用于博客列表、文章标题、日期和标签展示。正文则交给 next-mdx-remote 渲染。这样一篇文章既是内容,也是可被程序读取和组织的数据。
Tailwind CSS:快速试错,也能保持统一#
这个网站的视觉不是一次性设计出来的,而是在多轮修改中逐渐收敛的。比如首页主视觉、个人形象模块、卡片间距、移动端导航,都经历过调整。
Tailwind 的优势在于反馈很快:我可以直接在组件里调整 px-5、py-20、grid-cols-5、bg-cloud/86 这样的 class,然后立刻看到布局变化。对于 vibe coding 来说,这种短反馈链很重要。
但 Tailwind 不是随便堆 class。真正需要注意的是统一性:
- 常用颜色放进
tailwind.config.ts,比如ink、paper、cloud、coral、teal。 - 常用字体通过 CSS 变量管理。
- 卡片、边框、背景透明度保持相近节奏。
- 桌面端和移动端分别控制布局密度,避免手机端拥挤。
3. 和 Codex 一起 vibe coding 是什么感觉#
所谓 vibe coding,并不是“完全不管代码,让 AI 自动生成一个网站”。更准确地说,它像是一种快速对话式开发:我描述方向,Codex 给出实现;我指出不满意的地方,它继续修改;我再根据页面观感调整优先级。
这个过程中,最重要的不是一次生成完美代码,而是把模糊的审美和产品判断逐渐变成具体改动。
例如:
- 我觉得简历信息太单薄,于是补充真实经历和项目内容。
- 我觉得首页需要更像“个人形象”,于是加入照片展示模块。
- 我不满意自动生成的头像,就改用自己指定的
me.png。 - 我觉得“最新写作”和“兴趣爱好”挤在一起,就把它们拆成两个独立模块。
- 我尝试过把背景图元素融入全站,但发现影响整体观感,又把它撤掉。
这些修改都不是单纯的代码问题,而是“这个网站应该如何表达我”的问题。Codex 的价值在于,它可以快速把这些判断落到文件、组件、样式和构建结果里。
4. 网站里的几个具体编程知识点#
4.1 静态站点导出#
这个网站使用的是静态导出模式,适合部署到 GitHub Pages。静态站点的好处是部署简单、访问稳定、没有服务器维护成本。
核心思路是:构建时把页面预渲染成 HTML、CSS 和 JavaScript 资源,部署时只需要托管这些静态文件。
这要求页面尽量避免依赖运行时后端逻辑。博客、经历、论文这些内容都在构建阶段从本地文件或数据文件读取,因此很适合静态化。
4.2 国际化路由#
网站支持中文和英文页面。它不是简单地在一个页面里切换文字,而是通过 locale 路由组织内容,例如 /zh 和 /en。
内容层面,我使用类似这样的结构:
name: {
zh: '徐天乐',
en: 'Tianle Xu',
}渲染时通过 text(value, locale) 选择对应语言。这样做有两个好处:一是不会把中英文写散;二是未来新增页面时,可以复用同一套本地化逻辑。
4.3 数据驱动页面#
首页的技能、经历、论文、兴趣、个人照片,并不是硬编码在页面里的,而是从 src/data/ 里的结构化数据读取。
例如个人形象模块本质上是一个数组:每张照片有 image、title、caption。页面只负责遍历它们:
{profile.visualGallery.map((photo) => (
<figure key={photo.image}>...</figure>
))}这就是数据驱动页面的好处:新增一张照片或改一句描述,不需要重写布局。
4.4 响应式布局#
个人网站不能只在电脑上好看。很多 HR 或同学可能会直接在手机上打开链接,所以移动端体验也很重要。
响应式布局里比较关键的点包括:
- 首页 hero 在桌面端左右分栏,移动端自然上下堆叠。
- 导航在桌面端显示横向菜单,在移动端变成可横向滚动的按钮组。
- 个人形象模块在桌面端压缩成两排展示,移动端自动变成更适合阅读的列数。
- 图片使用
object-cover或object-contain控制裁切方式,避免重要内容被截掉。
这些细节看起来很小,但它们决定了网站是不是一个真正可访问、可分享的作品。
4.5 构建验证#
每次改完,我都会跑两个检查:
npm run type-check
npm run build前者用 TypeScript 检查类型问题,后者验证 Next.js 能否完成生产构建。对于个人网站这种展示型项目,构建通过并不代表内容完美,但至少说明页面、路由、MDX、图片引用没有明显断裂。
5. 个人网站不是终点,而是一个持续更新的接口#
做完第一版之后,我对个人网站的理解变了。
它不是一个“上线之后就结束”的项目,而是一个持续更新的接口:别人通过它理解我,我也通过它整理自己。
简历负责回答“你做过什么”;个人网站可以继续回答:
- 你为什么做这些事?
- 你怎么思考问题?
- 你怎么把想法变成系统?
- 你如何复盘失败和迭代方案?
- 你在技术之外是什么样的人?
所以这篇博客不仅是在记录一个网站的搭建过程,也是在给后面的内容开一个入口。以后我希望这里能继续出现项目复盘、论文阅读、推理系统调试、多模态模型实践、医学影像算法记录,以及一些不那么正式但真实的技术思考。
如果简历是一页纸,那么这个网站就是一个可以不断展开的版本。
这就是我从个人主页开始写第一篇技术博客的原因。