Skip to main content

Hugo 心得雜談

從使用者變成主題維護者,對 Hugo 越來越熟悉所以決定寫一下我的理解,本文比較面向用戶而不是開發者。

Hugo 的優點

Hugo 最大的優點就是「完全無須理解前端複雜生態」,不管前端有什麼 npm yarn pnpm bun,什麼 React Vue Angular Next.js 各種框架,SSR CSR Hydration 一堆有的沒的問題全都與我們無關,基本上 Hugo 就只會有 HTML/CSS/JS 三個打天下,不用學一堆有的沒的奇怪知識,我們沒有要成為前端工程師。

Hugo 沒有任何依賴,只要一個二進制包就可以在任何地方運行,這也代表不管過 10 年 20 年永遠都可以用同一個二進制檔案編譯你的 Markdown 文件不需要任何語法更新,沒有套件失效找不到的問題,也沒有任何麻煩的依賴管理,20 年後唯一要更新的就是舊版 CSS 語法瀏覽器可能不支援了,但是 Hugo 的二進制包還是活的好好的。

Hugo 很快,甚至比 Zola 還快。

Hugo 很容易客製化主題,內建的 override 機制可以任意客製化任何檔案,沒有任何檔案不能客製化的,對比 Docusaurus 高度支援但還是有限的客製化支援,以及 Vitepress 上手難度相對高的客製化,指定檔案的客製化輕鬆很多。hexo 雖然可以直接修改主題原始碼,但是沒有 override 功能,主題更新就需要手動合併上游更新。

Hugo 發展已經足夠久,支援各種想的到想不到的方法,例如 permalink 各種設定、相關文章、上下一篇文章等等,或是可以直接在 Markdown 裡面隨便寫 HTML,shortcode 簡單易懂能非常輕鬆的自定義,不用像 Docusaurus 寫彆腳的 MDX 語法,現在也整合 TS/SASS/Tailwind;主題爆多,絕對碾壓其他所有靜態網站生成器。

Hugo 由於其強烈基於 HTML 的原因,絕大多數主題即使沒有 JS 的環境大部分功能也能正常運作,而其他基於前端思維 SSG 做出來的網頁更依賴瀏覽器 JS 環境

Hugo 已經驗證可規模化

Hugo 的缺點

Template 的 return 功能是唯一一個回傳物件的方式,但是這種方式超級難以除錯

Hugo 的 Go 模板需要額外時間理解,Go 模板混用 HTML IDE 支援困難,需要額外理解 Hugo/Go 語法和渲染方式,不支援所有 Go 語法,文檔雖然非常詳細,但是編排對用戶和開發者都雜亂難理解。

Shortcode 功能雖然直覺易懂,但是讓 Hugo 的 Markdown 難以遷移到其他 SSG。

Hugo 要使用現代前端技術非常困難,因為基本上只有 HTML/CSS/JS 三件套,要搞 SPA 也不容易,根本沒有幾個主題支援 SPA,沒有框架所有東西只能手搓,這代表所有 Hugo 主題都不會太複雜。

Hugo 可以整合現代前端開發但是有點麻煩,因為他和 npm 就是不同系統的東西。

Hugo 可以當作沒有函式這種東西,唯一最像函式的 partial 限制一堆,連輸入輸出都沒辦法明確標示,開發很痛苦。

Hugo 沒有金主支援,像是 Next.js 有 Vercel,Docusaurus 有 Facebook,Hugo 是純開源的專案,看天吃飯。

Hugo 十年了還不是穩定版本,一天到晚在搞影響下游的更新,穩定程度甚至不如 JS-based 專案,除非你完全不升級。

Hugo 只有兩個維護者,沒有任何團隊組織,所有開發都是維護者覺得好就做,覺得好,不想做的也不做。

Hugo 邏輯奇特,沒理由的不處理就算了,還把自己不處理當作不接受的理由。用戶沒發問不代表不需要,很多人遇到問題就自己繞路解決了,不會特地去發文,還是他期待大家不爬文一直問重複問題?

主題安裝方式

有 Git submodule 和 Hugo module 兩種方式安裝,兩者都可以指定版本,Hugo module 功能比較豐富,但是因為 Hugo 文檔太爛所以要懂 Go module 才好用。

我認為手動安裝,也就是手動把主題放到 themes 目錄並且自己用 git 保管主題原始碼也是個好方法,這樣更安全。

另一種神奇方式

