Hugo 是一个静态网站生成器:把 markdown 文件编译成一堆 html,传上服务器就是一个完整站点,不需要数据库,也不需要 php 或 node 在线上跑。

它的整个程序是一个 65212416 字节的 exe,没有运行时依赖。装的过程就是把 zip 解开,把 hugo.exe 放到 PATH 里。

这次从建站到本地预览全跑了一遍:建站 0.30 秒,构建 0.31 秒出 9 个文件,本地服务 0.55 秒起好。中途撞到两个坑,一个是模板缺失,一个是配置项被废弃。

一个 exe 就是一整套建站工具

zip 包 23540934 字节,解开只有三个文件:hugo.exe、LICENSE 和一份 README。解压 0.32 秒。

它是 Go 编译出来的单文件程序,不装 .NET 也不装 Python。拷到任何一台 Windows 上都能直接跑,换 Linux 就下对应平台的包,命令完全一样。

项目字节
zip 包23540934
hugo.exe65212416
LICENSE11357
README.md16523

版本命令 0.48 秒

跑 hugo version 输出一行:v0.168.0 extended windows/amd64,带构建时间和 commit 号。从进程启动到打印结果 0.48 秒。

extended 这个后缀要紧。它表示编译时带进了 Sass 和 WebP 支持,很多主题需要它。普通版遇到 scss 会直接报错,所以下载时认准 extended 那个包。

建站只要 0.30 秒

hugo new site 是本地跑的建站命令,跑完在目录里生成两个文件:hugo.toml 和 archetypes/default.md。

就这么点东西。没有 node_modules,没有 package.json,也没有一堆配置文件。剩下的目录要在用的时候自己建。

命令耗时产出
hugo version0.48 秒一行版本信息
hugo new site0.30 秒2 个文件
hugo --minify0.31 秒9 个文件
hugo server0.55 秒本地 1313 端口

目录结构自己建

建站之后只有骨架。文章放 content,模板放 layouts,图片和 css 放 static,这三层要自己 mkdir 出来。

我第一次跑的时候 content 目录还不存在,直接构建出来是空站。它不会帮你建这些目录,也不会报错。

没有模板它什么都不渲染

这一点最容易绊住新手:建好站、写好文章、跑构建,命令返回成功,产物也确实生成了,但打开页面一片空白。

日志里会有四行 WARN,分别对应 page、section、taxonomy 和 home 四种页面类型找不到模板。实际产物只有 5 个文件 4032 字节,全是空壳。

状态产物体积结果
没有 layouts4032 字节 / 5 个文件页面空白,4 条 WARN
加两个模板6880 字节 / 9 个文件正常显示

两个模板就够跑起来

layouts/index.html 管首页,layouts/_default/single.html 管文章页。每个二十来行 html 就能出一个能看的站。

我写的这两个模板加起来不到 30 行,做完之后首页能列文章、点进去能看正文。要好看当然得装主题,但要验证它能不能跑,这两个文件够了。

构建 0.31 秒出 9 个文件

三篇 markdown 加两个模板,hugo --minify 用 0.31 秒,产物 9 个文件 6880 字节。它自己的日志里写 Total in 42 ms,那是纯渲染时间,不含进程启动。

改一篇文章再构建,耗时 0.46 秒。比全量构建还慢一点,因为这次要重新读配置和模板,缓存没热起来。

动作耗时产物
首次构建0.31 秒9 个文件 6880 字节
改一篇重建0.46 秒同上,内容更新
内部渲染计时42 ms日志 Total in 42 ms

--minify 会压掉空白

加这个参数会把 html 里的换行和多余空格去掉,产物小一点。不加也能构建,只是文件大些。

三篇文章的站点 6880 字节,单篇平均两 KB 出头。这个量级下压缩意义不大,文章多到几百篇才有感觉。

本地预览 0.55 秒起来

hugo server 起一个带热更新的开发服务器,默认 1313 端口。从命令到能访问 0.55 秒。

首页加载 0.05 秒,因为就是读一个静态 html。改文章保存,浏览器会自动刷新,不用手动按 F5。

Hugo 本地预览站点首页:标题与三篇示例文章的列表,由二十行的最小模板渲染
文章页 /posts/first/:标题与正文,模板只写了返回链接、标题和内容三部分

预览和构建是两套东西

server 模式把页面放在内存里渲染,不写 public 目录。要拿产物上线,得单独跑一次构建。

两个命令的配置是同一份,所以预览看到的样子和构建出来的基本一致。唯一的差别是 server 会注入一段用于热更新的脚本。

几个真踩过的报错

症状原因处理
构建成功但页面空白没有 layouts 模板至少写 index.html 和 single.html
日志四条 no layout 警告同上同上
languageCode 废弃警告v0.158 起改用 locale把 languageCode 换成 locale
scss 报错下的是普通版不是 extended换 extended 包
端口 1313 被占上次的 server 没退加 --port 换端口

第一条和第二条是同一个原因。Hugo 不会因为缺模板就拒绝构建,它照常输出 html,只是里面没内容。

这种「成功了但没效果」的情况比直接报错费时间,因为你会以为是缓存或者浏览器的问题。

languageCode 已经改名

我按老教程在 hugo.toml 里写 languageCode,构建时出一行 WARN:这个键从 v0.158.0 起废弃,以后会被移除,让改用 locale。

网上大部分中文教程还是写 languageCode。能跑,但每次构建都会提醒一次,看着烦。

什么场景值得上

你的情况结论
写博客、文档站合适,构建快、不用数据库
文章上千篇还要秒级构建合适,这是它的强项
要评论、要后台管理不合适,它只生成静态页
要用户登录和表单不合适,得另接服务
只想改几个页面的小站不合适,直接写 html 更快

它把「内容」和「呈现」分开,内容永远是 markdown,换了主题也不用动文章。这是静态生成器最值钱的地方。

代价是没有服务端。搜索、评论还有统计这些要接第三方,或者自己在构建时把索引生成好。想清楚这一点再选。