下載頁上 hugo_extended_0.170.0_linux-amd64.tar.gz 這個檔名看起來跟半年前一模一樣,抓下來跑 file 一看,type 從「dynamically linked」變成「statically linked」。同一個檔名,裡面已經不是同一種東西,這就是 Hugo v0.170.0 這次最容易被忽略的細節。
release note 寫得很直白:extended 版正式沒了,只留一顆 binary。表面上看是「拿掉一個下載選項」,但對還在用 css.Sass 編譯 .scss、CI 腳本寫死抓 extended 檔名的人來說,是建置直接失敗的等級。這篇把 v0.169.0 跟 v0.170.0 的 regular binary、以及兩版的 hugo_extended_* 封存檔都抓下來,在容器裡跑一輪,看差異到底多具體。
讀完能帶走三件事:extended 消失後錯誤訊息怎麼變、hugo_extended_* 別名封存檔實際是什麼貨色、以及這版順便修掉的旗標 vs 環境變數優先順序問題會不會動到你的 CI。

github.comgohugoio/hugo v0.170.0extended 版移除,css.Sass 只剩 Dart Sass,旗標優先序修正
一、背景:extended 版為什麼存在,又為什麼被拔
Hugo 從早期開始就有兩種發行版:regular(純 Go,CGO_ENABLED=0)跟 extended(CGO_ENABLED=1,多連結一顆 C 寫的 libsass,拿來編譯 Sass/SCSS)。想用 resources.ToCSS(後來的 css.Sass)處理樣式表的人,得特地去抓檔名帶 extended 的版本,不然建置會在 css.Sass 那一步噴錯。
Dart Sass 支援進來之後,libsass 其實早就被官方標成 deprecated——v0.153.0 開始,css.Sass 用 transpiler: libsass 會印一行 warning,提醒之後會拿掉。只是大多數人沒細看 release note,照舊沿用舊設定檔跑了快十個版本。
libsass 的 deprecated warning 從 v0.153.0(約一年前)就開始印,v0.170.0 只是把「警告」正式升級成「移除」。中間這段時間已經是給大家遷移到 Dart Sass 的緩衝期。
CGO 編譯有個現實麻煩:它需要目標平台有對應的 C 工具鏈,跨平台編譯變複雜,二進位也不是純靜態(dynamically linked),在某些最小化容器基底上會因為缺 libc 版本而跑不起來。維護團隊把這包袱拆掉,於是 v0.170.0 把 extended 整個停產,只留一顆靜態連結的 Go binary。
二、這次具體改了什麼
2.1 binary 層面
| 項目 | v0.169.0 | v0.170.0 |
|---|---|---|
| 官方發行版數量 | regular + extended 兩顆 | 只剩 regular 一顆 |
hugo_extended_<ver>_linux-amd64.tar.gz |
真的存在,CGO 編譯 | 仍保留檔名(相容舊 CI),內容換成跟 regular 同一顆 |
hugo.IsExtended |
regular 版本來就是 false | 恆為 false(已無任何官方 binary 會是 true) |
css.Sass transpiler: libsass |
可用(extended 版)/regular 版報錯要求裝 extended | 直接報錯:功能已移除 |
flag 是否覆蓋 HUGO_* 環境變數 |
否(env 贏,有 bug) | 是(flag 贏,已修正) |
這張表裡第二列最容易被忽略。官方刻意保留 hugo_extended_* 這個檔名,不是因為裡面的東西沒變,而是怕一次拿掉連下載連結都找不到,會讓舊版 CI 腳本直接 404。但保留檔名、換掉內容,反而製造了一種「看起來還能用」的假象:下載腳本不會報錯,直到跑到 css.Sass 那步才爆炸。
2.2 兩個官方 binary,實測確認型態差異

