我的博客重构之旅
咕咕了好几年,我的博客终于要重构上线了!
技术选型
以前用的Hexo
已经太过于古老想换个现代化的框架。热门选择基本都看了一下。
VuePress
/VitePress
:这两个框架构建的博客都带有浓厚的文档风格,与我期望的博客风格不符。(不知道是谁的问题😅)Nuxt.js
:当时Nuxt.js
刚开始适配Vue3
,存在不少 bug。Gatsby
/gridsome
:这两个框架的数据源只能是graphql
。gridsome
生态比前者更差。Next.js
:支持 SSG 和静态导出,对数据源没有限制,只要略懂React
语法就能轻松上手。Astro
:支持多种框架,这一点非常赞,但是我并不喜欢它的语法。
Vercel 推出的 turbopack
我一直到 Next.js 14.2.3
版本都无法正常使用,遇到了各种报错。希望明年能够顺利使用它,webpack
实在是太慢了。
博客评论功能使用的是 walien
,基于 Solidjs
构建的客户端。压缩后仅有 20kb,修一波bug后会开源。
最终方案为: Next.js
+ TypeScript
+ MDX
+ TailwindCSS
。
为什么不是Nuxt
?想尝试React
,而且我也没多到Next.js
有这么多bug。
数据源
_posts --------------------- // 文章目录
├─slug ------------------- // 每篇文章一个文件夹
│ ├─index.md ------------- // 文章
| |-components.ts -------- // 文章中使用的组件
| |- * ------------------- // 图片等资源
文章列表,Atom
,sitemap
都是通过使用fs遍历_posts
下全部文件夹获取数据。为了避免每次生成页面时重复读取全部文章获取时间进行排序,我在项目启动前读取全部文章的 Frontmatter 数据,进行排序并存储在项目中,减少对_posts
目录的遍历次数。
由于next-mdx-remote
不支持在文章中使用import
,因此只能在单独的文件中导入组件并传递给MDXRemote
。
// _posts/refactor-my-blog-using-nextjs/components.ts
import BgmSubject from '@/components/BgmSubject'
export { BgmSubject }
// app/posts/[slug]/page.tsx
export default async function Page({ params }: props) {
let postComponents = {}
try {
postComponents = await import('@/_posts/${params.slug}/components')
} catch (e) {}
/* ... */
return (
<MdxRemote
source={post.content}
components={postComponents}
/>
)
}
首页内容原本打算使用memos
管理,但由于没有服务器无法使用Docker
部署,只能由Leacloud代替。编写了一个简单的页面进行发布和管理,更新数据后调用Next.js
的revalidatetag
刷新首页数据。
bangumi页面使用bangumi的api获取数据,由于数据太多又懒得搞分页没必要,所以只展示前21条数据。二次元老婆部分因为官方api不能获取目录中收藏的角色。所以使用cheerio
爬取数据。
为markdown赋能
在Hexo
中,为Markdown
生成的内容添加交互操作十分繁琐,而现在借助MDX
的能力,只需定义组件替换DOM元素即可实现,无需额外学习成本。如果不使用MDX
,一些原本可以在服务端完成的功能就需要在客户端处理,添加交互也难以像组件化那样方便管理代码。
Next.js
官方集成的MDX
不够灵活无法在页面局部使用,仅适用于文档站点。
对于基本的Markdown
内容,mdx-bundler
的输出至少比next-mdx-remote
的输出大 400%。(RSC加持下这一优势我不确定是否还存在)。由于我在Markdown
中使用组件的频率较低,因此我选择使用next-mdx-remote
。
我只需要在文章中添加<BgmSubject id="395378" />
即可实现如下效果。直接贴链接也可以做到但是还没有弄。写这篇文章的时候才想到
默认元素我只替换了pre
和img
。使用shiki
实现代码高亮,为代码块添加复制按钮。plaiceholder
配合next/image
优化图片,react-medium-image-zoom
实现图片放大预览。