Hugo | 以正确姿势自动添加文章最后更新时间

3054字

之前在Hugo | 增加 Google Search Console 及其他修改里提到了设置文章最后修改时间为Git时间出错,纠结了一天,说实话我之前没有想过这是一件这么复杂的事情。

出现的问题

操作:config.yamlfrontmatter字段写明lastmod: [:"fileModTime", "lastmod"],并使用Vercel部署网站

结果:本地端进行hugo server,文章末尾显示CST时区,并显示时间为md文件最后修改时间。但部署后,末尾显示时区变为UCT,并且所有页面的更新时间全部变为最后构建时间。

摸一整天鱼

首先翻到一篇Issue:开启了 git info 但 Travis-CI 自动构建的文章修改日期始终为最新,其中提到了两个结论:

  1. 多半不是Hugo出了问题,而是部署阶段出问题了
  2. 如果使用Github Action的话,需要去掉checkout操作,否则hugo会找不到git info变量

同时十五也提到了可能是服务器部署的问题:

我自己的推测是服务器部署相当于在服务器的部署仓库执行强制推送,所以是拿不到源仓库的commit时间的;另外因为是服务器部署所以时区是服务器的时区

然后我去研究了一下同样采用vercel进行部署的网站,发现Sitemap.xml中显示的Lastmod时区和我的Blog同样,都显示+0:00的UTC时间。而其他不使用Vercel部署的网站正常显示+8:00。

……这大概率就是Vercel出问题了嘛

跟着这个思路搜到Vercel 设置时区,确定了我的怀疑,文章中提到:

在 Vercel 里的项目中,所有的时区都是默认的 UTC 时间

同时提到可以通过设置Vercel的环境变量为TZ=Asia/Shanghai来解决,但实际操作当中,设置TZ时Vercel提示The name of your Environment Variable is reserved. Please choose another name.,显然这是个被保留的环境变量,因此无法被修改。

为了确证是Vercel导致了读取更新时间出错,我开始做实验:

实验 结果 结论
在配置文件中删除frontmatter变量 最新更新时间显示为文章Lastmod设置中手动写下的时间,并在最后显示+8:00,sitemap显示+8:00 确定是指定Hugo读取时间戳导致显示混乱,直接写死时间不会出问题
在本地生成Public文件夹,并将渲染结果推到Gtihub Page,观察结果 时区显示为CST时间,但仍然同时刷新所有页面的最新更新时间 确定是Vercel的服务器时间导致时区混乱
变化配置文件中Frontmatter参数的写法,加入:git等等 没有区别,显示的时间为最后构建时间,同时刷新所有页面的最新更新时间,sitemap显示+0:00 不是参数的设置导致了时间戳的混乱

Github Action

总之锅到这里就是分完了,接下来在想怎么解决,最后决定试用一下Github Action来自动部署Blog。一方面是由于强烈的好奇心(我之前全都失败了!我不服气!),另一方面是觉得……都研究了这么长时间了,总得做出来看看。

整个流程采用了之前Issue中的提供的Workflow,流程参考了Suica之前写的自动部署笔记,这次全过程都有十五好心帮忙,所以还挺无痛,十五人真好,谢谢!

需要的是注意以下三点:

  1. 用于部署的仓库必须以name.github.io命名,否则需要修改配置。这是由于如果仓库不以此命名,Github Page的网址会变为name.github.io/repo_name/,由于配置文件中设置的都是一级目录,这会导致网站读不出某些文件,比如css样式(本地正常)
  2. 如果源代码仓库的分支不是Workflow中预设的Master,那么需要修改相关命令,例如:git clone --branch=master修改为git clone --branch=main,否则会遇到git clone报错。
  3. 以这个Workflow运行,源代码仓库必须是公开状态,否则git clone会报错找不到仓库。如果需要clone私有仓库,需要把clone命令换成git clone --branch=main --quiet https://$SECRET@github.com/$SOURCE_REPO site

最后的Workflow为:

name: Github-Pages

