从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 部署