为什么选择 Hugo

在尝试过几套博客方案后,我把目标收敛成一句话:只保留内容,其他都交给编译期。Hugo 正好满足这一条:

  • 一次编译,输出纯静态文件,部署只需把 public/ 放到 Nginx/Caddy 任意静态服务后。
  • 原生支持 Markdown、Front Matter、分类(Categories)和标签(Tags),无需额外插件。
  • 单二进制启动,无运行时依赖,对低资源服务器非常友好。
  • 构建速度极快,整个站点基本在毫秒级完成 hugo --minify。

相比之下,WordPress 需要数据库、PHP 运行时和持续的安全维护;Hexo 等 Node 方案在冷启动和依赖体积上明显更重。综合评估,Hugo 的"工具简单 + 长期可维护"更符合本项目的诉求。

选型前后要做的事

搭建之前,最好明确下面几个问题,否则后期容易反复改模板:

  1. 站点定位:纯博客还是泛内容门户?是否需要多语言?
  2. 内容分类:先把分类列清楚(例如本博客的 6 类),再让模板去适配。
  3. 部署形态:独立子目录、Caddy/Nginx 反代,还是 CDN?这一项决定 baseURL 怎么写。
  4. 可扩展点:评论、统计、相关文章、广告位——前期先不要写进模板。

我把这些写进 README.md 和 hugo.yaml,让"选型理由"和"实现细节"在同一份文档里对齐,避免方案漂移。

目录与配置骨架

下面是本站测试副本的核心目录约定,模板、配置和构建产物互不干扰:

1
2
3
4
5
content/    # 文章 Markdown(含 _index.md)
layouts/    # 自包含模板,不依赖第三方主题
static/     # css / js / 图片等
hugo.yaml   # 全部 Hugo 配置
public/     # hugo 构建产物(已加入 .gitignore)

hugo.yaml 里只保留真正用得到的字段:站点标题、默认语言、CJK 开关、菜单、Markdown 渲染参数、输出格式(首页和分类同时输出 HTML 与 RSS)。disableKinds 留空——Hugo 会按需生成必要页面,不提前裁剪。

本地构建与预览

构建并校验命令都很轻量:

1
2
3
4
5
6
7
8
# 生成静态站点到 public/
/tmp/hugo-bin/hugo --minify

# 严格模式:出现任何 warning 直接 panic
/tmp/hugo-bin/hugo --panicOnWarning

# 本地预览(默认 http://localhost:1313)
/tmp/hugo-bin/hugo server -D

--panicOnWarning 在 CI 或发布前很有用,能提前发现 front matter 拼写错误、模板语法问题、孤立链接等隐患。

SEO 与 RSS 基础

为了让搜索引擎能正确收录,我在基础模板里加了:

  • meta description:优先使用页面摘要,否则回退到 Site.Params.description。
  • link rel="canonical":避免 baseURL 切换后产生重复内容。
  • Open Graph 与 Twitter Card 元数据。
  • application/ld+json 站点级 / 文章级 JSON-LD:首页输出 WebSite,文章页输出 Article 并附 headline、datePublished、author。

Hugo 自带 sitemap.xml 与 index.xml(RSS)输出,无需手写。模板里 <link rel="alternate" type="application/rss+xml"> 会把订阅入口暴露给浏览器和阅读器。enableRobotsTXT: true 会输出极简的 robots.txt,后续如果需要精确控制,再补一份 layouts/robots.txt 模板即可。

分类与标签的落地方式

Hugo 把分类和标签当成"自带"的两套 Taxonomy。在 content/posts/*.md 的 front matter 里写:

1
2
categories: ["AI 与效率"]
tags: [Hugo, 静态博客]

Hugo 会自动生成:

  • /categories/:分类总览
  • /categories/<name>/:分类详情
  • /tags/、/tags/<name>/:标签总览与详情

为了避免 list.html 把分类页和普通文章列表混在一起,我额外提供了 taxonomy.html(分类总览)和 term.html(具体某个分类 / 标签)两个模板,渲染时只显示真正的文章页(Kind == "page"),不会把嵌套分类再次列出来。

站内搜索:客户端方案

搜索是本项目最低成本的实现。思路是:

  1. 模板在所有文章页统一通过一个 <script> 把 {title, permalink, summary, tags} 写入 <script id="post-data" type="application/json">。
  2. static/search.js 在用户访问 /search/ 时把这份数据加载到内存,做大小写不敏感的子串匹配。
  3. 结果按命中片段在标题 / 摘要的优先级排序。

这种方式无需后端、无需索引服务器、无需第三方库(用几十行原生 JS 就能跑),对低流量博客完全足够。等文章量增长到几百篇,再考虑切换到预生成的 JSON 索引 + Lunr/Pagefind。

后续清单

  • 在 README 里写明"修改文件 → 运行 hugo --minify → 检查 public/ 产物"的标准流程。
  • 接入 Git 仓库,每次构建都有提交记录可追溯。
  • 准备独立服务部署目录,由 Caddy 反代到 public/。
  • 在正式上线前再补一次 SEO 校验(canonical、OG 渲染结果、JSON-LD 校验)。

先把"能跑 + 能写"这一层搭好,再去决定是否扩展到淘宝客、攻略站等具体方向。

相关

顺带一提:站搭好只是第一步,搜索引擎怎么开始收录,看这篇百度搜索资源平台接入指南。