除此之外還有一種神奇安裝方式,就是 doks 使用 npm 把主題下載到 node_modules 裡面,再使用 mounts 功能把檔案掛載到 theme 目錄,這種方式找原始碼極度痛苦。

圖片要放哪

完全不會經過 Hugo 管道處理的放在 static,到處都會用到的放在 assets,文章目錄相關的放在 Markdown 同資料夾中。

static 的內容會原封不動的複製到專案輸出位置完全沒有額外處理,assets 和 content 目錄中的圖片則是可以被 Hugo 管道處理,如果沒有處理到的就是主題開發者寫錯,可以用 resources.Get.Resources.Get 檢查主題原始碼看看有沒有正確處理全局(包含 assets)和頁面(同一 page bundle 底下)的圖片。

不過我建議放在 CDN 上,這讓你的 Markdown 便攜和遷移能力又往上一個層級,方式請見架設Cloudflare R2免費圖床,給Hugo靜態網站託管圖片,他使用 rclone 作為和 CDN 的交互介面,或者可以參考不看后悔!CloudFlare R2 图床搭建教程,可能是目前最完美的解决方案!以 PicGo 作為介面,我個人則是使用 PicList,這是用法和 PicGo 幾乎相同但是使用體驗優化的版本。

404 頁面不支援多語言

因為這是靜態網站沒有伺服器,要找有後端處理能力的託管服務才可以達成,設定方式請見此討論

development 設定是什麼

config/development 用於開發環境的設定檔,例如我有一個 showcase 目錄可能有幾百個頁面,就可以在裡面設定 ignoreFiles 在本地開發時忽略這些檔案。

詳情請見 environment

Page bundles

bundles 應該翻譯成「包」或者「綑」,所以就是頁面包或者頁面綑綁,這知識一點屁用都沒有,我發了幾十個 PR 沒用過這觀念也是活的好好的功能全部正常,完全不懂為什麼大家都愛介紹這個。

簡單來說 bundles 就是目錄,分成 leaf bundles 和 branch bundles,leaf 就是單一文章,底下沒有子目錄或額外文章,branch 則相反,並且 branch 通常會有一個 _index.md 作為段落說明檔案。

超級實用的參數

Hugo 參數說多不多說少也不少,這裡是我整理出最實用的幾個參數:

  • -DEF: 分別代表構建 draft, expired, future,這可以避免你文章找老半天結果只是設定錯誤的問題
  • --renderToMemory: 渲染到記憶體,大小網站都適用,避免浪費硬碟讀寫壽命
  • --disableFastRender: 顧名思義
  • --bind 0.0.0.0: 綁定到本機 URL,可以透過 https://你的電腦IP:port/ 瀏覽
  • HUGO_參數: 使用環境變數覆寫任何參數,任何參數都可以覆蓋,我最常用的是 HUGO_DISABLELANGUAGES='it ja zh-cn' 快速開發避免渲染不需要的多語言,HUGO_PARAMS_DEFAULTBACKGROUNDIMAGE='/img/bg.jpg' 覆蓋 Blowfish 的白癡 SVG 背景圖片,改個文檔也可以讓 M1 MBP 風扇起飛未免太誇張。

還有不常用但是實用的參數

  • --source: 設定根目錄
  • --themesDir: 設定主題目錄,兩者結合就可以 clone Blowfish 專案並且以 hugo server --source exampleSite --themesDir ../.. 開發放在 exampleSite 的網站

頁面種類

這是從 Hugo page kind 文檔複製來的,無須說明一目了然:

content/
├── books/
│ ├── book-1/
│ │ └── index.md <-- kind = page
│ ├── book-2.md <-- kind = page
│ └── _index.md <-- kind = section
├── tags/
│ ├── fiction/
│ │ └── _index.md <-- kind = term
│ └── _index.md <-- kind = taxonomy
└── _index.md <-- kind = home

我認為用戶還是要懂頁面種類才能良好的使用 Hugo。如果你的主題作者有按照 Hugo 理念建立專案,那是可以做到一一對應的:

  • page: home.html
  • section: section.html
  • taxonomy: taxonomy.html
  • term: term.html

如果他用舊版語法或是其他原因沒照做,通常會變成這樣:

  • page: index.html
  • section: list.html
  • taxonomy: taxonomy.html or list.html
  • term: term.html or list.html

只有 baseof.html 永遠是所有頁面的基礎,其他都不一定,因為 Template lookup order 導致 Hugo 有非常高的互相替代邏輯,因此沒辦法說哪個檔案就一定是渲染哪種頁面。