Featured image of post Hugo Theme Stack 针对中国大陆部署优化不完全指南

Hugo Theme Stack 针对中国大陆部署优化不完全指南

哪里不爽调哪里。

我最近换到了hugo-theme-stack,However,主题作者似乎并未考虑到中国大陆一些特殊的情况1。我对其进行了一些调整,以适应我的需求。

部署hugo-theme-stack

Github Pages 实在太慢,且鉴于 Vercel 已经被「特殊照顾」过,为了稳定,我还是选择了其他的托管服务。

我采用 Github Actions 部署到 Azure Static Web App(Azure SWA),这个服务在中国大陆大部分会使用香港节点,访问速度还不错。我只需要按照提示点几下,这套服务就会自动帮我在仓库里生成 Actions 所需的 yaml 文件。随后删除作者原有的deploy.yml就大功告成了——只需写完文章然后 Push 到仓库,Oryx2 就会自动构建我的博客并发布。

不得不吐槽免费版的 SWA 边缘计算要求必须使用 Oryx,而 Oryx 的生成速度又比原生的 Actions 慢多了3,实在是有些浪费性能。

还有 Azure 一言难尽的面板,请坐和放宽……

Azure SWA 面板

优化hugo-theme-stack

换用国内前端资源 CDN

hugo-theme-stack前端资源大量采用了 JSDelivr,然而:

JSDelivr现状

可以看到,有些地方默认的 JSDelivr 前端资源甚至完全不可用。因此,更换这些前端资源成了当务之急。

由于我们使用的是模组形式加载hugo-theme-stack,根本就没有themes文件夹。Hugo 允许主题文件的覆盖4,只需要将需要覆盖的文件放在 working directory 即可。例如:我想修改原本在./themes/layouts/partials/head/下的custom.html,只需创建./layouts/partials/head/custom.html然后编辑,这个文件可以从原主题仓库复制。

hugo-theme-stack将通过外部加载的前端资源放在了./themes/data/external.yaml,我们在博客目录下创建./data/external.yaml

 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
Vibrant:
    - src: 
      type: script

PhotoSwipe:
    - src: https://lib.baomitu.com/photoswipe/4.1.3/photoswipe.min.js
      type: script
      defer: true

    - src: https://lib.baomitu.com/photoswipe/4.1.3/photoswipe-ui-default.min.js
      type: script
      defer: true

    - src: https://lib.baomitu.com/photoswipe/4.1.3/default-skin/default-skin.min.css
      type: style

    - src: https://lib.baomitu.com/photoswipe/4.1.3/photoswipe.min.css
      type: style

KaTeX:
    - src: https://lib.baomitu.com/KaTeX/0.15.6/katex.min.css
      type: style

    - src: https://lib.baomitu.com/KaTeX/0.15.6/katex.min.js
      type: script
      defer: true

    - src: https://lib.baomitu.com/KaTeX/0.15.6/contrib/auto-render.min.js
      type: script
      defer: true

Cactus:
    - src: https://latest.cactus.chat/cactus.js
      integrity:
      type: script
    - src: https://latest.cactus.chat/style.css
      integrity:
      type: style

由于 Vibrant.js 不在lib.baomitu.com上,所以需要自行解决托管问题。

原项目里这些前端资源还有个integrity键值用来校验资源完整性,经测试似乎只有 JSDelivr 支持这个特性,这里引用的 360 前端资源库保留这个键值会报错,于是一删了之。实际上有了 https 加持,除非遇到国家级网络攻击这种极端的情况,我们也基本上用不到这个特性。

我还修改了./layouts/partials/helper/external.html,直接去掉了所有的 Integrity:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
{{- $List := index .Context.Site.Data.external .Namespace -}}
{{- with $List -}}
    {{- range . -}}
        {{- if eq .type "script" -}}
            <script 
                src="{{ .src }}"
                {{ if .defer }}defer{{ end }}
                >
            </script>
        {{- else if eq .type "style" -}}
            <link 
                rel="stylesheet" 
                href="{{ .src }}"
            >
        {{- else -}}
            {{- errorf "Error: unknown external resource type: %s" .type -}}
        {{- end -}}
    {{- end -}}
{{- else -}}
    {{- errorf "Error: external resource '%s' is not found" .Namespace -}}
{{- end -}}

评论系统也引用了 JSDelivr,因此也要更换。我采用的评论系统是 Twikoo,创建./layouts/partials/comments/provider/twikoo.html,修改文件第一行:

1
<script src="//lib.baomitu.com/twikoo/1.6.21/twikoo.all.min.js"></script>

原主题的 Twikoo 版本是1.16.115,这里也顺便升级成匹配我部署的后端版本1.16.21

其他的评论系统也以此类推。

