如你所见,当你访问这篇文章的时候,我已经把写了 13 年的博客程序从 WordPress 迁移到了自己用 Next.js 写的程序。这可能是我第 N 次尝试使用其他的方式写博客,但我想绝对不会是最后一次。
第一次接触类博客的平台还是 20 年前,初一同学在课间说道:“我开通了 QQ 空间,快去给我踩一踩。”正儿八经地写作,还要追溯到 15 年前,那时的我是那么多愁善感,什么东西都想要“为赋新词强说愁”。我的足迹遍布各类 SNS 平台,在上面书写各种现在看来相当幼稚的话语。
因为专业的原因,在大学期间接触到了独立博客和 WordPress,当时的我就被这种独立而又个性的写作方式惊到了。那时还属于独立博客的黄金年代,QQ 雷锋群里群英荟萃,我那孱弱的前端知识就是通过此类途径习得。而我没想到的是,当初的开博宣言竟然一写就是 13 年。
年龄真是个好东西,因为其增长,我们能不断地丰富自己的阅历,也能见证所谓的“历史”。兜兜转转,写博客的人来来去去。有些相识数载至今还是好友,有些已经消失再无音讯。而我,对这 WordPress 也是又爱又恨,这期间换过太多的平台。有简单的 Hexo、Hugo,也有同样基于 LAMP 平台的 Typecho、Emlog、Z-Blog,还有之前很时髦的 Ghost。很多文章评论都放在了多说、Disqus 上,因为这来来回回的“搬迁”遗失大半。到头来,竟然还是这 WordPress 最好用,如同家里的“黄脸婆”,阅尽世间百态,才发现老婆是真爱。虽然至今还是不会写 WordPress 主题,但好在漂亮的主题数不胜数,凭着钞能力也能基本解决。
但,我还不甘心。
这十几年来前端风起云涌,每天都有新的东西诞生。13 年前博客用个 jQuery 就很了不起了,很多页面还使用表格布局,为了 IE6 要写一堆 Hack,那个时候声称不兼容 IE 的网站都属于“珍惜动物”。而如今 IE 早已不复存在,继任者 Edge 也把自己变成了 Chrome 的模样。前端相关的框架更是层出不穷,光打包工具我就完完整整地经历了 Grunt、Gulp、Webpack、Rollup、Vite、SWC 等,更别提其他的了。在这些技术的背景下,我这基于 jQuery 的 WordPress 就显得稍微有点 old school 了。
上周和 Tison 聊天,发现他正好准备基于 Astro 弄个新的博客。沉眠于心中多年的想法终于浮起,既然用了这么多博客平台都不满意,为何不能自己写一个。Next.js 这么时髦,其 App Router 还能用最新的 React Server Component,我都眼馋很久了。于是说干就干,趁着正好清明放假,我把几乎所有的时间都投入在了这一“浩大”的造博运动中。
Logo 设计
对我而言,技术牛逼与否并不是最重要的,最重要的是颜值。如果不好看,那就直接 pass。所以还没写博客,第一步,我就在考虑重新设计自己的博客 logo。对于之前用的 logo,其实问题并不大,主要的问题是矢量化。绘制这个 logo 的时候还是 6 年前,像素被限制在了 65px,在 PSD 底稿和对应字体都丢失的当下,想要放大适应视网膜屏幕等就显得有些困难。于是我借着这个机会,学习使用 sketch 来绘制矢量图形。这当中最大的绘制难点就是 logo 中那两个不规则的半圆环,我画了两个圆去叠加,然后合并后一点点拖拽曲线。才调整到和以前相似的形状。
绘制“帆”字的时候已经稍微熟悉,就直接使用钢笔工具一个个锚点描边,再稍微调整曲线就好,但是没想到还是在和圆环合并上栽了大跟头。弄了半天才发现是路径曲线的闭合问题,这其中的曲折大概就像是以前在微博上看到的这张长图所描绘的景象。不过万幸的是,最终圆满地达成了我想要的效果。
在绘制 logo 的同时,我也一并绘制了黑白两种形态,为日后主题支持黑白模式准备,同时也绘制了 Github Poster 放在 README.md
上用于展示。这当中最有意思的事情,就是对以膨胀色与收缩色的概念的复习。以前自学设计的时候,觉得这东西很抽象。这次设计黑色 logo 的时候,发现明明是同样的大小,但是黑色的 logo 在屏幕上就是显得大上一圈。我不得不微调曲线,向内收缩一圈才在视觉的保持了 logo 的大小一致,相当有趣。
字体使用
字体选择上分为博客正文字体和图片字体。以前并不懂版权,不知道字体很多是需要授权才能在一些公开媒介上使用的,这次特意选择了商业免费可用的字体。
正文字体使用的是 OPPO Sans 3.0,5 年前在字谈字畅的 PodCasts 得知此字体的公布,当即就喜欢上了。虽然和阿里普惠体、微软雅黑体等一众“汉仪兄弟们”师出同门,但是其变化是最讨喜的。它去掉了自冬青黑体时代就有的大喇叭口,字形更加方正,在笔画转弯处也更加刚正。其家族字体设计更多的是为传统非视网膜屏幕服务,所以夸张的笔锋搭配上抗锯齿就能有较好的观感。这种设计,放在当今连手机都是视网膜屏幕的年代,就显得很难看。所以 OPPO Sans 的设计,在当下很长一段时间,将成为我的首选字体。
Logo 部分的字体,主要是基于 M+A1 进行制作。虽然此字体是日本人制作,但是不同于在日本起绝对统治地位的明朝体,此字体是一款明朗的黑体,而且同时免费提供了多种粗细字型,简直感动到哭。最有意思的就是细款字形的笔画末端都有一定的隆起,结合之前学习到的光陷阱,想必此款字体在打印机下也能有极好的显示效果。
技术选型
技术选型上这次有点激进,相比已经成熟很好用的 VitePress 等动静结合的生成工具,我义无反顾地选用了 Next.js 的 App Router,运行环境选用了更快的 Bun。至于其他方面,基本是照着 leerob 的博客进行仿写。所以文章格式不再是常见的 Markdown,而是能插入动态内容的 MDX。对于历史的评论,我还是舍不得丢弃,毕竟有 3000 多条。所以再三对比之下,我选择使用 Artalk 进行存储。有了多说的经历后,我也不敢使用任何第三方的 SaaS 服务存储评论,毕竟数据在自己手里才最安全。
博客以前最喜欢的音乐播放器是 Hermit-X,对应的作者荒野无灯已经神隐很久,获取网易音乐信息的 Meting API 也没持续更新。而 APlayer 更是不知道 DIYgod 什么时候能来“扫墓”,上次 APlayer 的诈尸还只是更新了个 License。所以在新博客环境只有 Aplayer React 这个名为 APlayer 实则是借着其样式用 React 完全重写的播放器可用,其在 RSC 下有点小问题,但估计短时间内作者也没时间修复。(谁叫我是前端菜鸟呢)
MDX 一开始是手动使用 fs
加载,使用 grey-matter
解析 matter
后再用 next-mdx-remote
渲染。但是鉴于自己太菜,很多页面的渲染都需要全量读取博文解析。后面改成了推友推荐的 contentlayer
先渲染静态化,再进行加载。但瞅着 contentlayer
这半死不活的状态,未来大概率还是要弃。😭
Update 2024/04/14
没错,一周后我又来屁颠屁颠地更新博客啦,一周过去后,我的博客也发生了不少变化。首先是搜索终于支持了,使用的是 fuse.js。前文提到的 Contentlayer 也被我废弃,换成了更好用的 Velite。
Update 2024/05/22
今天,我把博客从 Next.js 迁移到了 Astro,重写了部分代码的实现,优化了部分设计。Next.js 版本的博客,内容管理和生成工具使用的是 Velite.js,它的设计很有想法,作者也很有经验。但是对应的 Next.js 与其集成后,却给我带来了很多解决不了的问题。首当其中的就是 Next.js 默认是 SSR,我在 MDX 中生成的内容,部分需要 inline 到 Client 端使用 JS 去动态执行,结果无法实现。其次就是 Astro 先天的在内容管理与编写上下了不少功夫。基于上述理由,我花了两天多一点的时间,就轻松把博客用 Astro 重写了。
重写之后发现 Astro 其实还是比较不成熟,很多东西文档并不清楚,还是要看源码来理清其设计想法。比如 Astro:content
的设计原理和其使用的细节问题,再比如 Astro:asset
这个特定的 import.meta 的使用问题。整体上而言,很多细节问题其实是 Astro 变化太快,对应的文档还没有来得及讲清楚。但是最让我失望的是,Astro 的 SSR 并不完善,它的 inline CSS 和 JS 的实现,其实是靠 Vite 整合 Rollup 提供的能力。所以在 SSR 上,如果你在一个 Astro Component 里面 is:inline
去定义 JS,很有可能会遇到因为模块重用而导致的坑。
另一个我很失望的缺陷就是 Astro 对于 MDX 的支持问题。当前的版本对于 MDX,还是无法实现预渲染来全文输出 RSS。当然,我知道这并非 Astro 自己的问题,主要和 MDX 的复杂和生态息息相关。
迁移到 Astro 的同时,也将博客的 Comment 系统 Artalk 的数据库从 MySQL 切换成了 Postgres,对应的数据库查询相关的代码完全废弃重写,顺带着使用 DrizzleORM 来完成了相关的查询的编写。整体上的使用比想象中愉悦。
希望这是我最后一次重写博客吧。
Update 2024/06/23
截止上次更新,又过去了一个月。这期间博客经历了大大小小的数次优化,比较值得开心的就是在 Astro 4.11.0 的发版记录上榜上有名,修改了一处小 BUG。网站比较值得提及的重大变化有如下四点。
Astro Container API 使用
在一个月前我还在抱怨 Astro RSS 无法做到 MDX 渲染导致只能输出摘要,随后的 Astro 4.9 就更新了 Container API 能自定义渲染某个 Astro 的页面模块。虽然 Container API 的设计更像是为了动态编程方式渲染某个具体的样式模块,包括但不限于 React,Astro,Vue 和 Solid 等。但因为能引入 MDX 的内容,所以就近似实现了输出 MDX 全文的效果。同时,因为 MDX 在渲染时可以替换对应的 Component 实现,所以在 RSS 中还能优化渲染结果。
Astro Container API 前前后后经过数次修改。在最新的 Astro 4.11 中可以说相对稳定下来,并且能在 Vercel 等 Serverless 平台部署不报错。如果有 RSS 全文输出类需求,可以考虑尝试。
Artalk 前端评论模块弃用
Artalk 作为后端评论系统,其实没啥问题,并且有相当不错的安全机制和设计,但是其前端样式怎么定义都不是很好看。早在准备自己实现评论系统的时候,第一个想法就是基于 Artalk 的 Rest API 改成 SSR 的模式加载评论。目前经过数次修改,其评论样式和效果已经和以前使用的 WordPress 基本接近。
在做评论系统的替换的同时,也在遗忘了很久的百度网盘的网站备份目录中找到了多说和 Disqus 的备份。经过修改和迁移,已经成功将多说的评论全部导入进 Artalk。而 Disqus 的备份,受限于欧盟的 GDPR 政策,已经不再提供评论者的 Email 信息,所以只能基于历史评论进行检索对比来确定用户信息进行导入。虽然已经尽了全力,但还是有部分评论被废弃。
Astro Actions 的使用
因为博客的评论模块的替换,导入需要引入大量的 Rest 接口。结合以前有的喜欢按钮等接口,博客一共累计超过 4 个接口。以前都是散乱在 pages 目录里面,这次一并使用了 Astro 4.8 的 Actions 进行统一定义和管理,整体感受如下:
- Actions 和 tRPC 的使用体验基本相似,都是 Typed 的。
- 生成的 actions 可以用 import 的方式在前端的 JS 里面调用,Vite 会打包整合。
- 使用 Actions 可以统一包装错误管理,调用上更加灵活。
Astro CDN 功能的整合和实现
Astro 在 2.2 引入了 CDN Support,其主要目的是对动态构建的 CSS、JS 和图片等内容,可以自定义它们的访问路径和 URL,Astro 会在最终构建的网站结果中予以替换对应的资源路径。但是 Astro 只实现前面说的内容,如果想要在生产环境能实现全套的 CDN 支持,还需要将构建出来的文件上传到对应的 CDN 服务提供商。如,上传到 UPYUN、七牛云、S3 等对象存储。
在这里我选用了用了近 10 年之久的 UPYUN,第一版是使用 0.25 引入的 Astro Integration API 来进行实现。Astro Integration API 是一个非常经典的观察者模式的设计,它对应了 Astro 构建的几个不同阶段,允许你定义不同阶段的特殊勾子,Astro 会在对应阶段调用你的自定义逻辑。对于我而言,我只需要在 'astro:build:done'
阶段读取所有想要上传的目录,进行上传即可。
这期间对上传逻辑进行了多次重构,第一版使用 UPYUN Node.js SDK,但是这个 SDK 年久失修,使用的还是有安全问题的 axios 版本。对于已经习惯上 fetch 一把梭的我,有点生理不适。考虑到很多云存储都支持了 S3 协议,并且使用 S3 协议能更灵活地切换到不同的存储服务。在第二版使用了 Client S3 来进行实现,这里面遇到的唯一问题就是 ContentType 需要显式设置,而原先的 UPYUN Rest API 能根据文件名自动设置。
第三版使用了基友 Tison 安利的 Apache OpenDAL™ 进行了重构,还是走的 S3 协议。Apache OpenDAL™ 是一个使用 Rust 编写的统一云存储层抽象接口,整体的代码质量和实现都很不错。但是 Node.js 部分的 Binding 使用 napi-rs 实现,对应的文档写得比较抽象,我是看 Rust 部分的文档反向推导 Node.js binding 该如何使用,期待文档的进一步完善。同时因为一些已知问题,暂时还无法直接在生产环境使用。
Update 2024/10/16
距离上次更新又过去了 4 个月,这期间看了不少书,博文倒是没写几篇。这期间博客的源码倒是没少折腾,但基本都是细枝末节的修改,如例行的升级依赖啥的,比较需要注意的更新有如下内容。
补完全部文章的插图
博客的文章书写时间已经有 15 年的跨度,这期间文章的很多插图,要么尺寸过小,要么丢失。在 3 年前切换回 WordPress 时进行了统一的梳理,将所有图片去除,转成了 Markdown 格式,但并未补全全部插图。这次借着切换为 Astro 的机会,将博客的文章都配上了精美的插图,并设置了对应的封面图片。(何等可怕的工作量)
支持动态 OG 图片
对于 OG 图片的支持,历时 3 个月才予以实现,最早的版本为选取文章的封面,后面改为使用 @vercel/og 生成。博客切换为 Astro 时一并放弃了 React Server Component 方案,对应的 OG 生成暂时搁置。在仔细学习了基于 napi 的 @napi-rs/canvas
后,本博客的 OG 图片使用 Canvas 绘制,并在构建的时候静态生成放于对象存储上来减少字体加载、渲染等耗时。目前 OG 的样式经过多次微调,暂时满意。
使用 Zeabur Serverless Function 部署
Zeabur 因为有中国区,考虑网站面向的人群,我实在是无法割舍。之前因为使用 Astro Container API,对应的包构建为 Lambda 时会有依赖问题,所以一直使用 Docker 方式在 Zeabur 部署。经过和 Zeabur 的小伙伴合作,同时完成了 Zeabur 对 astro/env
的支持后,现在网站已经不再使用 Docker 方式,转而使用 Zeabur 提供的 Serverless 的方式运行。
其他微调
- 文章页展示标签:标签更像是一个动态灵活的文章分类,之前设计新博客的时候有所遗漏,现在已经补上。
- 搜索结果支持分页:之前对 fuse.js 的理解不够深刻,经过仔细摸索,发现可以基于其结果做二次分页,于是不再限制搜索条数进行一页展示。
- 自定义鼠标样式:添加了箭头、手指的鼠标样式,并支持视网膜屏幕。
- 文章支持多别名:对于一篇文章,除了固定地址外,目前还支持了短链接别名。比如 https://yufan.me/papapa
写此文章前,本有一肚子关于清明三天折腾的坎坷想要倾诉。真正写下来的时候,却又没多少。一来是年龄的增长,很多东西不再像以前那么过激。二来,大部分问题基本解决。数数上次更新博客的时间,已经不知道是猴年马月。希望自己在未来的年月里,能笔耕不辍,多记录一点自己的生活。
至于博客载体,那都是浮云啦。
博客版面确实比较新颖,也有点与众不同,应该有成就感吧!
以前我也喜欢折腾,甚至也想写一个特立独行的前端。现在越来越喜欢简洁,觉得用成熟的方案不尝也是一种解脱,所以就一直沿用 WordPress 方案了。
你好,感谢留言,我发现你在后台有多条相同的留言。其实我的博客默认情况下,留言都会进入审核,审核通过后才会予以展示。所以不好意思,让你以为出了故障,进行了多次评论。
没关系。之前貌似一直一直没有提交成功的提示,以为没提交,所以多点了几下。
也是会玩!
以前更流行的说法叫做,爱折腾。不过年纪大了,也懒得折腾。
Hi, 可以出一个“artalk Rest API 改成 SSR 的模式加载评论”的教程吗?最近也在用Asrto + Wordpress,想法也和你一样,评论也想跟Wordpress 样式一样,感谢感谢。
我的博客在我的 GitHub 上面开源,你可以直接看看源码实现?
从wordpress迁移到这个系统有啥好用工具吗,一个个整理好麻烦
这块我当时有手动写了一些迁移工具,按照我的想法去解析迁移对应的数据格式为 Markdown:相关代码。
鉴于对应的数据解析迁移工具很简单,我觉得你可以用类似的方式实现。
Astro 竟然支持动态评论?
有没有一种可能,是我在 Astro 上增加了动态评论?
太狠了,从nextjs切换到astrojs是为什么呢?能不能分享下这样做法的目的?为了ssg?
切换到 Astro 是因为其对 MDX 支持得更好,我不需要花什么心思在 MDX 解析等额外工作上。另,你的这条评论位置跑到了留言板块,我给你挪回了我认为正确的地方。
22 年和 23 年好像更新比较少
设计的很不错
笔耕着实不错
你就没后悔,自己写个就在心里爽。
嘿嘿嘿,被你发现了。确实,很爽。
这个博客还是相当不错地