
摘要: 本文分享 Hugo 博客性能优化的完整实战经验,通过启用缓存、图片压缩、资源优化等 10 个技巧,将构建时间从 5 秒压缩到 500ms,提升 10 倍。
一、优化前后对比 #
| 指标 | 优化前 | 优化后 | 提升 |
|---|---|---|---|
| 构建时间 | 5.2 秒 | 480ms | 91% |
| 首页加载 | 2.1MB | 380KB | 82% |
| Lighthouse 分数 | 72 | 96 | +24 |
| 图片体积 | 15MB | 2MB | 87% |
二、Hugo 构建优化 #
2.1 启用缓存 #
配置 hugo.toml:
[cache]
# 启用文件缓存
[cache.configfile]
maxAge = -1 # 永久缓存
[cache.getresource]
maxAge = -1
[cache.getjson]
maxAge = -1
[cache.getcsv]
maxAge = -1
[cache.getdir]
maxAge = -1
[cache.getglob]
maxAge = -1构建命令:
# 首次构建(无缓存)
hugo --minify
# 后续构建(使用缓存)
hugo --minify --cacheDir /tmp/hugo_cache2.2 减少页面数量 #
问题: 每篇文章生成多个页面(分页、标签、分类)
优化:
# hugo.toml
[pagination]
pagerSize = 20 # 减少分页数量
# 禁用不需要的页面类型
disableKinds = ["taxonomy", "term", "RSS", "sitemap", "robotsTXT"]2.3 并行构建 #
# 使用所有 CPU 核心
hugo --minify --maxProcesses -1
# 或指定核心数
hugo --minify --maxProcesses 42.4 精简内容 #
删除草稿:
# 不构建草稿文章
hugo --minify --buildDrafts=false限制构建范围:
# 只构建特定目录
hugo --minify --contentDir content/posts
# 只构建修改过的内容(实验性)
hugo --minify --renderToMemory三、图片优化 #
3.1 自动压缩 #
安装 hugo-pipe-images:
npm install -g sharp配置处理管道:
{{/* layouts/_default/single.html */}}
{{ $featured := .Resources.GetMatch .Params.featureimage }}
{{ $optimized := $featured.Resize "1200x webp q85" }}
<img src="{{ $optimized.Permalink }}"
width="{{ $optimized.Width }}"
height="{{ $optimized.Height }}"
loading="lazy"
alt="{{ .Title }}">3.2 响应式图片 #
{{ $img := .Resources.GetMatch "cover.jpg" }}
{{ $small := $img.Resize "480x webp q75" }}
{{ $medium := $img.Resize "768x webp q80" }}
{{ $large := $img.Resize "1200x webp q85" }}
<picture>
<source media="(min-width: 1024px)" srcset="{{ $large.Permalink }}">
<source media="(min-width: 640px)" srcset="{{ $medium.Permalink }}">
<img src="{{ $small.Permalink }}" alt="{{ .Title }}" loading="lazy">
</picture>3.3 懒加载 #
<!-- 原生懒加载 -->
<img src="image.jpg" loading="lazy" alt="...">
<!-- Intersection Observer(更精确控制) -->
<img src="placeholder.jpg"
data-src="image.jpg"
class="lazyload"
alt="...">
<script>
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
observer.unobserve(img);
}
});
});
document.querySelectorAll('img.lazyload').forEach(img => observer.observe(img));
</script>3.4 批量压缩脚本 #
#!/bin/bash
# scripts/optimize-images.sh
STATIC_DIR="/var/www/ai.mylog.vip/static/images"
find "$STATIC_DIR" -name "*.jpg" -o -name "*.png" | while read img; do
if [[ $img == *.jpg ]]; then
# JPG 压缩(质量 85%)
cwebp -q 85 "$img" -o "${img%.jpg}.webp"
elif [[ $img == *.png ]]; then
# PNG 压缩
pngquant --quality=65-85 --force "$img"
fi
echo "✅ Optimized: $img"
done四、资源加载优化 #
4.1 CSS 内联关键样式 #
{{/* layouts/partials/head.html */}}
<style>
{{ $critical := resources.Get "css/critical.css" | minify }}
{{ $critical.Content | safeCSS }}
</style>
<link rel="preload" href="{{ "css/main.css" | relURL }}" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="{{ "css/main.css" | relURL }}"></noscript>4.2 JavaScript 延迟加载 #
{{/* 非关键 JS 延迟加载 */}}
<script defer src="{{ "js/main.js" | relURL }}"></script>
{{/* 第三方库异步加载 */}}
<script async src="https://analytics.example.com/script.js"></script>4.3 DNS 预解析 #
<head>
<!-- 预解析常用域名 -->
<link rel="dns-prefetch" href="//fonts.googleapis.com">
<link rel="dns-prefetch" href="//www.google-analytics.com">
<!-- 预连接 -->
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
</head>五、CDN 配置 #
5.1 静态资源 CDN #
配置 hugo.toml:
[params]
cdnUrl = "https://cdn.example.com"
[outputFormats]
[outputFormats.CDN]
mediaType = "text/html"
baseName = "index"
isHTML = true使用 CDN URL:
{{ $cdnUrl := .Site.Params.cdnUrl }}
<img src="{{ $cdnUrl }}/images/{{ .Params.featureimage }}" alt="{{ .Title }}">
<link rel="stylesheet" href="{{ $cdnUrl }}/css/main.css">5.2 缓存策略 #
Nginx 配置:
# 静态资源(1 年缓存)
location ~* \.(jpg|jpeg|png|gif|ico|css|js|webp)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# HTML 文件(不缓存)
location ~* \.html$ {
expires -1;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}六、性能监控 #
6.1 Lighthouse 自动化 #
#!/bin/bash
# scripts/lighthouse-check.sh
URL="https://ai.mylog.vip"
OUTPUT_DIR="/var/www/ai.mylog.vip/reports"
lighthouse $URL \
--output=html \
--output-path=$OUTPUT_DIR/lighthouse-$(date +%Y%m%d).html \
--quiet
# 提取分数
score=$(cat $OUTPUT_DIR/lighthouse-*.html | grep -oP '"performance":\s*\K\d+' | head -1)
echo "Performance Score: $score"
# 告警(低于 90 分)
if [ $score -lt 90 ]; then
echo "⚠️ Performance score below 90!"
# 发送通知...
fi6.2 构建时间监控 #
#!/bin/bash
# scripts/build-monitor.sh
START=$(date +%s%N)
hugo --minify
END=$(date +%s%N)
DURATION=$(( (END - START) / 1000000 ))
echo "Build completed in ${DURATION}ms"
# 记录到日志
echo "$(date '+%Y-%m-%d %H:%M:%S'),${DURATION}" >> /var/log/hugo-build.log
# 告警(超过 1 秒)
if [ $DURATION -gt 1000 ]; then
echo "⚠️ Build time exceeded 1s!"
fi七、高级优化 #
7.1 资源 Hint #
<head>
<!-- 预加载关键资源 -->
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/css/critical.css" as="style">
<!-- 预获取(下一页可能需要的资源) -->
<link rel="prefetch" href="/page/2/">
<!-- 预渲染(整个页面) -->
<link rel="prerender" href="/next-article/">
</head>7.2 Service Worker #
// static/sw.js
const CACHE_NAME = 'hugo-blog-v1';
const urlsToCache = [
'/',
'/css/main.css',
'/js/main.js',
'/images/logo.png'
];
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(urlsToCache))
);
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => response || fetch(event.request))
);
});注册 Service Worker:
{{/* layouts/partials/footer.html */}}
{{ if hugo.IsProduction }}
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(reg => console.log('SW registered:', reg.scope))
.catch(err => console.log('SW registration failed:', err));
}
</script>
{{ end }}7.3 按需加载组件 #
{{/* 只在需要的页面加载特定 JS */}}
{{ if eq .Type "post" }}
<script defer src="{{ "js/post.js" | relURL }}"></script>
{{ end }}
{{ if .IsHome }}
<script defer src="{{ "js/home.js" | relURL }}"></script>
{{ end }}八、优化清单 #
发布前检查 #
- 图片已压缩(WebP 格式)
- CSS/JS 已压缩
- 启用了缓存
- 配置了懒加载
- 设置了 CDN
- 添加了缓存头
- Lighthouse 分数 > 90
- 构建时间 < 1 秒
性能目标 #
| 指标 | 目标值 | 优先级 |
|---|---|---|
| 构建时间 | < 500ms | 高 |
| 首屏加载 | < 1s | 高 |
| Lighthouse | > 90 | 中 |
| 图片体积 | < 100KB/张 | 中 |
九、常见问题 #
Q1: 构建时间突然变长? #
排查步骤:
- 检查新增内容数量
- 查看是否有大图片
- 清理缓存重新构建
- 使用
--logLevel debug查看详细日志
Q2: 图片质量下降明显? #
调整压缩参数:
{{ $optimized := $img.Resize "1200x webp q90" }} <!-- 提高质量到 90 -->Q3: CDN 缓存不更新? #
解决方案:
- 文件名添加版本号:
main.v1.2.3.css - 或清除 CDN 缓存
- 设置较短的缓存时间测试
十、总结 #
核心优化技巧 #
- 启用缓存 - 减少重复处理
- 图片压缩 - WebP + 懒加载
- 资源优化 - 压缩、内联、延迟加载
- CDN 加速 - 静态资源分发
- 监控告警 - 持续性能跟踪
收益总结 #
- ✅ 构建时间减少 91%(5.2s → 480ms)
- ✅ 页面体积减少 82%(2.1MB → 380KB)
- ✅ Lighthouse 分数提升至 96
- ✅ 用户体验显著改善
参考资料: