使用 Next.js 搭建個人博客
現階段有非常非常多的靜態博客生成工具(site generators),Hexo、VuePress、Docusaurus 等等,基本只需把 markdown 文件配置到指定目錄,無需編寫其他代碼即可建站。
本文記錄一下使用 next.js 從 0 到 1 搭建一個博客網站的流程。
初始化項目
使用 blog-starter-typescript 作為模板創建一個項目
npx create-next-app my-blog --use-yarn --example "https://github.com/vercel/next.js/tree/canary/examples/blog-starter-typescript"
模版 example 是個大倉庫,包含了 next.js 與各種技術集成的樣例
目錄結構
.
├── @types
├── README.md
├── _posts # 博客 .md 文件
│ ├── dynamic-routing.md
│ ├── hello-world.md
│ └── preview.md
├── components
├── lib # 解析 .md 文件,提取文章數據
│ ├── api.ts
│ ├── constants.ts
│ └── markdownToHtml.ts
├── next-env.d.ts
├── package.json
├── pages # blog 各個頁面
│ ├── _app.tsx # 自定義初始化頁面
│ ├── _document.tsx #自定義 html body
│ ├── index.tsx
│ └── posts
├── postcss.config.js
├── public
├── styles
├── tailwind.config.js
├── tsconfig.json
└── types
模版是簡單的 blog 樣例,包含讀取解析 markdown 文件、加載文章數據、生成首頁、生成 blog 文章頁面。
用到的 npm 包:
gray-matter處理 yaml front matterremark解析 markdown,把 markdown 轉成 astremark-html把 ast 轉成 htmltailwindcss原子化樣式 class,無需頭疼組件 class 的命名
生成頁面
生成的頁面對應 pages 目錄下的文件,頁面的路由為文件路徑名,例如 pages/about.tsx ,則頁面路由為 /about。
一般項目的目錄都會有 src 目錄,所以 next.js 也支持 src/pages 目錄。
很明顯,不可能為每篇 blog 文章都創建一個文件,那麼就需用到動態路由(dynamic routes)。
getStaticPaths
動態路由形如 pages/posts/[slug].tsx,然後就會生成 posts/1, posts/2,slug 可以理解為前端路由的路徑參數 params。
頁面需定義 getStaticPaths 方法,必須返回 params 參數。
// pages/posts/[slug].tsx
const Post = () => {...}
export default Post
export async function getStaticPaths() {
const posts = getAllPosts(['slug'])
return {
paths: posts.map((post) => {
return {
params: {
slug: post.slug,
},
}
}),
}
}
獲取數據
getStaticProps
getStaticProps 會在服務端執行,因此可以使用 node api,讀取文件系統,獲取 markdown 內容。
返回值會作為頁面組件的 props,入參為 getStaticPaths的返回值。
const Post = ({ post, morePosts }: Props) => {
return <Layout>...</Layout>;
};
export default Post;
export async function getStaticProps({ params }) {
const post = getPostBySlug();
const content = await markdownToHtml(post.content || '');
return {
props: {
post: {
...post,
content,
},
},
};
}
定製化
在 pages 下還有 _app.tsx 和 _document.tsx,這兩個文件用於定製化頁面。
next.js 默認使用 next/app 初始化頁面,_app.tsx會替代next/app初始化頁面,因此可以在 _app.tsx放一些公共邏輯,公共的佈局,導入樣式等。
import { AppProps } from 'next/app';
import 'github-markdown-css/github-markdown-light.css';
import '../styles/index.css';
import Layout from '@/layout';
export default function MyApp({ Component, pageProps }: AppProps) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
);
}
同樣,_document.tsx 用於為 html、body 做定製化
import { Html, Head, Main, NextScript } from 'next/document';
// 必須導入 Html、Head、Main、NextScript,不能省略
export default function Document() {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
結語
一個 blog 的原型基本就搭建起來了,剩餘就是部署到靜態託管服務上(Vercel、GitHub Page 等),另外可以參照 example,與其他技術集成,繼續美化 blog。
參考鏈接
- Next.js 官方文檔
- 學習 Next.js