分別把兩個版本的 hugo_extended_<ver>_linux-amd64.tar.gz 解開看 ELF header:
$ file h169-extended/hugo h170-extended/hugo h169-extended/hugo: ELF 64-bit LSB executable, x86-64, dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, stripped h170-extended/hugo: ELF 64-bit LSB executable, x86-64, statically linked, Go BuildID=..., stripped
v0.169.0 那顆有 interpreter /lib64/ld-linux-x86-64.so.2,代表執行時要去找動態函式庫,這是 CGO 編譯的典型特徵,裡面真的連結了 libsass。v0.170.0 同檔名的那顆完全沒有 interpreter 欄位,是純 Go 靜態編譯,跟 regular 版本質上是同一顆程式。官方把舊檔名留著給還沒更新 CI 腳本的人下載,但下載到的東西已經名不符實。
三、實測環境與方法
3.1 環境
| 項目 | 內容 |
|---|---|
| 容器 | debian:12-slim,amd64 |
| 編譯環境 | Docker Desktop |
| Hugo 版本 | v0.169.0(2026-10-27)、v0.170.0(2026-11-13),皆為官方 linux-amd64 release 二進位 |
| extended 封存檔 | 同版號的 hugo_extended_<ver>_linux-amd64.tar.gz,用來比對二進位型態 |
| 測試日期 | 2026-11-14 |
3.2 方法
兩個版本各自裝進獨立的 Debian 容器,跑同一組測試站台(一個有 .scss 資源、一個有 1 篇 draft 文章的最小 Hugo 專案)。每組測試都是對照跑:先跑 v0.169.0 記錄輸出,再跑 v0.170.0 記錄輸出,指令與參數完全一致,只換 binary。輸出照貼,沒有取平均也沒有重複跑(這些是確定性輸出,不是效能數字,跑幾次結果都一樣)。
3.3 原始輸出:版本號
$ hugo version hugo v0.169.0-1da10fc44701c566b1669cdb2d12638f155138bd linux/amd64 BuildDate=2026-10-27T14:52:20Z VendorInfo=gohugoio
$ hugo version hugo v0.170.0-f7aa05f0f521611aa960b2da56e1870ea04f57b2 linux/amd64 BuildDate=2026-11-13T14:17:19Z VendorInfo=gohugoio
3.4 原始輸出:libsass 編譯
layout 裡放一段 css.Sass (dict "transpiler" "libsass") 處理 main.scss:
$ hugo WARN deprecated: css.Sass: libsass was deprecated in Hugo v0.153.0 and will be removed in a future release. Use dartsass instead. ERROR error building site: render: [en] failed to render pages: render of "/" failed: executing "index.html" at <.Content>: error calling Content: TOCSS: failed to transform "/sass/main.scss": Check your Hugo installation; you need the extended version to build SCSS/SASS with transpiler set to 'libsass'.
$ hugo ERROR error building site: render: [en] failed to render pages: render of "/" failed: executing "index.html" at <css.Sass>: error calling Sass: css.Sass: the libsass transpiler was removed in Hugo v0.170.0 (deprecated from v0.153.0); use dartsass instead.
兩段錯誤訊息長得像,但意義完全不同。v0.169.0 那句「你需要 extended 版」隱含一個可行動作:去抓 extended 版就能解決。v0.170.0 那句「已經移除」沒有這個退路,唯一出路是把設定改成 dartsass。如果 CI log 只抓關鍵字 "extended" 來判斷要不要切版本,這次升級會讓腳本邏輯整個失效。
3.5 原始輸出:旗標 vs 環境變數
第一組:-e 旗標與 HUGO_ENVIRONMENT 環境變數同時設定不同值:
$ HUGO_ENVIRONMENT=qa hugo --quiet -e staging EnvironmentHugo=qa
$ HUGO_ENVIRONMENT=qa hugo --quiet -e staging EnvironmentHugo=staging
v0.169.0 這組是 release note 點名的 bug:它實際上載入的是 -e staging 指定的設定檔,但模板裡 hugo.Environment 讀回來卻是 qa。也就是說設定套用對了,回報的值卻是錯的。這種「行為對、回報錯」的 bug 特別難抓,因為建置結果看起來正常,只有依賴 hugo.Environment 做條件判斷的模板邏輯會悄悄走錯分支。v0.170.0 修正後兩者一致,flag 真正贏過環境變數。
第二組:草稿建置開關,一樣 env 與 flag 互相矛盾:
$ HUGO_BUILDDRAFTS=false hugo --quiet --buildDrafts Drafts=0
$ HUGO_BUILDDRAFTS=false hugo --quiet --buildDrafts Drafts=1
測試站只放了 1 篇標記 draft: true 的文章。v0.169.0 底下,即使指令明確帶 --buildDrafts,只要環境變數殘留 false,草稿就是不會被建出來。這種情境在 CI 很常見:某個共用的 base image 或 .gitlab-ci.yml 全域設了 HUGO_BUILDDRAFTS=false 當預設,個別 job 想臨時建草稿預覽就加 --buildDrafts,結果在 v0.169.0 完全沒用。v0.170.0 修正後,旗標真的能覆蓋掉繼承來的環境變數。

- CI 腳本若同時用環境變數設定一個基礎值、又用指令列旗標做個別覆寫(常見於共用 base image + per-job override),升級後行為會反過來,建議先在測試分支跑一次完整建置
- 設定檔或 Makefile 裡若還寫著
css.Sass transpiler: libsass,升級後建置會直接失敗,需要先確認已裝 Dart Sass 並改掉transpiler設定
四、影響分析:誰會被這次升級動到
純粹用 Markdown + 內建樣式處理、沒碰過 Sass 的站台,升級幾乎無感。regular binary 從以前到現在都是同一顆,這次只是把「extended 這個選項」拿掉,不影響沒用到它的人。
真正會被打到的兩群人:一群是還在用 transpiler: libsass 的舊設定檔,升級後建置直接紅字失敗;另一群是 CI 腳本同時依賴環境變數和旗標的,行為會悄悄改變而不一定馬上報錯,風險反而更隱蔽,建置可能照樣綠燈通過,只是產出的環境標籤或草稿數量跟預期不同。
對維運影響最大的其實是第三類:那些寫死 hugo_extended_*_linux-amd64.tar.gz 下載連結的安裝腳本。這些腳本不會失敗,因為檔名還在、下載照樣成功,直到真正呼叫 css.Sass 才爆炸,錯誤出現的位置離「版本升級」這個根因很遠,排查起來容易繞遠路。
- 先確認專案有沒有用到
transpiler: libsass(grep -r "libsass" config* layouts/) - 有用到 → 安裝 Dart Sass,把設定改成
transpiler: dartsass - 檢查 CI 腳本是否寫死
hugo_extended_開頭的下載檔名,確認下游邏輯沒有依賴「extended = 有 libsass」這個假設 - 若 CI 中環境變數與旗標同時存在,重新跑一次確認行為符合預期
五、對比與取捨:跟其他靜態網站產生器比起來
| 特性 | Hugo 0.170.0 | Eleventy | Zola |
|---|---|---|---|
| 核心語言 | Go | JavaScript | Rust |
| Sass/SCSS 支援 | 需外部 Dart Sass(CLI 或 npm 套件) | 依賴外部 build pipeline | 內建(也是 Rust 原生實作,無 extended 問題) |
| 單一 binary 分發 | ✅(v0.170.0 起唯一選項) | ❌(需 Node.js 環境) | ✅ |
| 建置速度(官方宣稱定位) | 快,大型站台常見選擇 | 中等,依外掛數量 | 快 |
Zola 從設計之初就沒有「extended/regular」這種分裂,因為它的 Sass 支援是 Rust 原生實作、靜態連結本來就是常態。Hugo 這次等於是往同一個方向靠攏,只是過程中會讓一部分舊使用者踩到設定檔相容性的坑。這不代表 Hugo 設計有問題,CGO 可選擇性編譯原本就是給需要額外原生函式庫的場景用的,只是維護兩套發行版的成本,到了這個階段被認為不划算。
限制也要講清楚:這次測試只涵蓋 linux-amd64 官方二進位,沒有測 Homebrew、Scoop、Snap 等套件管理通路打包的版本是否仍保留某種 extended 變體;也沒有測 Windows、macOS 平台的行為(release note 內容應該一致,但沒有逐一驗證)。
六、實務建議
- 搜尋專案內
transpiler: libsass,確認是否需要改用dartsass - 確認本機或 CI 容器已安裝 Dart Sass(
npm install -g sass或對應套件管理工具) - 檢查安裝腳本是否寫死
hugo_extended_*檔名,若有,改抓 regular 版(功能已相同) - 重新檢視 CI 中環境變數與旗標同時使用的地方,確認升級後行為符合預期
- 在測試分支跑一次完整建置,確認
hugo.Environment與草稿數量符合預期
適合現在就升的情境:純 Markdown 建站、已經改用 Dart Sass、CI 腳本單純只用其中一種設定方式(環境變數或旗標擇一)的站台,升級幾乎零風險,還能拿到 static 檔同步加速與 WASM image codec 修正等改進。
不建議馬上升的情境:還在維護老舊設定檔、短期沒空處理 Sass 遷移的站台,可以先鎖定 v0.169.0,排個時間處理完 libsass 遷移再升,反正 libsass 從 v0.153.0 就已經是 deprecated,遲早要面對。
七、結論
extended 版拔掉不是一次單純的瘦身,而是把一個「看起來還在、實際已經不同」的相容性陷阱留在下載頁上。靜態連結、動態連結這種底層差異平常不會有人去查,直到建置在 css.Sass 那步炸掉才回頭看版本。
值不值得升?純 Markdown 站台可以直接升,幾乎無感;用 Sass 的站台要先把 transpiler 改成 dartsass 再升,順便檢查 CI 腳本有沒有依賴環境變數和旗標同時生效的舊行為。後續觀察重點:官方是否會在未來某個版本把 hugo_extended_* 這個相容別名徹底拿掉,以及 Dart Sass 的建置速度是否會成為大型站台的新瓶頸。
還能抓到真的 CGO 編譯、支援 libsass 的 Hugo 嗎?
官方發行版不行,v0.170.0 起沒有任何官方二進位支援 libsass。要用 libsass 只能自行用舊版原始碼搭配 CGO 工具鏈編譯,但官方已不建議這條路。
不用 Sass 的站台需要改設定嗎?
不需要,純 Markdown 或只用內建樣式處理的站台升級後行為不變。
CI 腳本寫死抓 hugo_extended_* 檔名會怎樣?
下載不會失敗,檔名還在,但裡面已經是跟 regular 版相同的二進位,不支援 libsass;建議改抓不帶 extended 字樣的一般檔名。
旗標覆蓋環境變數的修正會影響所有旗標嗎?
release note 只點名 -e(environment)與 HUGO_ENVIRONMENT 這組互動,本次實測額外驗證了 --buildDrafts 與 HUGO_BUILDDRAFTS 也遵循同一套「旗標優先」邏輯,其餘旗標未逐一測試。
參考資料
- gohugoio/hugo v0.170.0 Release Notes(GitHub,2026-11-13)
- gohugoio/hugo v0.169.0 Release Notes(GitHub,2026-10-27)
- Hugo css.Sass 官方文件
- Hugo Installation 官方文件
這篇對你有幫助嗎?


發佈留言