
1. 项目概述一个基于Next.js与Cursor AI的现代化个人作品集最近在GitHub上看到一个挺有意思的项目叫“bilaltosungit/cursor-nextjs-portfolio”。光看这个名字就能拆解出几个关键信息这是一个个人作品集Portfolio技术栈是Next.js并且很可能与Cursor这个AI代码编辑器有深度集成。作为一个常年混迹在开源社区和前端领域的开发者我立刻意识到这不仅仅是一个简单的模板它背后反映的是当前个人开发者展示自身技术实力和项目经验的一种新范式。在过去搭建一个个人作品集网站要么是找个现成的模板修修改改要么是从零开始用React、Vue吭哧吭哧地写。前者缺乏个性后者又耗时耗力。而“bilaltosungit/cursor-nextjs-portfolio”这个项目巧妙地结合了Next.js这个全栈框架的生产力优势以及Cursor AI在代码生成和辅助开发上的能力旨在为开发者提供一个高质量、现代化且易于定制的起点。它解决的痛点非常明确让开发者尤其是独立开发者或自由职业者能够快速拥有一个专业、美观、性能优异的线上门户集中展示自己的项目、技能和经历而无需在UI设计和基础架构上投入过多精力。这个项目适合谁呢我认为主要面向几类人群一是正在寻找工作的应届生或初级开发者需要一个体面的作品集来吸引招聘方的目光二是自由职业者或独立开发者需要展示案例来获取客户信任三是任何希望建立个人技术品牌、进行知识输出的技术爱好者。接下来我将深入拆解这个项目的设计思路、技术实现细节并分享如何基于它快速打造属于你自己的、独一无二的数字名片。2. 项目整体架构与技术选型解析2.1 为什么是Next.js选择Next.js作为这个作品集项目的基石是一个经过深思熟虑的决定绝非随波逐流。Next.js在服务端渲染SSR、静态站点生成SSG、图像优化、API路由等方面提供了开箱即用的支持这些特性对于一个作品集网站来说至关重要。首先性能与SEO。作品集网站是个人在互联网上的门面加载速度和搜索引擎可见度直接影响访客可能是潜在雇主或客户的第一印象。Next.js的SSG功能可以在构建时生成静态HTML使得页面加载速度极快并且对搜索引擎爬虫非常友好。这对于展示项目详情、博客文章这类内容固定的页面是完美匹配。其次开发体验与生产力。Next.js的文件系统路由、热重载、TypeScript的深度集成极大地提升了开发效率。对于个人项目我们追求的是在有限时间内产出高质量成果Next.js的“约定优于配置”哲学减少了大量样板代码和决策成本。再者现代化的技术栈。它基于React拥有庞大的生态系统。这意味着项目中可以方便地集成各种流行的UI库如Tailwind CSS、Shadcn/ui、状态管理工具和第三方服务确保作品集的技术栈本身也是其专业性的体现。项目中使用app/目录结构也表明它采用了Next.js最新的App Router利用了React Server Components等前沿特性在保持性能的同时简化了数据获取和渲染逻辑。2.2 Cursor AI在项目中的角色项目名称中包含了“cursor”这暗示了Cursor AI在这个项目的开发过程中扮演了核心辅助角色。Cursor并非一个运行时依赖而是一个开发工具。它的价值体现在项目构思、代码生成和迭代优化阶段。在实际操作中开发者可以利用Cursor的AI能力来快速生成项目骨架。例如你可以用自然语言描述“创建一个使用Next.js 14 App Router、Tailwind CSS和Framer Motion的个人作品集首页包含导航栏、英雄介绍区、项目展示网格和页脚。” Cursor能够生成结构清晰、风格现代的React组件代码。这对于不擅长前端设计或想快速验证想法的开发者来说是巨大的效率提升。更重要的是Cursor在代码理解和重构方面表现突出。当你想修改某个组件的样式、调整布局逻辑或是为项目添加一个暗色主题切换功能时你可以直接向Cursor提问它会分析现有代码上下文给出准确的修改建议甚至生成差异代码块。这相当于拥有一位随时待命、精通当前项目技术栈的资深编程伙伴极大地降低了开发和维护的心理负担。2.3 核心功能模块设计一个优秀的作品集不仅仅是项目的罗列。bilaltosungit/cursor-nextjs-portfolio项目通常包含以下精心设计的模块每个模块都服务于特定的展示目的响应式导航与页眉清晰展示个人品牌Logo/姓名提供主要页面的快速导航如首页、项目、关于、博客、联系并适配从手机到桌面的所有屏幕尺寸。高级版本可能包含主题切换按钮。英雄介绍区这是网站的“第一屏”用于快速建立个人形象。通常包含一个吸引眼球的标题如“全栈开发者”、“创意工程师”、一句精炼的个人标语、一张专业的头像或抽象图形以及一个明确的行动号召按钮如“查看我的项目”、“联系我”。项目展示区作品集的核心。以网格或列表形式展示精选项目。每个项目卡片应包含项目名称、简短描述、使用的技术栈标签、项目截图或动效预览以及指向项目详情页或外部演示/代码仓库的链接。技能与技术栈以可视化的方式如图标网格、进度条、标签云展示你掌握的技术、工具和框架。这能让访客在几秒钟内了解你的技术背景。关于我/经历用一段文字介绍你的背景、热情和职业哲学。可以结合时间线组件来展示教育背景和工作经历。博客/文章区可选但强烈推荐如果你有技术博客或文章集成一个简单的列表展示最新文章。这不仅能展示你的技术深度还能体现你的沟通和总结能力。Next.js非常适合构建这类内容驱动的页面。联系表单与社交链接提供一个简单的联系表单可集成第三方服务如Formspree或EmailJS以及指向GitHub、LinkedIn、Twitter等社交媒体的图标链接。页脚包含版权信息、可能的站点地图链接或再次强调联系方式。注意在设计这些模块时务必保持视觉风格的一致性色彩、字体、间距、圆角。使用像Tailwind CSS这样的工具可以极大地简化这一过程通过工具类快速实现一致的设计系统。3. 从零开始环境搭建与项目初始化3.1 前置条件与工具准备在动手之前确保你的开发环境已经就绪。你需要安装Node.js建议使用最新的LTS版本如18.x或20.x和包管理器npm或yarn。我个人更推荐使用pnpm它在速度和磁盘空间利用上更有优势。接下来是代码编辑器。虽然任何编辑器都可以但为了最大化利用本项目“cursor”的基因我强烈建议你尝试Cursor编辑器。它基于VS Code但深度集成了AI助手对于按照这个模式开发有奇效。当然使用VS Code配合GitHub Copilot或其他AI插件也是完全可行的。打开你的终端让我们开始创建项目。我们将使用Next.js官方提供的create-next-app脚手架工具这是最标准、最可靠的方式。3.2 使用Next.js脚手架创建项目在终端中导航到你希望创建项目的目录然后运行以下命令npx create-next-applatest my-portfolio --typescript --tailwind --app --no-eslint让我解释一下这些参数latest确保我们获取的是最新版本的Next.js。my-portfolio你的项目文件夹名称可以按需修改。--typescript添加TypeScript支持。对于严肃的项目TypeScript提供的类型安全是必不可少的能避免许多运行时错误。--tailwind集成Tailwind CSS。这是一个功能优先的CSS框架能让我们通过编写工具类来快速构建UI是当前前端开发的主流选择。--app使用Next.js 13/14引入的App Router。这是未来的方向提供了更简单的数据获取、布局和嵌套路由模型。--no-eslint暂时禁用ESLint初始化。对于快速原型有时严格的lint规则会干扰我们可以在后期再根据需要添加。运行命令后CLI会交互式地询问几个问题通常直接按回车选择默认推荐值即可如不启用src/目录不启用导入别名。完成后进入项目目录并安装基础依赖cd my-portfolio npm install # 或使用 pnpm install / yarn install3.3 项目结构与核心文件解读进入项目你会看到类似如下的结构my-portfolio/ ├── app/ │ ├── globals.css # 全局样式文件 │ ├── layout.tsx # 根布局组件定义整个站点的HTML骨架和共享布局 │ └── page.tsx # 首页组件 ├── public/ # 静态资源文件夹图片、字体等 ├── next.config.js # Next.js配置文件 ├── package.json ├── postcss.config.js # PostCSS配置文件Tailwind所需 ├── tailwind.config.ts # Tailwind CSS配置文件 └── tsconfig.json # TypeScript配置文件app/layout.tsx这是最重要的文件之一。它定义了整个应用的根HTML结构。你可以在这里设置全局的head标签标题、元描述、字体链接、全局样式引入以及所有页面共享的布局组件如导航栏和页脚。app/page.tsx你的网站首页。我们将在这里构建英雄区域、项目展示等核心内容。app/globals.css这里导入了Tailwind的基础样式。你也可以在这里添加一些自定义的全局CSS变量或样式。tailwind.config.ts在这里你可以扩展Tailwind的主题比如定义品牌色、自定义字体、添加插件等。现在你可以运行开发服务器来查看初始页面npm run dev打开浏览器访问http://localhost:3000你应该能看到Next.js的默认欢迎页面。我们的改造之旅将从这个页面开始。4. 核心组件开发与样式设计4.1 构建可复用的布局组件一个清晰的结构是良好代码的基础。我们首先在app/components/目录下创建一些可复用的组件。4.1.1 导航栏组件 (Navbar.tsx)导航栏是每个页面都需要的。我们创建一个响应式的导航栏在小屏幕上显示汉堡菜单。// app/components/Navbar.tsx import Link from next/link; import { Menu, X } from lucide-react; // 需要安装 lucide-react: npm install lucide-react import { useState } from react; const navItems [ { name: 首页, href: / }, { name: 项目, href: /projects }, { name: 关于, href: /about }, { name: 博客, href: /blog }, { name: 联系, href: /contact }, ]; export default function Navbar() { const [isOpen, setIsOpen] useState(false); return ( header classNamesticky top-0 z-50 w-full border-b border-gray-200 bg-white/80 backdrop-blur-md dark:border-gray-800 dark:bg-gray-950/80 div classNamecontainer mx-auto flex h-16 items-center justify-between px-4 md:px-6 {/* Logo */} Link href/ classNametext-xl font-bold text-gray-900 dark:text-white 你的名字 /Link {/* 桌面端导航 */} nav classNamehidden md:flex items-center gap-6 {navItems.map((item) ( Link key{item.name} href{item.href} classNametext-sm font-medium text-gray-600 transition-colors hover:text-gray-900 dark:text-gray-300 dark:hover:text-white {item.name} /Link ))} /nav {/* 移动端菜单按钮 */} button classNamemd:hidden onClick{() setIsOpen(!isOpen)} aria-labelToggle menu {isOpen ? X size{24} / : Menu size{24} /} /button /div {/* 移动端下拉菜单 */} {isOpen ( div classNamemd:hidden border-t border-gray-200 bg-white dark:border-gray-800 dark:bg-gray-950 div classNamecontainer mx-auto flex flex-col space-y-3 px-4 py-4 {navItems.map((item) ( Link key{item.name} href{item.href} classNamepy-2 text-base font-medium text-gray-600 hover:text-gray-900 dark:text-gray-300 dark:hover:text-white onClick{() setIsOpen(false)} {item.name} /Link ))} /div /div )} /header ); }这个组件使用了sticky定位确保导航栏始终在顶部并使用了背景模糊效果增强视觉层次。通过container和mx-auto实现水平居中hidden md:flex实现了响应式显示。4.1.2 页脚组件 (Footer.tsx)页脚相对简单主要包含版权信息和社交链接。// app/components/Footer.tsx import { Github, Linkedin, Twitter, Mail } from lucide-react; import Link from next/link; const socialLinks [ { icon: Github, href: https://github.com/yourusername, label: GitHub }, { icon: Linkedin, href: https://linkedin.com/in/yourusername, label: LinkedIn }, { icon: Twitter, href: https://twitter.com/yourusername, label: Twitter }, { icon: Mail, href: mailto:your.emailexample.com, label: Email }, ]; export default function Footer() { const currentYear new Date().getFullYear(); return ( footer classNameborder-t border-gray-200 bg-gray-50 py-8 dark:border-gray-800 dark:bg-gray-900/50 div classNamecontainer mx-auto px-4 md:px-6 div classNameflex flex-col items-center justify-between gap-6 md:flex-row {/* 版权信息 */} div classNametext-center text-sm text-gray-600 dark:text-gray-400 md:text-left p© {currentYear} 你的名字. 保留所有权利。/p p classNamemt-1用Next.js与Tailwind CSS构建。/p /div {/* 社交链接 */} div classNameflex items-center gap-4 {socialLinks.map((link) { const Icon link.icon; return ( Link key{link.label} href{link.href} target_blank relnoopener noreferrer classNamerounded-full p-2 text-gray-700 transition-colors hover:bg-gray-100 hover:text-gray-900 dark:text-gray-300 dark:hover:bg-gray-800 dark:hover:text-white aria-label{link.label} Icon size{20} / /Link ); })} /div /div /div /footer ); }4.2 设计并实现首页核心区域接下来我们修改app/page.tsx用我们自己的内容替换默认页面。我们将构建英雄区域和项目展示网格。4.2.1 英雄区域 (Hero Section)英雄区域是访客的第一印象需要简洁有力。// app/page.tsx import { ArrowRight, Sparkles } from lucide-react; import Link from next/link; import ProjectCard from /app/components/ProjectCard; // 我们稍后创建 // 模拟项目数据 const featuredProjects [ { id: 1, title: 智能任务管理平台, description: 一个基于React和Node.js的全栈应用集成了实时协作与AI任务优先级建议。, tags: [React, Node.js, PostgreSQL, Socket.io], imageUrl: /project1.jpg, // 占位图需放入public文件夹 projectUrl: https://demo.example.com, githubUrl: https://github.com/yourusername/project1, }, // ... 可以添加更多项目 ]; export default function HomePage() { return ( div classNameflex min-h-screen flex-col {/* 英雄区域 */} section classNamecontainer mx-auto flex flex-col items-center justify-center px-4 py-16 md:py-24 lg:flex-row lg:justify-between lg:px-6 div classNamemax-w-2xl text-center lg:text-left div classNamemb-4 inline-flex items-center rounded-full border border-gray-200 bg-gray-100 px-3 py-1 text-sm dark:border-gray-800 dark:bg-gray-800 Sparkles size{14} classNamemr-2 / 全栈开发者 创意工程师 /div h1 classNamemb-6 text-4xl font-bold tracking-tight text-gray-900 dark:text-white sm:text-5xl md:text-6xl 用代码构建 span classNameblock text-blue-600 dark:text-blue-400数字体验/span /h1 p classNamemb-8 text-lg text-gray-600 dark:text-gray-300 md:text-xl 我是[你的名字]专注于打造高性能、可访问且视觉出色的Web应用。热爱将复杂问题转化为优雅的解决方案。 /p div classNameflex flex-col gap-4 sm:flex-row sm:justify-center lg:justify-start Link href/projects classNameinline-flex items-center justify-center rounded-lg bg-blue-600 px-6 py-3 text-sm font-medium text-white transition-colors hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-950 查看我的项目 ArrowRight classNameml-2 h-4 w-4 / /Link Link href/contact classNameinline-flex items-center justify-center rounded-lg border border-gray-300 bg-transparent px-6 py-3 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 dark:border-gray-700 dark:text-gray-300 dark:hover:bg-gray-800 dark:focus:ring-gray-600 dark:focus:ring-offset-gray-950 联系我 /Link /div /div {/* 右侧头像或插图区域 - 暂时留空或放置一个占位图形 */} div classNamemt-12 lg:mt-0 lg:ml-12 div classNameh-64 w-64 rounded-full bg-gradient-to-br from-blue-100 to-purple-100 dark:from-blue-900/30 dark:to-purple-900/30 lg:h-80 lg:w-80/div /div /section {/* 精选项目区域 */} section classNamecontainer mx-auto px-4 py-12 md:px-6 md:py-16 div classNamemb-10 text-center h2 classNamemb-4 text-3xl font-bold text-gray-900 dark:text-white md:text-4xl 精选项目 /h2 p classNamemx-auto max-w-2xl text-gray-600 dark:text-gray-400 以下是我近期完成的一些代表性作品涵盖了从前端交互到后端架构的不同挑战。 /p /div div classNamegrid gap-6 sm:grid-cols-2 lg:grid-cols-3 {featuredProjects.map((project) ( ProjectCard key{project.id} project{project} / ))} /div div classNamemt-12 text-center Link href/projects classNameinline-flex items-center text-sm font-medium text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300 查看所有项目 ArrowRight classNameml-1 h-4 w-4 / /Link /div /section /div ); }4.2.2 项目卡片组件 (ProjectCard.tsx)项目卡片需要美观且信息清晰。// app/components/ProjectCard.tsx import { ExternalLink, Github } from lucide-react; import Image from next/image; import Link from next/link; interface ProjectCardProps { project: { id: number; title: string; description: string; tags: string[]; imageUrl: string; projectUrl?: string; githubUrl?: string; }; } export default function ProjectCard({ project }: ProjectCardProps) { return ( div classNamegroup relative overflow-hidden rounded-2xl border border-gray-200 bg-white shadow-sm transition-all hover:shadow-xl dark:border-gray-800 dark:bg-gray-900 {/* 项目图片 */} div classNameaspect-video overflow-hidden bg-gray-100 dark:bg-gray-800 Image src{project.imageUrl} alt{project.title} width{600} height{400} classNameh-full w-full object-cover transition-transform duration-300 group-hover:scale-105 / /div {/* 卡片内容 */} div classNamep-6 h3 classNamemb-2 text-xl font-semibold text-gray-900 dark:text-white {project.title} /h3 p classNamemb-4 text-gray-600 dark:text-gray-400 {project.description} /p {/* 技术标签 */} div classNamemb-6 flex flex-wrap gap-2 {project.tags.map((tag) ( span key{tag} classNamerounded-full bg-blue-100 px-3 py-1 text-xs font-medium text-blue-800 dark:bg-blue-900/30 dark:text-blue-300 {tag} /span ))} /div {/* 操作按钮 */} div classNameflex items-center justify-between {project.projectUrl ( Link href{project.projectUrl} target_blank relnoopener noreferrer classNameinline-flex items-center text-sm font-medium text-gray-700 hover:text-gray-900 dark:text-gray-300 dark:hover:text-white 访问项目 ExternalLink classNameml-1 h-4 w-4 / /Link )} {project.githubUrl ( Link href{project.githubUrl} target_blank relnoopener noreferrer classNameinline-flex items-center rounded-lg border border-gray-300 bg-transparent px-4 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-100 dark:border-gray-700 dark:text-gray-300 dark:hover:bg-gray-800 Github classNamemr-2 h-4 w-4 / 源码 /Link )} /div /div /div ); }提示注意Image组件来自next/image。Next.js的Image组件会自动优化图片格式、尺寸、懒加载对性能提升很大。确保你的图片放在public目录下并按需配置next.config.js中的images域如果需要使用外部图片。4.3 集成布局与全局样式最后我们需要将导航栏和页脚集成到根布局中并设置一些全局样式。修改app/layout.tsx// app/layout.tsx import type { Metadata } from next; import { Inter } from next/font/google; import ./globals.css; import Navbar from /app/components/Navbar; import Footer from /app/components/Footer; const inter Inter({ subsets: [latin] }); export const metadata: Metadata { title: 你的名字 | 个人作品集, description: 一名全栈开发者的个人作品集展示项目、技能与思考。, }; export default function RootLayout({ children, }: Readonly{ children: React.ReactNode; }) { return ( html langzh-CN classNamescroll-smooth body className{${inter.className} bg-white text-gray-900 antialiased dark:bg-gray-950 dark:text-gray-100} div classNameflex min-h-screen flex-col Navbar / main classNameflex-1{children}/main Footer / /div /body /html ); }在app/globals.css中确保Tailwind指令正确并可以添加一些自定义样式tailwind base; tailwind components; tailwind utilities; layer base { :root { --background: 0 0% 100%; --foreground: 222.2 84% 4.9%; } .dark { --background: 222.2 84% 4.9%; --foreground: 210 40% 98%; } } /* 自定义滚动条样式可选 */ ::-webkit-scrollbar { width: 10px; } ::-webkit-scrollbar-track { background: #f1f1f1; } ::-webkit-scrollbar-thumb { background: #888; border-radius: 5px; } ::-webkit-scrollbar-thumb:hover { background: #555; }至此一个具备基本结构和样式的作品集首页就搭建完成了。运行npm run dev你应该能看到一个现代、响应式的个人网站雏形。5. 高级功能实现与优化5.1 实现暗色/亮色主题切换主题切换是现代网站的标配。我们可以使用Next.js的next-themes库来轻松实现。首先安装依赖npm install next-themes然后我们创建一个主题提供者组件// app/components/ThemeProvider.tsx use client; // 因为要用到useState和useEffect必须是客户端组件 import { ThemeProvider as NextThemesProvider } from next-themes; import { type ThemeProviderProps } from next-themes/dist/types; export function ThemeProvider({ children, ...props }: ThemeProviderProps) { return NextThemesProvider {...props}{children}/NextThemesProvider; }修改app/layout.tsx用ThemeProvider包裹整个应用// app/layout.tsx (部分修改) import { ThemeProvider } from /app/components/ThemeProvider; // ... 其他导入 export default function RootLayout({ children }: Readonly{ children: React.ReactNode }) { return ( html langzh-CN classNamescroll-smooth suppressHydrationWarning body className{${inter.className} antialiased} ThemeProvider attributeclass defaultThemesystem enableSystem disableTransitionOnChange div classNameflex min-h-screen flex-col bg-white text-gray-900 dark:bg-gray-950 dark:text-gray-100 Navbar / main classNameflex-1{children}/main Footer / /div /ThemeProvider /body /html ); }注意suppressHydrationWarning属性用于避免因主题类名在服务端和客户端初始渲染不一致而产生的警告。我们将背景色和文字颜色的类名从body移到了内部的div上。现在创建一个主题切换按钮组件// app/components/ThemeToggle.tsx use client; import { Moon, Sun } from lucide-react; import { useTheme } from next-themes; import { useEffect, useState } from react; export default function ThemeToggle() { const { theme, setTheme } useTheme(); const [mounted, setMounted] useState(false); // 确保组件在客户端渲染后再显示避免水合不匹配 useEffect(() { setMounted(true); }, []); if (!mounted) { return ( button classNamerounded-lg p-2 aria-labelToggle theme disabled Sun classNameh-5 w-5 / /button ); } const toggleTheme () { setTheme(theme dark ? light : dark); }; return ( button onClick{toggleTheme} classNamerounded-lg p-2 text-gray-700 transition-colors hover:bg-gray-100 hover:text-gray-900 dark:text-gray-300 dark:hover:bg-gray-800 dark:hover:text-white aria-label{切换到${theme dark ? 亮色 : 暗色}主题} {theme dark ? Sun size{20} / : Moon size{20} /} /button ); }最后将这个ThemeToggle组件添加到你的Navbar.tsx中合适的位置比如在导航链接旁边。5.2 使用MDX创建博客系统一个技术博客是展示你思考深度的绝佳场所。Next.js对MDXMarkdown JSX有很好的支持。我们可以使用next/mdx来创建简单的博客。首先安装必要的包npm install next/mdx mdx-js/loader mdx-js/react更新next.config.js以配置MDX// next.config.js const withMDX require(next/mdx)(); /** type {import(next).NextConfig} */ const nextConfig { pageExtensions: [js, jsx, md, mdx, ts, tsx], // 其他配置... }; module.exports withMDX(nextConfig);在项目根目录创建mdx-components.tsx文件用于定义MDX中使用的自定义组件样式// mdx-components.tsx import type { MDXComponents } from mdx/types; export function useMDXComponents(components: MDXComponents): MDXComponents { return { h1: ({ children }) h1 classNamemb-6 mt-8 text-4xl font-bold{children}/h1, h2: ({ children }) h2 classNamemb-4 mt-8 text-3xl font-semibold{children}/h2, p: ({ children }) p classNamemb-4 leading-7{children}/p, ul: ({ children }) ul classNamemb-4 ml-6 list-disc{children}/ul, code: ({ children }) ( code classNamerounded bg-gray-100 px-1 py-0.5 font-mono text-sm dark:bg-gray-800 {children} /code ), ...components, }; }现在在app/blog/目录下创建你的第一篇博客my-first-post.mdx--- title: 我的第一篇技术博客 date: 2024-05-27 description: 关于如何在Next.js中集成MDX的探索。 --- # 欢迎来到我的博客 这是我的第一篇使用MDX写的博客。 MDX允许我在Markdown中直接使用React组件这非常强大。 例如我可以嵌入一个自定义的警告框 div classNamemy-6 rounded-lg border border-blue-200 bg-blue-50 p-4 dark:border-blue-900 dark:bg-blue-900/20 strong提示/strong 这是一个用MDX写的自定义组件块。 /div 也可以写代码块 jsx function Greeting({ name }) { return h1Hello, {name}!/h1; }接下来创建一个博客列表页app/blog/page.tsx来读取和展示所有博客文章。这需要读取文件系统我们可以使用fs模块注意这需要在服务端进行。为了简化我们可以将博客元数据标题、日期、描述、slug维护在一个单独的JSON文件或数据库中。这里展示一个基于文件系统的简单示例需要在API路由中实现或使用getStaticProps但在App Router中更推荐使用服务端组件直接读取。5.3 性能优化与最佳实践图片优化始终坚持使用next/image组件。为next.config.js中的images域配置你可能会用到的外部图片CDN。字体优化使用next/font自动优化和托管Google Fonts或本地字体避免布局偏移CLS。代码分割与懒加载Next.js默认支持基于路由的代码分割。对于大型组件可以使用React.lazy结合Suspense进行动态导入减少初始包大小。静态生成SSG对于作品集、博客文章这类不常变化的内容优先使用静态生成。在页面组件中使用generateStaticParams对于动态路由或在layout.tsx/page.tsx中直接导出数据获取函数Next.js会在构建时生成静态HTML。元数据API充分利用Next.js 13的元数据APImetadata对象来为每个页面设置标题、描述、Open Graph标签等提升SEO。分析工具考虑集成像Vercel Analytics、Google Analytics或Umami这样的分析工具了解访客行为。6. 部署上线与持续迭代6.1 部署到Vercel推荐Vercel是Next.js的创建者提供的平台部署体验无缝。将你的代码推送到GitHub、GitLab或Bitbucket仓库。登录 Vercel 点击“Add New...” - “Project”。导入你的Git仓库。Vercel会自动检测到是Next.js项目配置几乎无需修改。保持默认设置点击“Deploy”。部署完成后你会获得一个*.vercel.app的域名。你可以在项目设置中绑定自己的自定义域名。Vercel的优势在于自动的HTTPS、全球CDN、每次git push自动触发部署预览和生产环境、服务器less函数支持、以及深度集成的性能分析工具。6.2 自定义域名与SEO设置在Vercel的项目设置中找到“Domains”选项添加你的自定义域名例如portfolio.yourname.com。你需要按照指引在你的域名注册商处添加CNAME或A记录。确保在app/layout.tsx和各个页面的metadata中设置了正确的canonicalURL、Open Graph图片和Twitter卡片以便在社交媒体分享时显示正确的信息。6.3 内容更新与维护流程作品集不是一次性的项目而是一个需要持续维护的“数字花园”。项目更新定期将你的新项目添加到app/projects/目录或数据源中。保持项目描述精炼突出技术亮点和业务价值。博客写作养成写博客的习惯。即使是小知识点的总结也能体现你的学习能力和分享精神。MDX文件可以直接放在app/blog/下部署后自动更新。技能树刷新技术栈在变化定期回顾并更新你的技能展示部分。性能监控利用Vercel Analytics或Lighthouse等工具定期检查网站性能确保加载速度始终保持在优秀水平。反馈收集可以在联系表单或通过社交媒体主动寻求朋友、同行对你的作品集的反馈持续改进用户体验。7. 常见问题与排查技巧实录在实际构建和部署过程中你可能会遇到一些典型问题。以下是我在多个类似项目中总结的一些经验和解决方案。问题1图片加载失败或控制台出现Image组件警告。症状图片不显示或控制台提示“Invalid src prop”或“Missingwidthprop”。排查检查图片路径是否正确。public目录下的图片路径应以/开头如/project1.jpg。如果使用外部图片必须在next.config.js中的images.remotePatterns或images.domains中配置主机名。确保为Image /组件提供了width和height属性或者设置fill属性并让父容器有尺寸。解决// next.config.js module.exports { images: { remotePatterns: [ { protocol: https, hostname: images.unsplash.com, // 可以指定路径名和端口 }, ], // 或者使用旧的 domains 配置 // domains: [images.unsplash.com], }, };问题2暗色主题切换时页面闪烁。症状页面加载时先显示亮色主题然后快速切换到暗色或反之。原因这是因为next-themes在客户端才确定主题而服务端初始渲染时没有主题类名导致短暂的不匹配。解决我们已经在ThemeToggle组件中通过mounted状态和suppressHydrationWarning属性缓解了此问题。另一种更彻底的方法是在html标签上内联一段脚本来在HTML加载之初就读取localStorage或系统主题但这需要更复杂的实现。通常上述方法已能极大改善体验。问题3部署到Vercel后API路由或动态路由返回404。症状本地开发正常但线上访问/api/xxx或/blog/[slug]页面时显示404。排查检查Vercel部署日志看构建是否成功是否有错误。确认你的动态路由页面如app/blog/[slug]/page.tsx正确导出了generateStaticParams函数如果使用SSG或者没有错误的逻辑导致在构建时被跳过。对于API路由app/api/route.ts确保其HTTP方法GET, POST等被正确处理。解决清理.next缓存重新部署。仔细检查动态路由参数和API路由的处理逻辑是否符合Next.js App Router的规范。问题4字体图标或SVG图标不显示。症状使用了像lucide-react这样的图标库但图标不显示或显示为方块。排查确认图标组件是否正确导入和使用。对于lucide-react你需要使用具名导入如import { Home } from lucide-react;然后在JSX中使用Home size{24} /。解决检查包是否已安装node_modules中存在并重启开发服务器。有时打包工具需要刷新缓存。问题5Tailwind CSS样式在生产环境不生效。症状开发环境样式正常但运行npm run build和npm run start后部分Tailwind类名对应的样式丢失。原因Tailwind使用PurgeCSS在Tailwind v3中是内置的来移除未使用的CSS以减小文件体积。如果你的样式类名是动态拼接的例如bg-${color}-500PurgeCSS可能无法识别它们。解决在tailwind.config.ts的safelist数组中明确列出这些动态类名。避免使用完全动态的类名拼接改为使用完整的类名字符串。// tailwind.config.ts export default { // ... safelist: [ bg-red-500, text-center, // 你需要的任何类名 ], }构建一个个人作品集是一个迭代的过程。不要追求第一次就完美。先从核心功能开始部署一个可访问的版本然后根据反馈和你的成长不断添加新内容、优化设计和体验。这个cursor-nextjs-portfolio项目模板为你提供了一个坚实的起点和一套现代化的技术组合剩下的就是填充属于你自己的独特内容与故事了。记住作品集本身也是你技术能力的最佳证明。