从0到1搭建技术博客,Next.js Tailwind CSS MDX全流程
本文目录导读:
在当今互联网时代,拥有一个个人技术博客不仅能帮助开发者记录学习历程,还能提升个人品牌影响力,许多开发者可能会因为技术选型或搭建过程的复杂性而望而却步,本文将详细介绍如何从零开始搭建一个现代化的技术博客,使用 Next.js 作为前端框架,Tailwind CSS 进行样式设计,并支持 MDX 格式的博客内容管理,我们将涵盖从项目初始化到部署的全流程,帮助你快速构建一个高性能、可扩展的技术博客。

技术选型与项目初始化
1 为什么选择 Next.js + Tailwind CSS + MDX?
- Next.js:基于 React 的框架,支持 SSR(服务端渲染)和 SSG(静态生成),适合 SEO 优化,并提供优秀的开发体验。
- Tailwind CSS:一个实用优先的 CSS 框架,可以快速构建响应式 UI,无需编写大量自定义 CSS。
- MDX:Markdown 的扩展,允许在 Markdown 中嵌入 React 组件,适合技术博客的内容管理。
2 初始化项目
使用 create-next-app 快速搭建 Next.js 项目:
npx create-next-app@latest my-tech-blog --typescript cd my-tech-blog
安装 Tailwind CSS:
npm install -D tailwindcss postcss autoprefixer npx tailwindcss init -p
配置 tailwind.config.js:
module.exports = {
content: [
"./pages/**/*.{js,ts,jsx,tsx}",
"./components/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
在 globals.css 中引入 Tailwind:
@tailwind base; @tailwind components; @tailwind utilities;
搭建博客核心功能
1 文章管理与 MDX 集成
安装 @next/mdx 和 remark 相关插件:
npm install @next/mdx @mdx-js/loader @mdx-js/react remark-gfm rehype-highlight
在 next.config.js 中配置 MDX:
const withMDX = require("@next/mdx")({
extension: /\.mdx?$/,
options: {
remarkPlugins: [require("remark-gfm")],
rehypePlugins: [require("rehype-highlight")],
},
});
module.exports = withMDX({
pageExtensions: ["ts", "tsx", "md", "mdx"],
});
创建 posts 目录存放 MDX 文件,示例 hello-world.mdx:
--- "Hello World"
date: "2023-10-01"
description: "我的第一篇博客文章"
---
# Hello World
这是我的第一篇博客文章,使用 **MDX** 编写!
```js
console.log("Hello, MDX!");
### **2.2 实现文章列表与详情页**
#### **文章列表页 (`pages/index.tsx`)**
```tsx
import { GetStaticProps } from "next";
import fs from "fs";
import path from "path";
import matter from "gray-matter";
interface Post {
slug: string;
frontmatter: { string;
date: string;
description: string;
};
}
export default function Home({ posts }: { posts: Post[] }) {
return (
<div className="max-w-3xl mx-auto p-4">
<h1 className="text-3xl font-bold mb-6">技术博客</h1>
<ul className="space-y-4">
{posts.map((post) => (
<li key={post.slug} className="border-b pb-4">
<a href={`/posts/${post.slug}`} className="block hover:text-blue-500">
<h2 className="text-xl font-semibold">{post.frontmatter.title}</h2>
<p className="text-gray-600">{post.frontmatter.date}</p>
<p className="text-gray-500">{post.frontmatter.description}</p>
</a>
</li>
))}
</ul>
</div>
);
}
export const getStaticProps: GetStaticProps = async () => {
const postsDir = path.join(process.cwd(), "posts");
const filenames = fs.readdirSync(postsDir);
const posts = filenames.map((filename) => {
const filePath = path.join(postsDir, filename);
const fileContent = fs.readFileSync(filePath, "utf-8");
const { data } = matter(fileContent);
return {
slug: filename.replace(/\.mdx$/, ""),
frontmatter: data,
};
});
return { props: { posts } };
};
文章详情页 (pages/posts/[slug].tsx)
import { GetStaticProps, GetStaticPaths } from "next";
import fs from "fs";
import path from "path";
import matter from "gray-matter";
import { MDXRemote } from "next-mdx-remote";
import { serialize } from "next-mdx-remote/serialize";
interface PostProps {
frontmatter: { string;
date: string;
description: string;
};
mdxSource: any;
}
export default function Post({ frontmatter, mdxSource }: PostProps) {
return (
<div className="max-w-3xl mx-auto p-4">
<h1 className="text-3xl font-bold mb-2">{frontmatter.title}</h1>
<p className="text-gray-600 mb-6">{frontmatter.date}</p>
<article className="prose prose-lg">
<MDXRemote {...mdxSource} />
</article>
</div>
);
}
export const getStaticPaths: GetStaticPaths = async () => {
const postsDir = path.join(process.cwd(), "posts");
const filenames = fs.readdirSync(postsDir);
const paths = filenames.map((filename) => ({
params: { slug: filename.replace(/\.mdx$/, "") },
}));
return { paths, fallback: false };
};
export const getStaticProps: GetStaticProps = async ({ params }) => {
const filePath = path.join(process.cwd(), "posts", `${params?.slug}.mdx`);
const fileContent = fs.readFileSync(filePath, "utf-8");
const { data, content } = matter(fileContent);
const mdxSource = await serialize(content);
return { props: { frontmatter: data, mdxSource } };
};
优化与部署
1 样式优化
- 使用
@tailwindcss/typography优化文章排版:npm install @tailwindcss/typography
在
tailwind.config.js中添加:plugins: [require("@tailwindcss/typography")],
2 SEO 优化
在 推荐使用 Vercel(Next.js 官方托管平台): 本文详细介绍了如何从零开始搭建一个基于 Next.js + Tailwind CSS + MDX 的技术博客,涵盖: 通过这个流程,你可以快速搭建一个高性能、现代化的个人博客,并专注于内容创作,希望本文对你有所帮助!🚀pages/_app.tsx 中添加 <Head>
import Head from "next/head";
function MyApp({ Component, pageProps }) {
return (
<>
<Head>
<title>我的技术博客</title>
<meta name="description" content="记录技术学习与思考" />
</Head>
<Component {...pageProps} />
</>
);
}
3 部署