Hugo 博客初始化过程记录

需求
hugo 编写文档时,需要手工将图片复制到 /static/images目录下,会很繁琐,而且在terminall 页面编辑不一定体验感会很强,尤其是在文章的复制粘贴的时候,又携带了很多图片,会变得非常不方便
Obsidian
Obsidian 是一个开源的 markdown 笔记本,有丰富的插件,支持将笔记定时到github等,页面也非常友好,我们可以使用 obsidian 编辑我们的文章,同时还可以解决图片编辑的问题,以下是详细步骤
- 修正图片链接
设置中找到
Files and link
关闭Use[[Wikilinks]]
如果不关闭复制上来的图片格式会是:![[]]
而不是markdown格式的![]()
hugo 也就无法正确的加载 - 设置文件保存路径
设置中指定文件的保存路径为:
/static/images
与hugo一致 - 使用相对路径save
New link format 要改为:
Absolute path in vault
默认是短链,hugo也无法识别
配置
1. 解决复制图片的路径问题
obsidian配置完后会发现图片还是无法正常加载,因为 hugo 编译的时候会把 /static/images 的东西编译到 public 目录,页面引用路径会变成:/images
编辑文件(没有则创建):vim layouts/_default/_markup/render-image.html
{{- $src := .Destination -}}
{{- $src = replace $src "static/" "/" -}}
<img src="{{ $src }}" alt="{{ .Text }}" {{ with .Title }}title="{{ . }}"{{ end }} />
这个渲染钩子会自动将 Markdown 中的 static/images/ 路径转换为 /images/。 这是一个 Hugo 内置功能,不需要修改 Markdown 文件本身,能自动处理页面渲染时的路径问题。
2. 压缩问题
2.1 使用hugo 钩子
Hugo 有强大的图片处理能力,可以在构建时自动压缩和调整图片大小: 在render-image.html 中引入如下内容:(这段已经包含了路径替换,与上一段不能一起使用)
{{- $src := .Destination -}}
{{- $src := replace $src "static/" "/" -}}
{{- $original := printf "static%s" $src -}}
{{- if fileExists $original -}}
{{- $resource := resources.Get (strings.TrimPrefix "/" $src) -}}
{{- with $resource -}}
{{- $processed := .Resize "1000x webp q80" -}}
<img src="{{ $processed.RelPermalink }}" alt="{{ $.Text }}" />
{{- else -}}
<img src="{{ $src }}" alt="{{ $.Text }}" />
{{- end -}}
{{- else -}}
<img src="{{ $src }}" alt="{{ $.Text }}" />
{{- end -}}
*不推荐使用,因为路径的关系 resource.Get会失效 *
2.2 使用precommit
在.git/hook/pre-commit 写入如下内容(write by cursor),并 chmod +x precommit 注意:要预装:ImageMagick brew install image magick 即可
#!/bin/bash
# 彩色输出函数
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
RED='\033[0;31m'
NC='\033[0m' # 恢复默认颜色
# 创建临时文件
TMP_FILE=$(mktemp)
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${BLUE}📸 图片压缩工具${NC}"
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
# 检查有哪些工具可用
TOOLS_FOUND=0
if command -v pngquant &> /dev/null; then
echo -e "${GREEN}✓${NC} 发现 pngquant"
TOOLS_FOUND=$((TOOLS_FOUND+1))
fi
if command -v optipng &> /dev/null; then
echo -e "${GREEN}✓${NC} 发现 optipng"
TOOLS_FOUND=$((TOOLS_FOUND+1))
fi
if command -v jpegoptim &> /dev/null; then
echo -e "${GREEN}✓${NC} 发现 jpegoptim"
TOOLS_FOUND=$((TOOLS_FOUND+1))
fi
if command -v convert &> /dev/null || command -v magick &> /dev/null; then
CONVERT_CMD=$(command -v magick 2>/dev/null || echo "convert")
echo -e "${GREEN}✓${NC} 发现 ImageMagick ($CONVERT_CMD)"
TOOLS_FOUND=$((TOOLS_FOUND+1))
fi
if [ $TOOLS_FOUND -eq 0 ]; then
echo -e "${RED}错误: 未找到任何图片压缩工具${NC}"
echo "请安装以下至少一种工具:"
echo " • ImageMagick (convert/magick)"
echo " • pngquant"
echo " • optipng"
echo " • jpegoptim"
exit 1
fi
echo -e "\n${BLUE}🔍 查找需要压缩的图片...${NC}"
# 只获取新增(A)和修改(M)的文件
git diff --cached --name-only --diff-filter=AM -z > "$TMP_FILE"
# 统计数量和大小
TOTAL_FILES=0
TOTAL_ORIG_SIZE=0
TOTAL_NEW_SIZE=0
PROCESSED_FILES=0
# 处理文件
while IFS= read -r -d $'\0' FILE; do
# 检查文件是否存在且是images目录下的图片
if [[ -f "$FILE" && "$FILE" == static/images/* ]]; then
# 获取小写扩展名
EXT="${FILE##*.}"
EXT=$(echo "$EXT" | tr '[:upper:]' '[:lower:]')
if [[ "$EXT" == "jpg" || "$EXT" == "jpeg" || "$EXT" == "png" ]]; then
TOTAL_FILES=$((TOTAL_FILES+1))
# 获取文件名部分
FILENAME=$(basename "$FILE")
if [[ "$EXT" == "jpg" || "$EXT" == "jpeg" ]]; then
echo -e "\n${YELLOW}🖼️ 处理 JPEG:${NC} $FILENAME"
cp "$FILE" "$FILE.bak"
if command -v jpegoptim &> /dev/null; then
echo -e " 使用 jpegoptim 优化中..."
jpegoptim --max=82 --strip-all --all-progressive --overwrite "$FILE" > /dev/null
elif command -v convert &> /dev/null || command -v magick &> /dev/null; then
echo -e " 使用 ImageMagick 优化中..."
$CONVERT_CMD "$FILE" -resize "1200x>" -quality 82 -strip "$FILE" > /dev/null
fi
elif [[ "$EXT" == "png" ]]; then
echo -e "\n${YELLOW}🖼️ 处理 PNG:${NC} $FILENAME"
cp "$FILE" "$FILE.bak"
if command -v convert &> /dev/null || command -v magick &> /dev/null; then
echo -e " 使用 ImageMagick 调整大小..."
$CONVERT_CMD "$FILE" -resize "1200x>" -strip "$FILE.tmp.png" > /dev/null
mv "$FILE.tmp.png" "$FILE"
fi
if command -v pngquant &> /dev/null; then
echo -e " 使用 pngquant 优化中..."
pngquant --force --quality=80-95 --skip-if-larger --strip --output "$FILE" "$FILE" > /dev/null 2>&1
fi
if command -v optipng &> /dev/null; then
echo -e " 使用 optipng 优化中..."
optipng -o3 -quiet "$FILE" > /dev/null
fi
fi
# 检查效果
ORIG_SIZE=$(stat -c%s "$FILE.bak" 2>/dev/null || stat -f%z "$FILE.bak")
NEW_SIZE=$(stat -c%s "$FILE" 2>/dev/null || stat -f%z "$FILE")
ORIG_SIZE_KB=$(( $ORIG_SIZE / 1024 ))
NEW_SIZE_KB=$(( $NEW_SIZE / 1024 ))
if [ $NEW_SIZE -lt $ORIG_SIZE ]; then
SAVED_KB=$(( $ORIG_SIZE_KB - $NEW_SIZE_KB ))
PERCENT=$(( ($SAVED_KB * 100) / ($ORIG_SIZE_KB + 1) ))
echo -e " ${GREEN}✓ 压缩成功:${NC} ${ORIG_SIZE_KB}KB → ${NEW_SIZE_KB}KB (减小 ${SAVED_KB}KB, 节省 ${PERCENT}%)"
rm "$FILE.bak"
git add "$FILE"
PROCESSED_FILES=$((PROCESSED_FILES+1))
TOTAL_ORIG_SIZE=$((TOTAL_ORIG_SIZE + ORIG_SIZE_KB))
TOTAL_NEW_SIZE=$((TOTAL_NEW_SIZE + NEW_SIZE_KB))
else
echo -e " ${RED}✗ 无法有效压缩,保留原图${NC}"
mv "$FILE.bak" "$FILE"
fi
fi
fi
done < "$TMP_FILE"
# 清理临时文件
rm "$TMP_FILE"
echo -e "\n${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
if [ $TOTAL_FILES -eq 0 ]; then
echo -e "${YELLOW}未找到需要处理的图片文件${NC}"
else
echo -e "${GREEN}🎉 总结:${NC}"
echo -e " • 找到 ${TOTAL_FILES} 个图片文件"
echo -e " • 成功压缩 ${PROCESSED_FILES} 个文件"
if [ $PROCESSED_FILES -gt 0 ]; then
TOTAL_SAVED=$((TOTAL_ORIG_SIZE - TOTAL_NEW_SIZE))
TOTAL_PERCENT=$((TOTAL_SAVED * 100 / TOTAL_ORIG_SIZE))
echo -e " • 总共节省空间: ${TOTAL_SAVED}KB (${TOTAL_PERCENT}%)"
fi
fi
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
exit 0
最终效果图:
3. 启用评论
我们引用的DoIt 主题已经包含了很多评论工具,如 giscus/disqus等等,现主要介绍这两种,具体的可以在官网中查找:site_configuration 二者的接入方式都比较简单,此处不再展开,要注意的是一定要参考官方文档,插件都更新的比较快,以官方文档为准
baseURL = 'https://ox-warrior.top/'
languageCode = 'en-us'
title = 'Ox-Warrior'
theme = 'DoIt'
[params.page.comment]
enable = true
[params.page.comment.disqus]
enable = true
shortname = "xxxxxxx"
[params.page.comment.giscus]
enable = true
dataRepo = "ox-warrior/hugo-doit-giscus"
dataRepoId = "Rxxxxx"
dataCategory = "General"
dataCategoryId = "DIC_xxxxxx"
dataMapping = "pathname"
dataReactionsEnabled = "1"
dataTheme = "preferred_color_scheme"
dataInputPosition = "bottom"
[build]
noComments = false
这里同时开启了 giscus
与 disqus
如果不加任何配置,会优先使用第一个:disqus
我们现在有个需求:英文文档使用 disqus (外网访问较快),中文使用 giscus,如果要实现该效果,我们需要在文章的开头属性那里配置如下
comment:
disqus:
enable: true
giscus:
- enable: false
需要将每一个插件都穷举在这里,很不方便,通过对 DoIt 的分析,发现控制comment的加载是通过 themes/DoIt/layouts/_partials
下的 comment.html
控制的,那可以修改这里的代码,增加一个参数commentSystem
根据他的值来决定加载哪个!
但是我们最好不要直接修改源代码,可以在项目的 layouts/partials
下创建一个新的comment.html
{{- $cdn := .Scratch.Get "cdn" | default dict -}}
{{- $fingerprint := .Scratch.Get "fingerprint" -}}
{{- $comment := .Scratch.Get "comment" | default dict -}}
{{- $commentConfig := dict -}}
{{- if $comment.enable -}}
{{- .Scratch.Set "enableComment" true -}}
<div id="comments" class="print:!tw-hidden tw-pt-32 tw-pb-8">
{{- /* Disqus Comment System */ -}}
{{- /* 使用 .Params.commentSystem 参数来决定启用哪个评论系统 */ -}}
{{- $commentSystem := .Params.commentSystem | default "default" -}}
{{- if eq $commentSystem "none" -}}
<!-- 不显示评论,但保留评论区块 -->
<div class="comment">评论功能已禁用</div>
{{- else if eq $commentSystem "disqus" -}}
{{- $disqus := $comment.disqus | default dict -}}
{{- if $disqus.enable -}}
<div id="disqus_thread" class="comment"></div>
{{- $source := printf "https://%v.disqus.com/embed.js" $disqus.shortname -}}
{{- dict "Source" $source "Defer" true | dict "Scratch" .Scratch "Data" | partial "scratch/commentScript.html" -}}
<noscript>
Please enable JavaScript to view the comments powered by <a href="https://disqus.com/?ref_noscript">Disqus</a>.
</noscript>
{{- end -}}
// 其他插件方法类似,不一一展开了
{{- end -}}
最后在文档的开头增加一个属性:commentSystem: “插件名” 即可如果没设置就是不开启
4. Obsidian 属性头
可以通过 Templater 插件定义一个专属属性头 准备一个.template 格式文件,插件安装好后导入即可。
---
date: <% tp.date.now("YYYY-MM-DDTHH:mm:ss") %>
draft: "false"
title: "<% tp.file.title %>"
commentSystem: giscus
---
创建新文档后,可以使用快捷键或者鼠标点击插件应用该 matter 就会自动追加到开头
主题
换一次电脑,需要重新安装
git clone https://github.com/HEIGE-PCloud/DoIt.git themes/DoIt