條件式載入資產,判斷 Hugo 頁面中是否包含指定元件(HasShortcode, .Store, .Scratch)
條件式載入資產是老生常談的問題,然而官方文檔依舊寫的七零八落,不自己摸索根本不能直觀的理解該怎麼做。本文介紹 Hugo 所有能用的頁面條件判斷方式,用於判斷頁面是否有指定的東西,包含
- HasShortcode
- .Store / .Scratch
目前只有這兩種方式可以跨模板判斷。
HasShortcode
HasShortcode 可以在模板的任何位置判斷當前頁面是否包含 shortcode,因為 Hugo 會先過一次 Markdown 文件,Markdown 之外的 shortcode 呼叫如 .Page.RenderString 則理所當然的不會被判斷。相關源碼在 page__content.go#L108-L124。
使用:
<!-- partial A -->
{{ if .HasShortcode }}
{{ with resources.Get "css/foo.css" }}
...
{{ end }}
{{ end }}
Store vs Scratch
.Scratch 已經被淘汰,他現在就是 .Store 的別名。
Store and Scratch
.Store 的 .Set / .Get 依賴於模板執行順序,不會提前 evaluate,因此你必須在所有最後的模板才用 .Store.Get "hasXXX" 來判斷是否載入該元件的資源。
使用:
<!-- partial A -->
{{ if .Param "someFunction" }}
{{ .Store.Set "func" true }}
{{ end }}
<!-- partial B -->
{{ if .Store.Get "func" }}
{{ with resources.Get "css/foo.css" }}
...
{{ end }}
{{ end }}
Shortcode + Store
shortcode 內部呼叫 .Store:這時候可以透過 trigger .Content 提前 evaluate Markdown,這樣就可以在 .Content 真正渲染前使用 .Get 方法。trigger 方式如文檔。注意只有由 Markdown 觸發的 .Store .Scratch 才有用如,因為我們是在 trigger .Content evaluate。
Store 的缺點
在 live reload 會有問題,因為重新載入之後 .Store 的 flag 狀態會保持 true 不會被重置為 false,造成只要 live reload 一次之後資產(CSS/JS)就不會被載入了。實際情況是只有當前刷新的頁面會被完整重新渲染,其他頁面則會因為部分刷新而缺少資產。
這是一個非常久且公認存在的 bug,直到當前版本 0.164.0 都持續存在。
Content 快取
觸發 .Content 提前渲染會不會造成任何問題?答案是不會。.Content 會被快取1,同一個 Page 在不同模板呼叫 10 次 .Content 都沒差,都是被快取的,但是文檔又沒講,到底為什麼連這麼重要的問題都是 undocumented?