添加图片灯箱

原主题有一个「Image gallery」功能,但只支持本地图片,这对于所有图片都存在图床上的我来说显然不是什么好消息。于是我只好自己添加一个图片灯箱。

我原本准备采用 fancybox,毕竟我最熟悉这个,但 fancybox 需要引入 jQuery,这和我想让博客尽可能轻量化的初衷背道而驰。于是我找到了zoom-vanilla.js,虽然它也不完美,但论轻量是绝对够格的。

首先需要在前端引入zoom-vanilla.min.jszoom.css这两个资源,我直接丢进./static/引用,见仁见智。

将这两个资源放入./static/imgzoom/后,分别在<head>内和<body>6引入 css 和 js:

修改./layouts/partials/head/custom.html

1
<link href="/imgzoom/zoom.css" rel="stylesheet">

修改./layouts/partials/footer/custom.html

1
<script src="/imgzoom/zoom-vanilla.min.js"></script>

引入前端资源后需要为所有图像加上一个data-action="zoom"

修改./layouts/_default/_markup/render-image.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<img src="{{ $Permalink }}"
	{{ with $Width }}width="{{ . }}"{{ end }}
	{{ with $Height }}height="{{ . }}"{{ end }}
	{{ with $Srcset }}srcset="{{ . }}"{{ end }}
	loading="lazy"
	{{ with $alt }}
		alt="{{ . }}"
	{{ end }}
	{{ if $galleryImage }}
		class="gallery-image" 
		data-flex-grow="{{ div (mul $image.Width 100) $image.Height }}"
		data-flex-basis="{{ div (mul $image.Width 240) $image.Height }}px"
	{{ else }}
		data-action="zoom"
	{{ end }}
>

同前面一样,我也列出了这个文件的一部分,真正修改的部分只有一个else分支和data-action="zoom"

至此,图片灯箱添加完成。

变更 RSS 行为

这个其实有点超纲了,不过这个主题确实自定义了 RSS 模板。

RSS 遇到了两个问题,一个是输出了我全部 50+ 篇文章,文件变得特别大,这显然是不合理的;还有就是输出了searchabout等与 RSS 毫不相干的页面。

在配置文件config.toml末端加上:

1
2
3
[services]
  [services.rss]
    limit = 10

可以把 RSS 输出的文章数量限制在 10 篇。接下来处理不相关页面的问题,其实限制输出 10 篇文章已经解决了第二个问题的大部分。此时更新后的 Feed 依然会在第一个输出about,而且输出日期会随着构建时间变化,暂不清楚是什么原理导致的。

我的解决方案是引入一个新的 Front matter 键值nonRSS: true,编辑./layouts/_default/rss.xml的前部分:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{{- $pctx := . -}}
{{- if .IsHome -}}{{ $pctx = .Site }}{{- end -}}
{{- $pages := slice -}}
{{- if or $.IsHome $.IsSection -}}
{{- $pages = $pctx.RegularPages -}}
{{- else -}}
{{- $pages = $pctx.Pages -}}
{{- end -}}
{{- $pages := where $pages "Params.hidden" "!=" true -}}
{{- $pages := where $pages "Params.nonRSS" "!=" true -}}	//加入这一行
{{- $limit := .Site.Config.Services.RSS.Limit -}}
{{- if ge $limit 1 -}}
{{- $pages = $pages | first $limit -}}
{{- end -}}

重新构建就修好了 RSS Feed。

建议搜索引擎不索引「标签」页面

不知道为什么,搜索引擎总是喜欢把我的标签页面编入索引7,于是就出现了这样的场面:

image-20231020002500043

我决定给每个 Tag 页面加上一个noindex标记。并且用robots.txt排除这些页面。编辑baseof.html,在<head>部分加入如下内容:

1
2
3
{{ if .Data.Singular }}
    <meta name="robots" content="noindex">
{{ end }}

这样应该会给每个 Tag 页面加入一个noindex标记。

./static/下创建robots.txt

1
2
User-Agent: *
Disallow: /tags/

这样就可以把所有 Tag 页面排除索引。


  1. 作者 JimmyCai 似乎住在西班牙 ↩︎

  2. Azure 的边缘计算,https://github.com/microsoft/Oryx。 ↩︎

  3. 通过 Actions 调用 Oryx。 ↩︎

  4. 详见Hugo官网:Anytime Hugo looks for a matching template, it will first check the working directory before looking in the theme directory. If you would like to modify a template, simply create that template in your local layouts directory. ↩︎

  5. 现在已经升级成1.16.21PR#877 ↩︎

  6. 至少作者是这么说的,我放在<footer>也照样用。 ↩︎

  7. 可能是因为站点地图 ↩︎