千万不要自己做博客网站,否则你会被逼成命令行大师
序
很久以前我在 github Page 上搭了一个静态的个人网站,用的现成的Hexo框架,Wikitten主题,写写配置文件,一个小时就捣腾完了。
但是用一段时间之后也发现了很多问题,按问题严重性降序排列如下:
- 丑,Wikitten已经是矮子里拔将军了,但还是不能忍。而且封装好的ejs 主题,要改的成本不小。
- Github Page 只支持静态网站,每次更新要重新生成所有网页然后上传。很不环保,很不经济。
- 静态网站生成器无法托管图片,图片全在新浪免费图床上,朝不保夕。
- 元数据标识(标题、时间)用YAML 表示,写错了会生成失败,写新帖子没那么方便了。
- 搜索要重新生成所有文件的元数据 JSON db,还要传到客户端。这很不环保(看一个贴子要加载所有帖子的元数据),关键是浪费流量(db size 2Mb+),严重劣化首屏加载时间。
- 移动端效果不佳,目录展开会挤压阅读区域。
正好研零的暑假有不少时间挥霍,实习跑路之前也写了5000+ 行前端代码,就想着重构一下个人网站。
我的目标如下:
- 要优雅,所以我选择用 tailwind CSS 手写样式以达到最高的自由度。
- 要能动态地生成静态网页(?意思就是灵活性和速度我都要。既能免维护,不用每次更新手动生成整个网页,又能保持静态网页的高性能),利用Nextjs ISG 的特性加一行
就能搞定。revalidate: 1 - 自给自足,自己管理本地图片,能上传、改大小、压缩。
- 无需YAML,利用文件本身的元数据来标识网页(写啥文本都能导入)
迁移老系统
在2021 年,我决定不再每天写一篇日记,而是每天写,每个月生成一篇。
现在我要把这两种格式统一,怎么做呢?
一提到办公自动化就想到Python,但其实shell 比Python 又快又好:
for dic in `ls -d */`; do # -d 列出所有文件夹📂:1,2,3,4…… cd ${dic%%/*}; # 进入,我这里移除了文件夹的尾标/,你也可以不移除. # 这取决于你shell 的智能程度,我的zsh 甚至可以不写 cd for file in `ls -tr *.md`; do # 对所有文件,按创建时间顺序📃做: cat $file >> `stat -f "%Sc" -t "%Y-%m"`.md; # 所有文件依次排泄进 2022-08.md 里 done sed -i '' 's/^# .*//' 2022-08.md # 删除所有一级标题 mv 2022-08.md ../${file:0 :7}.md # 命名成当时的时间,上一个file 是2020-08-06.md 这种 cd ..; rm -rf $dic; # 删除所有文件夹 done
完蛋了!所有文件的元数据都乱了。
Question:把老文件的内容导入到新文件,那么这个文件的创建日期是什么时候呢?
所以,现在所有日记的日期都乱了,2020年和2022年的日记都在同一天被创建了出来。。。
别急,我来依据文件的标题把日期改回来:
for file in $(find ./ -name "*.md"); do ## 找到所有markdown 文件 setfile -d ${file:0-5:2}"/01/"${file:0-10:4} $file ## 把日期按照文件标题改回来 done
(后面rsync 同步的时候又乱了,现在我知道为什么要用YAML了,,,)
新浪图床本地化
首先是下载所有图床照片:
把不能显示的ima tag 换成markdown 模式:
sed -i '' -e 's/<img src="\(.*\)" alt.*/![](\1)/'p `find ./ -name "*.md"`
实际上这一步是脱裤子放屁,给网站的markdwon parser加一个inner HTML 插件就行,但当时以为这最省事儿,结果又酿成大祸。。。
完蛋了,所有照片都被重复了6次
刚学会sed 行处理又要学awk 列处理了,,,
awk '!/.*\].*\(.*jp[e]g.*/ || !x[$0]++ ' $file > tmp && mv -f tmp $file
去重按理说很简单,有专门的uniq。但是它是无脑去重,所有重复的行都被去除了,包括空行和你需要重复的行。
这条sed 命令首先正则匹配了一个有jpg或jpeg的行,然后创建一个 map name x,用当前行$0作为 map 的 key,到 map 中查找相应的 value,如果没找到,则整个表达式的值为真,可以执行之后的语句(++);
如果找到了,则表达式的值为假,跳过这一行。
++操作会先把对应的 value 设成 0,然后再自增成 1,下次再遇到重复的行的时候,对应的 key 就能找到一个非 0 的 value 了。
(网上抄的,有一个awk 速查表大全,希望以后用不到)
图片使用逻辑
我使用Typora 写作,图片拖过来就能自动触发一个命令。问题是,这个命令是什么?
Typora 给的官方解释:
You could config a custom command to upload images, using tools that is not listed in above options, or even write your own tools / scripts. Typora will append all images that needs to be uploaded after the custom command you filled.
Then, Typora will fetch image urls from the last N lines of the standard output of your custom command. (N is the number of images to upload).
For example, if you write a tool
, then you can input
upload-image.shin the command filed. Typora will call
[some path]/upload-image.shto upload two images located in
[some path]/upload-image.sh "image-path-1" "image-path-2"and
image-path-1. Then the command may return something like:
image-path-2Upload Success: http://remote-image-1.png http://remote-image-2.png
其实很简单,坑在于它只接受url式的输出 file://……,而不是~/ 路径。
我的上传脚本:
for var in "$@"; do convert $var -resize 1640x1680 $var /Applications/ImageOptim.app/Contents/MacOS/ImageOptim "$var" cp "$var" http://74.48.115.131:5555/.pic/`basename $var` done echo "Upload Success:" for var in "$@"; do echo http://74.48.115.131:5555/.pic/`basename $var` done
UNIX 真是把功能原子化做到了极致,连basename 这么这么方便的东西都有,而node简直草台,fs 连按时间顺序列出文件都没有。
完了,nextjs 没有动态 public 图片的功能
所有pubic 下的文件必须是静态的,不能动态添加。nextjs 为了防止恶意用户插入代码,在服务开始时为每个文件都打上了hash 前缀,给cdn 带来无数麻烦,网上的解决办法都tldr,直接来一个:
python3 -m http.server 5555
重新开一个服务来server 图片。
然后
.replace( new RegExp( "(file://)?http://74.48.115.131:5555/.pic/", "gm" ), "http://124.220.179.145:5555/.pic/" )
这只是开始
你看,前面忙了这么多其实都还没开始开发呢呢。。。
开发过程很琐碎,没啥可说的,直接看结果吧:
为什么没有域名?因为域名要备案,网站内容有被查封的风险。