惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 三生石上(FineUI控件)
月光博客
月光博客
人人都是产品经理
人人都是产品经理
Google DeepMind News
Google DeepMind News
M
MIT News - Artificial intelligence
Vercel News
Vercel News
MyScale Blog
MyScale Blog
爱范儿
爱范儿
博客园 - 司徒正美
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
IT之家
IT之家
H
Help Net Security
Last Week in AI
Last Week in AI
阮一峰的网络日志
阮一峰的网络日志
酷 壳 – CoolShell
酷 壳 – CoolShell
L
LangChain Blog
罗磊的独立博客
Stack Overflow Blog
Stack Overflow Blog
宝玉的分享
宝玉的分享
博客园 - 聂微东
云风的 BLOG
云风的 BLOG
J
Java Code Geeks
博客园 - 叶小钗
D
Docker

秋实-Allenyou 的小窝

【笔记】人工智能与模式识别 复习笔记 - 秋实-Allenyou 的小窝 【教程】使用 Keyd 将 Copilot 键映射为可用的组合键并修复触摸板防误触失效问题 机械革命无界 15X 的 Arch Linux 开荒指南 我在用什么?(2026 版) - 秋实-Allenyou 的小窝 关于 Next.js SSG 生成 RSS Feed 文件的另一思路 从零开始的 NixOS 体验 - 秋实-Allenyou 的小窝 2025:迷茫中转向 - 秋实-Allenyou 的小窝 我在用什么?(2025 版) - 秋实-Allenyou 的小窝 【杂谈】关于 AIGC 的一些思考 - 秋实-Allenyou 的小窝 【记录】一种在主机通过 Docker 容器名解析容器 IP 的方法 【记录】如何在 Next.js 中优雅的调用 Matomo 统计 从信号与系统角度看 OI/XCPC 中的傅里叶变换运用 - 秋实-Allenyou 的小窝 【杂谈】答《博客作者呀,我想采访你这 9 个问题!》 - 秋实-Allenyou 的小窝 使用 Golang 重写 gh-proxy - 秋实-Allenyou 的小窝 FurryCTF 2024 寒假赛 调试窗口 题解 2024:“我”的大学生活 - 秋实-Allenyou 的小窝 【游记】CCPC 2024 重庆站尾杀记 - 秋实-Allenyou 的小窝 【游记】ICPC 2024 亚洲区域赛南京站打铁记 - 秋实-Allenyou 的小窝 【杂谈】这次 Furrygooo 结束后我的一些体验 - 秋实-Allenyou 的小窝 【教程】使用阿里云 OSS + CDN 加速 Gravatar 【记录】 一次罗技鼠标驱动冲突问题的排查经历 - 秋实-Allenyou 的小窝 【教程】如何用 Git 快速搭建简单的 CI - 秋实-Allenyou 的小窝 我的DN42 Peering信息 - 秋实-Allenyou 的小窝 【进度】博客重构计划 - 秋实-Allenyou 的小窝 这是一个正经的2023总结 - 秋实-Allenyou 的小窝 【题解】Luogu P9769 [HUSTFC 2023] 简单的加法乘法计算题 2023新年谜题总结 - 秋实-Allenyou 的小窝 【教程】浅谈Linux服务器的一些基础安全技巧 - 秋实-Allenyou 的小窝 Goodbye, 2022~ - 秋实-Allenyou 的小窝 【教程】使用 Docker 开服,优雅地隔离不同版本JDK - 秋实-Allenyou 的小窝
【记录】我是如何用 Next.js 重构我的博客的 - 秋实-Allenyou...
2024-03-09 · via 秋实-Allenyou 的小窝

前段时间完成了博客的重构,在这里记录一些重构过程中的经验(?)

技术选型

静态 vs 动态

从 2019 年开始,我的博客一直使用 Wordpress/Typecho 等基于 PHP 的 CMS 构建。

动态生成站点内容的好处是显而易见的,比如使用体验良好的管理后台、自带的评论系统、更快的更新站点速度等。此外,相比于需要自行在本地搭建开发环境的 Hexo 等静态博客系统,动态 CMS 更加”开箱即用“的设置也极大降低了搭建博客的门槛。

但是相对的,Wordpress/Typecho 等动态 CMS 的问题也很明显:每次打开页面都需要访问数据库带来的较高 TTFB、与 PHP 深度耦合导致无法使用 React/Vue 等相对更”现代“的前端技术栈……虽然使用 Redis/Memcached 缓存 + 静态资源 CDN 的方案可以缓解,但静态 CMS 方案在 TTFB 上的优势依旧是显而易见的。

