部署同步更新博客文章FrontMatter

部署同步更新博客文章FrontMatter

Salt 练气期

前情提要

之前在某篇文章中提到了 Qexo 的一项优点:右侧支持自定义 Markdown 的front-matter,同时默认自动添加updated属性,实现只要我们更新文章,发布时间date属性值不变,updated属性会变成当前时间,但是生成的时间格式为ISO 8601标准,同时带有时区+8:00后缀(如:2024-08-06T01:44:42.550+08:00),导致在文章中显示的日期是 UTC+0 的时间,即与当地时间相差 8 小时。

本文主要解决两个问题:

  1. 更改日期生成格式。
  2. 保证expires的值与updated一致,expires是 Redefine 主题自带属性,本身指最后一次更新时间,定义上与updated是相同的。

思路

笔者在这里绕了不少弯路,这件事也提醒我规划预期的重要性(当然还有自身的技术力不足)。

正确的解法

幸好 Qexo 开源,为什么一开始没想到呢?可恶!

Qexo 源码开源,可以直接通过修改源码达到我们想要的功能。

1
2
3
4
5
6
# 拉取自己仓库的分支
git clone <your-repo-url>
# 进入分支源码目录
cd <your-repo-name-folder>
# 使用Vscode打开项目文件夹
code .

需求一:时间格式化

由于创建文章后发布时间是不变的,因此后续不会有其它方法处理该属性。而更新时间需要每次打开文件就修改。

  1. 修改创建时间

    1. 进入hexoweb目录,找到function.py,修改get_post_details函数
    2. 将时间格式化方式由isoformat()更改为strftime('%Y-%m-%dT%H:%M')
  2. 修改发布时间

    1. 进入templates/home目录,里面的edit.htmledit_page.html中涉及到关键字updated,其中涉及到处理时间的代码为content=getRFC3339()

    2. 进入templates/includes目录,查询关键字getRFC3339(),更改函数为:

      1
      2
      3
      4
      5
      6
      7
      function getRFC3339() {
      let date = new Date(+new Date() + 8 * 3600 * 1000);
      let iso = date.toISOString();
      let rfc = iso.replace("Z", "+08:00");
      // 格式化为 YYYY-MM-DDTHH:MM
      let rfc = iso.replace("Z", "").slice(0, 16); // 去掉 "Z" 并截取到分钟
      return rfc;

需求二:绑定 expires 属性与 updated 属性

由于updated是 Qexo 编辑文章时自带的属性,因此源码里面一定有该字段。

涉及页面相关的源码文件有:edit.html、edit_page.html、new_page.html、new.html,前者是对之前的文章进行更新,后者是创建新的文章

注意:只有过期日期格式为 %Y-%m-%d %H:%M:%S时,才会生效

找到 templates/home/edit.html,找到showSidebar(first = false)函数,修改如下:

1
2
3
4
5
6
7
8
# 更改前
if (OrgSidebar[i]["search"] === "updated" || OrgSidebar[i]["search"] === "lastmod")
# 更改后,发布日期、更新日期、过期时间均需格式化
if(OrgSidebar[i]["search"] ==="date"){
content= front.date.replace('T', ' ').slice(0, 19);
}else if (OrgSidebar[i]["search"] === "updated" || OrgSidebar[i]["search"] === "lastmod" || OrgSidebar[i]["search"] === "expires") {
content = getRFC3339();
}

待自动重新部署后,在 Qexo 编辑界面新建expires属性即可。

别忘了 git 提交修改。

失败的尝试

思路 1:不改变 Markdown 文档本身,改变 Hexo 读取原始文档后的data数据,修改updatedexpires属性,最终实现渲染后的文章显示正确。

原因剖析

此思路在于脚本未能正确处理时间,由于dateupdatedexpires涉及到moment类和datetime之前的转化处理,脚本一直执行报错,故放弃。

思路 2:直接更改源文件,读取 Markdown 文档本身,解析front-matter,然后修改updatedexpires属性。

原因剖析

此思路对于本地部署可行,但对于部署在 Github 仓库中的文件,Vercel 进行自动化部署时并不会更改仓库的原始文件, 因此无效。

折中办法:使用 Vercel 配合 Github Actions,当 Vercel 触发部署时,自动运行 Actions,Actions 再调用脚本,从而修改原始文件。

此处贴上思路 2 的源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
const fs = require("fs");
const moment = require("moment-timezone"); // 引入 Moment.js 和 moment-timezone

hexo.extend.filter.register("before_generate", async function () {
const posts = await hexo.model("Post").find({});

// 遍历所有文章
posts.data.forEach((post) => {
const filePath = post.full_source; // 直接使用完整的 Markdown 文件路径

// 检查文件是否存在
if (!fs.existsSync(filePath)) {
console.warn(`文件不存在: ${filePath}`);
return; // 如果文件不存在,跳过此文章
}

// 读取文件的最后修改时间
fs.stat(filePath, (err, stats) => {
if (err) {
console.error(`获取文件 ${filePath} 的状态时出错:`, err);
return;
}

// 获取文件的最后修改时间并转换为东八区时间
const fileModifiedTime = new Date(stats.mtime); // 文件修改时间
const utc8Date = moment(fileModifiedTime).tz("Asia/Shanghai"); // 转换为东八区时间

// 使用 Moment.js 解析 updated 时间
const updatedMoment = post.updated
? moment(post.updated).tz("Asia/Shanghai")
: moment(0); // 创建 Moment 对象并设置为东八区

// 如果 updated 比文件的修改时间早,则更新 updated
if (updatedMoment.isBefore(utc8Date)) {
const formattedDate = utc8Date.format("YYYY-MM-DDTHH:mm:ss.SSSSSS"); // 格式化为东八区时间
post.updated = formattedDate; // 使用 Moment 格式更新 updated
}
post.expires = post.updated;
console.log("date:", post.date);
console.log("updated:", post.updated);
console.log("expires:", post.expires);

// 保存更改
post.save();
});
});
});
  • 标题: 部署同步更新博客文章FrontMatter
  • 作者: Salt
  • 创建于 : 2024-08-06 01:44:43
  • 更新于 : 2024-10-26 21:53:10
  • 链接: https://blog.isoland.top/posts/7e560f53/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论
目录
部署同步更新博客文章FrontMatter