# 在 master 分支更新时触发构建
on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-18.04
    env:
      TZ: Asia/Shanghai
      SOURCE_REPO: ""  # 博客源码仓库
      TARGET_REPO: ""  # 博客部署仓库
      TARGET_BRANCH: "gh-pages"  # 博客部署的分支名
      SECRET: ${{ secrets.PERSONAL_TOKEN }}
    steps:
      # 配置 git,避免一些莫名其妙的错误
      - name: Git Configuration
        run: |
          git config --global core.quotePath false
          git config --global core.autocrlf false
          git config --global core.safecrlf true
          git config --global core.ignorecase false
          git config --global user.name "github-actions[bot]"
          git config --global user.email "github-actions[bot]@users.noreply.github.com"
      # 拉取源码
      - name: Clone Repository
        run:
          git clone --branch=main --quiet https://$SECRET@github.com/$SOURCE_REPO site

      # 安装 hugo (v0.88.1)
      - name: Setup Hugo
        run:
          wget -q -O hugo.deb https://github.com/gohugoio/hugo/releases/download/v0.88.1/hugo_extended_0.88.1_Linux-64bit.deb && sudo dpkg -i hugo.deb && hugo version

      # 构建网站
      - name: Build
        run:
          cd site && hugo --gc --minify --cleanDestinationDir

      # 部署至 GitHub Pages
      - name: Deploy
        run: |
          cd site/public && git init
          git add .
          git commit -m "Update Blog By GitHub Actions With Build ${GITHUB_RUN_NUMBER}"
          git push --force --quiet "https://$SECRET@github.com/$TARGET_REPO" master:$TARGET_BRANCH

等等,还有Git

部署了Github Action后成效显著,文章最近更新时间开始显示为CST时间了——但是,等等,别高兴得太早,它仍然无法读取时间戳——无论是文件修改时间还是git时间,文章末尾仍然显示最新构建时间——并且更新全站页面。

崩溃五分钟后理一下思路:本地预览仍然是正确的,说明Hugo部分没有问题,不使用Vercel部署后时区也显示正确了,说明部署服务器不再影响时区读取,那么很有可能这个全站时间修改是由于它们之外的奇幻原因导致的,而考虑到整个部署流程,猜测嫌疑人很可能是git。

于是以这个思路进行搜索,找到几个案例,比如Netlify构建Hugo博客导致文章修改时间失效中提到可以通过修改构建命令解决,而GIT 获取文件最初创建及最新修改日期中提到了可以通过git命令获取文件最新修改时间,给 Gataby 文章添加修改日期则明确说道

每次重新 git clone 之后所有文件最近更新时间 mtime 都变成克隆的时刻,这是 git 的一个 bug

最后我找到一篇从 Git 提交历史中「恢复」文件修改时间,提到:

Git 不保存文件的修改时间

这篇文章的解决办法是使用commit时间来近似作为文章修改时间,换到Hugo上显然就是":git",再在配置中加上enableGitInfo: true后(很难想象我花了二十分钟才意识到需要加上这个),世界恢复了正常的秩序。

可以下结论了

结论: 在这场精密的错误面前,每位参与了构建部署的朋友都有自己的责任,首先Hugo不设置GitInfo则无法正确读取git时间,其次Vercel部署的服务器时间影响了时区的显示,最后借助于Hugo的规则,git成为了无法读取正确时间,还试图拖所有页面下水的第三位犯人。

于是最终的解决办法是:

  1. 换用Github Action进行自动部署,或者使用可以设置服务器时区的自动部署服务

  2. 在config.yaml中写明

    frontmatter:
        lastmod: [":git", "lastmod"]
    

一些余波

Github Page加速

显然Github Page太慢了……使用了Vercel进行加速,新建一个project,导入部署仓库,并且一路按下一步就可以完成(不必选择Hugo框架,FRAMEWORK PRESET可以选Other,等到Vercel构建成功并分配二级域名后,修改网址DNS设置为CNAME,指向Vercel分配的DNS地址。

……当然,这和昨天发现的Google Search Console读取TXT值错误冲突了,不过管他呢,反正Google Search Console也没有读取我的sitemap,这是我的报复(不是。

Hugo时区变量

Zero提到了Hugo时区设置的更新,值得在这里记一笔。

hugo 的时区问题在上个月的 0.87.0 起已经得到了优雅的解决

现在可以在站点的 config.{yaml|toml|json} 中添加上 timeZone 变量

具体的写法为:TimeZone: Asia/Shanghai

另一个Workflow

Stack主题 + GitHub Action 这篇文章里提到了可以通过自动缓存的办法来加快部署速度,同时解决了更新时间的问题:原因是actions/checkout@v2 默认不会clone历史信息,需要加上fetch-depth: 0以clone完整的历史信息。