考虑到我的服务器基本都是 2C2G 这种入门配置,还是用静态方案吧(

前端:React or Vue?

目前主流的前端框架主要有 React 和 Vue 两大派(其他后起之秀我不了解,这次显然没法用),两个框架提供的特性、性能都大差不差,所以选择哪一个主要取决于上层框架。

在这点上,同样是面向 SSR 的上层框架,基于 React 的 Next.js 拥有远好于基于 Vue 的 Nuxt.js 的生态,出各种问题都能更好地找到资料。

最后权衡一下,选择了 React & Next.js 的前端方案。

CSS:Tailwind CSS 真香

首先声明,我对前端设计一窍不通

因为没有正统学习过前端 HTML + CSS + JS 技术栈,我一直都是以”现用现学“的方法补习这些基础知识。但是同样地,现在让我自己用传统的 CSS/SCSS 去构建博客的前端样式显然会堆成屎山。此外,CSS 优化这个老生常谈的问题显然能直接让我原地爆炸

好在有 Tailwind CSS。

你说得对,但是 Tailwind CSS 是由 Tailwind Labs 自主研发的一款全新 Utilities-first CSS 框架。

正经点说,Tailwind CSS 把原有的众多 CSS 规则全部拆成了 class 的形式,使用时不需要写 CSS,只要直接写 class 就行,每条 className 对应一条简单的规则,比如 p-4 对应 padding: 1rem 规则,在最终构建时 Tailwind CSS Compiler 将扫描代码,提取所有用到的规则名称并且合并为一个 CSS 文件。

更多详情请前往官网

后端:Not Hexo

虽然 Hexo 的 Warehouse 后端用的人很多,但是我这里没有用这个。

一方面是我的博客去除了分类/标签,而 Hexo 有这个,略显麻烦;另一方面我太菜没搞明白文档

所以我写了个简单的后端,使用 frontmatter 库在 .md 文件头写标题、日期之类的 Metadata,通过扫描文件建立临时 CMS。

源代码在 src/libs/content.ts 里面。

技术笔记

图片 Lazyload & 灯箱

这里图片的 Lazyload 优化使用了 Sukka 大佬的实现,代码在这里

同时,我在 <LazyloadImage /> 组件中附加了 medium-zoom 库,添加了图片点击放大的效果。

为了让 Lazyload 和 medium-zoom 的 Ref 不冲突,我将原本官方的 RefCallback 改成了这样:

const myref: RefCallback<HTMLImageElement> = (node) => {
	imageElRef.current = node;
	const zoom = getZoom();
	if (node) {
		zoom.attach(node);
	} else {
		zoom.detach();
	}
};

扩展 Markdown 解析

参照 Sukka 大佬的思路,我在博客构建时通过 markdown-it 库对 Markdown 内容进行解析渲染为 HTML,并通过 htmr 库将生成的 HTML 解析为 React 节点树插入页面。在此过程中,我通过 htmr 库的 transform 参数控制了 HTML 标签的解析方式,将 a 标签解析为自定义的 <AllenyouLink /> 组件,从而实现内外链区分跳转(博客内链在当前页面无刷新跳转,外链使用 _blank 参数在新页面打开),同时将 img 标签解析为 <LazyloadImage /> 组件实现 Lazyload。

同时,由于 Markdown 原生支持内嵌 HTML,在 Markdown 源文件中插入的 HTML 代码会被原样保留。因此,综合考虑后,我对 div 标签的解析做了修改,替换为自定义的 <AllenyouDiv /> 组件。

在此组件中,我添加了属性 component。当 component 为空或不在预先设定的列表中时,将原样解析为 div 标签。若 component 值在预定义的列表中时,将解析为自定义的 React 组件。

目前已经实现的组件有:

  • Bilibili: 嵌入 Bilibili 视频播放器

相关组件在 src/components/MarkdownExtend 下存放。

// src/components/AllenyouDiv.tsx
export default function AllenyouDiv(
	props: JSX.IntrinsicElements["div"] & {
		component?: string;
		children?: React.ReactNode;
	}
) {
	if (props === undefined || !props.hasOwnProperty("component")) {
		return <div>{props.children}</div>;
	}
	if (!customComponents.hasOwnProperty(props.component!)) {
		return <FallbackComponent {...props}>{props.children}</FallbackComponent>;
	}
	const Target = customComponents[props.component!];
	if (props.children === undefined || props.children === null) {
		return <Target {...props} />;
	} else {
		return <Target {...props}>{props.children}</Target>;
	}
}

博客的 CI 构建

在博客的构建上,我选择在本地构建,通过 npm 的 postbuild 钩子将构建好的网站提交到服务器上的 Git 仓库,并在服务器上使用 Git Hook 搭建简单的 CI 实现自动将网站部署到 NGINX 网站目录下,并将静态文件上传到 OSS,刷新 CDN 缓存。

详情请参见这篇文章

未完待续