修复 Vercel/Github Actions 部署 hexo 导致文章的更新时间错误
修复 Vercel/Github Actions 部署 hexo 导致文章的更新时间错误
在使用 Vercel
或 Github Actions
自动化部署 hexo 博客时会发现所有文章的更新时间都变成了此次提交修改的时间,但实际上这些文章是没有任何修改的。
这是因为 git
在推送更新的时候不会保存文件的访问时间、修改时间等元信息。
Git SCM Wiki 中的解释
Why isn't Git preserving modification time on files?
Modification time on files is a feature that affects build tools. Most build tools compare the timestamp of the source(s) with the timestamp of the derived file(s). If the source is newer, then a rebuild takes place, otherwise nothing happens. This speeds up the build process a lot.
...
Git sets the current time as the timestamp on every file it modifies, but only those. The other files are left untouched, which means build tools will be able to depend on modification time and rebuild properly. If build rules change, that can cause a failure anyway, but that is a far less common problem than accidentally not rebuilding.
所以每次使用 git clone
下载的项目的文件元数据都是当前系统时间,而不是项目的创建时间。
在 Hexo
中的文章默认是通过使用 文件的最后修改时间 作为文章的更新时间,只有在 font-matter
中指定了 updated
才会使用 updated
的值作为文章的更新时间,所以才会出现 CI 构建后所有文章的更新时间都变成了此次构建的时间,因为推送上去的文件的元信息不会保存。
方法一:使用 updated 属性
在所有文章的 front-matter
中添加 updated: 更新时间
项
1 | title: article title |
以后需要修改文件的更新时间时,只需要修改 updated
的值即可,但是这样做的话就需要手动维护所有文章的更新时间,不太方便。
使用 PowerShell 脚本自动更新所有文章的 updated 属性
在 @yiyun 的博客中,他使用了一个 PowerShell 脚本来自动更新所有文章的 updated
属性。
在 Hexo 博客根目录中创建 update.ps1
文件
update.ps1
1 |
|
出处:yiyun’s Blog - 使用 PowerShell 一键更新 Hexo 文章的 updated
修改 font-matter 模板
默认的 font-matter
模板中不包括 updated
属性,所以需要修改模板使以后新建的文章也包含 updated
属性。
打开 Hexo
博客根目录下的 /scaffolds/post.md
文件,添加 updated
属性
1 | title: {{ title }} |
以后新建的文章就会自动包含 updated
属性了,其默认值为文章的创建时间。
方法二:修改 update_option
updated_option
控制了当 Front Matter 中没有指定 updated
时,updated
如何取值:
mtime
: 使用文件的最后修改时间。这是从 Hexo 3.0.0 开始的默认行为。date
: 使用date
作为updated
的值。可被用于 Git 工作流之中,因为使用 Git 管理站点时,文件的最后修改日期常常会发生改变empty
: 直接删除updated
。使用这一选项可能会导致大部分主题和插件无法正常工作。
use_date_for_updated
选项已经被废弃,将会在下个重大版本发布时去除。请改为使用 updated_option: 'date'
。
From: hexo.io - 配置
在 Hexo 博客根目录下的 _config.yml
文件中修改 updated_option
的值为 date
即可。
1 | # 文章的更新时间 |
然而,这样做会导致所有文章默认的 updated
属性都变成了文章的创建时间,而不是修改时间,治标不治本。
方法三:使用 Github Action 部署到 Vercel
本站使用的就是这种方法,由于本站使用的是 Vercel 作为托管平台,每次推送到仓库后,Vercel 会自动构建并部署。
我们需要在 Vercel 构建之前使文件的最后修改时间与文章的更新时间一致,这样 Vercel 构建后的文件的最后修改时间才会与文章的更新时间一致。
因为 Vercel 绑定仓库后,每次推送会自动进行部署,不能修改 Vercel 的构建流程,所以我们需要在 Github 仓库中添加 Github Action。
原理
在 hexo-theme-next issue # 893 中提到了这个问题,@sli1989 提出了一个解决方案:
hi, the updated time with CI deployment can be fixed using this. please check Continuous Integration configurations carefully.
1 | # Restore last modified time |
该条命令会将文件的最后修改时间修改为 Git 仓库中文件的最后提交时间,即文章的更新时间。
同样使用 find
命令也可以实现这个功能:
1 | find source/_posts -name '*.md' | while read file; do touch -d "$(git log -1 --format="@%ct" "$file")" "$file"; done |
准备工作
首先,将 Vercel 项目
与 Github 仓库
的绑定关系解除,因为我们将要在 Github Action 中手动部署到 Vercel 中。
不想解除仓库绑定?查看关闭自动部署教程
在 Git Configuration | Vercel Docs 中提到:
git.deploymentEnabled
Type: Object
of key branch identifier String
and value Boolean
, or Boolean
.
Specify the branches that will not trigger an auto-deployment when committing to them. Any non specified branch is true
by default.
Property’s default value is true
. In case you want to turn auto-deployments off for every branch, property value must be set to false
.
1 | { |
所以我们可以在博客根目录中创建一个 vercel.json
文件,添加以下内容:
1 | { |
这样 Vercel 就不会在 Github 仓库更新时自动部署了。
在 Github Action 中需要使用以下两个环境变量、一个秘钥:
VERCEL_ORG_ID
VERCEL_PROJECT_ID
VERCEL_TOKEN
获取 Vercel Access Token
我们需要在 Vercel 中获取一段 Vercel Access Token 用于 Github Action 部署到 Vercel。快速前往 Access Token 页面
获取 VERCEL_ORG_ID 和 VERCEL_PROJECT_ID
在本地安装 Vercel CLI 后,使用 vercel login
登录 Vercel
1 | # npm |
在博客根目录下执行 vercel link
,创建一个 Vercel 项目,此操作会在博客根目录下生成一个 .vercel
文件夹,.vercel/project.json
里面包含了 VERCEL_ORG_ID
和 VERCEL_PROJECT_ID
。
在 Github 仓库中添加 secrets
在 Github 仓库中的 Settings
-> Secrets and Variables
-> Actions
中添加以下秘钥和环境变量:
VERCEL_TOKEN
VERCEL_ORG_ID
VERCEL_PROJECT_ID
创建 Github Action
在 Github 仓库中创建一个名为 .github/workflows/deploy.yml
的文件,添加以下内容:
1 | name: Deploy Blog to Vercel Production Deployment |
注意
如果 github actions
中使用 actions/checkout@v2
,请设定它的参数 fetch-depth: 0
,因为 0
表示获取所有分支和标签的所有历史记录。默认值为 1
推送代码到 Github
在本地执行 git push
推送代码到 Github,Github Action 会自动部署到 Vercel。
方法三(Github Page版):使用 Github Action 部署到 Github Page
如果你的博客源文件托管在 Github 上,且使用 Github Action 部署到 Github Page,那么可以在你的部署 Action 中添加以下代码:
1 | - name: Restore file modification time 🕒 |
其余步骤与 方法三 -> 创建 Github Action
中一致,只是部署方式不同。
例子
以下是一个完整的 Github Action 部署到 gh-pages 分支的例子:
1 | name: deploy blog to github |
不要忘了在 secrets 中添加 DEPLOY_TOKEN
秘钥
参考链接
除了文中直接引用的链接出处,还有以下作为参考:
使用 GitHub Actions and Releases 将您的站点部署到 Vercel
How can I use GitHub Actions with Vercel? - Vercel Docs
examples/production.yaml at main - vercel/examples
头图/封面素材更改于 Ray Hennessy on Unsplash