我的 Hugo 工作流程

(Photo by Christin Hume on Unsplash)

高中時曾任校刊社社長,也許對於出版不會太陌生。從 2017 年開始轉換使用 Hugo,逐步打造相對應的工作流程與工具,在這裡做個紀錄。不論入門或活用,希望大家能從中獲得能為自己提升工作效率的片段 :)

優缺點比較

當時採用以及現今繼續採用 Hugo 作為 blog 基礎系統的幾個優點:

  • 開放原始碼 - https://github.com/gohugoio/hugo
  • 開放格式
    • 從筆記整理、草稿撰寫、到 Hugo 內容產出、甚至整理投影片,全程得以使用共通的開放格式 Markdown,節省許多資料轉換時間。
    • 內容檔案格式為純文字 (Front Matter + Markdown),未來若需要轉換格式有出路
    • 內容檔案格式為純文字,搭配版本控制或檔案同步機制,可以自己跨平台、任選編輯器
    • 原始內容可以放進版本控制、同時達成異地備份
  • 當時觀察了好一陣子,Hugo 使用人數夠多且呈現增加趨勢,不會太快變成孤兒(不會太快再轉換一次)
  • 產出為靜態檔案,不需要維護特定規格的主機,找個 GitHub PagesAmazon S3 丟上去後設定 DNS 指向即可
  • (各種意義上的節省時間)(例如在 Macbook Air (M1, 2020)build 343 pages 只需要 1077 ms,平均每頁花費 3.14 ms)
  • 有指令列工具 (CLI),方便進行自動化
  • 擴充套件偏少(我覺得是優點,不會犧牲「快」)

缺點:

  • 一起參與協作的同伴,有學習門檻。學習 Markdown 等語法和作業流程

編輯器

Visual Studio Code (VSCode)

Hugo 對各種編輯器都有社群貢獻的一些擴充套件

我主要在 macOS 上使用 Visual Studio Code 來編輯 Hugo 的內容檔案。沒特地安裝 Hugo 控制相關套件(啊就 CLI 控),倒是安裝了些 Hugo、Markdown 語法周邊:

關於輸入圖檔路徑以及預覽,還在找尋其他有效率的做法,目前是盡量固定檔名命名規則,然後大量複製貼上 ![](/img/2021/2021-06-19-hugo-workflow/filename_here.png),接著到 Hugo 在地預覽(瀏覽器)上查看,希望未來有機會直接在編輯器內預覽。

Joplin

在某些場合不方便開啟電腦、或來不及開啟電腦時,我會使用跨平台的 Joplin 來編輯 Markdown,或是先快速做筆記片段暫存。等到整理文章時再來剪貼統整。之後再另外準備一些文章來討論 Joplin。

Joplin 也是開源軟體,可以達成跨平台,所以我在 Android phone、iPhone、iPad、Macbook Pro/Air、Windows 都可以同步筆記,繼續下一個階段的編輯整理動作。

Byword

在開始使用 Joplin 之前,使用過一小段時間的 Byword。目的相同,需要跨平台、任何裝置順手抓來就要可以快速進入做筆記的狀態,然後不用擔心跨裝置之間筆記同步掉資料的問題。且 Byword 無法運作在 Android 裝置上,這有時候有點困擾,因為出差時的主力機是 Android。

Obsidian

身邊陸續越來越多朋友跟我推薦 Obsidian,果然一開起來玩就停不下來。雖然不是開源軟體,但我的底線是開放的資料格式。我很期待運用 Obsidian 插入圖片後可以立即預覽的功能來編輯 Hugo 內容檔案,但至少食譜類的筆記已經往這邊移動了。但目前無法成為主力,因為只能在電腦上操作,行動裝置上還未有公開的版本。再觀察看看。

Hugo

環境設定 config.toml

設定檔可以多爬 Hugo 官方文件,以及 Hugo 官方 Discourse 討論區

一開始搞不清楚要在哪裡設定,但多看幾個文件後,可以鎖定幾個目錄位置,每個都動手設定看看,會比較快上手。

因為想練習英文寫作,所以很貪心地從一開始就將手上的 Hugo 往多國語系方向做設定(也為後來的某些客服系統打下基礎)。多國語系的架構、對應、翻譯、片段更新與維護,還是個值得研究的題目。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
[languages]
  [languages.en]
    LanguageName = "English"
    weight = 1

    [[languages.en.menu.main]]
    url    = "/about"
    name   = "About"
    weight = 5 
    [[languages.en.menu.main]]
    url    = "/notes/aws/products/"
    name   = "AWS Product Lists"
    weight = 10   
    [[languages.en.menu.main]]
    url    = "/notes/aws/"
    name   = "AWS Notes"
    weight = 20

  [languages.zh]
    LanguageName = "中文"
    weight = 2

    [[languages.zh.menu.main]]
    url    = "/about"
    name   = "關於"
    weight = 5

    [[languages.zh.menu.main]]
    url    = "/notes/aws/products/"
    name   = "AWS 產品清單"
    weight = 10

    [[languages.zh.menu.main]]
    url    = "/notes/aws/"
    name   = "AWS 筆記"
    weight = 20      

內容分類 content

目前使用了兩種內容:postnote。前者紀錄隨著時間順序而興起撰文者,後者嘗試相互連結形成網狀結構,也許會往 Digital Garden 方向整理(從清理蜘蛛網,到種花種草?!)。

我也建立了個別的 archetypes 檔案、以及個別的 create new shell scripts 對應到 postnote 兩種內容格式。

以下是 create new post 的 shell 範例:(若你沒有將圖檔依照各篇文章用目錄區隔開的需求,可以忽略這個範例,直接 hugo new 即可)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/bin/sh

# If a command fails then the deploy stops
set -e

POSTNAME=$1
THISYEAR=`date +'%Y'`
TODAY=`date +'%Y-%m-%d'`

POSTPATH="${THISYEAR}/${TODAY}-${POSTNAME}"
IMGFOLDER="./static/img/${POSTPATH}/"
NEWPOSTZH="posts/${POSTPATH}.zh.md"
NEWPOSTEN="posts/${POSTPATH}.en.md"

echo "[  ] Initing..."
echo "THISYEAR = "${THISYEAR}
echo "TODAY = "${TODAY}
echo "POSTPATH = "${POSTPATH}
echo "IMGFOLDER = "${IMGFOLDER}
echo "NEWPOSTZH = "${NEWPOSTZH}
echo "NEWPOSTEN = "${NEWPOSTEN}
echo

# Create static image folder
mkdir -p ${IMGFOLDER}
echo "[OK] mkdir -p ${IMGFOLDER}"
echo

# Create hugo new post
hugo new ${NEWPOSTZH}
echo "[OK] hugo new ${NEWPOSTZH}"
echo

hugo new ${NEWPOSTEN}
echo "[OK] hugo new ${NEWPOSTEN}"
echo

最後更新 lastmod

我是將 blog 當作筆記系統的延伸,所以常常有個想法、或想到之間的關聯性等等,就會回頭做些修改或調整,因此希望能呈現出該文章建立與最後一次修改的日期。參考了這幾篇文章,實作了 lastmod 這個功能。

自定義 shell aliases and functions

參考自 Christian Mohn 的工作流程,稍作修改成為自己的版本。

若大家有興趣,之後我會更新在我的 dotfiles.aliases.local.example 裡頭(現在 dotfiles 裡頭因為 Apple Silicon 而一片混亂中,敬請小心服用 XDD)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
###################################################################################
# Blog Operation: Hugo
###################################################################################

PATH_BLOG=~/projects/ernestchiang/www
PATH_DEFAULT_SCREENCAPTURE="/Users/dwchiang/Dropbox/Screenshots"
alias blogd="cd '$PATH_BLOG'"

function blogserv() {
    cd $PATH_BLOG
    open "/Applications/Google Chrome.app" http://localhost:1313
    hugo server -D -F -w
}

function hugonew() {
    cd $PATH_BLOG && ./hugo-new-post.sh $1 && code .
}

function move-image-here() {
    mv ~/Downloads/image.jpg $(pwd -P)/index.jpg
}

因為在編輯文章時,有時需要大量螢幕截圖(例如每年年底 AWS re:Invent Keynote 筆記),每次螢幕截圖後還需要手動搬移檔案到 Hugo 專案的 static/img/年份/該篇文章專屬目錄 底下,加上有時還要做轉檔與壓縮優化等步驟,實在頗累人。後來索性將 Dropbox Screenshots 關閉,但沿用 ~/Dropbox/Screenshots 目錄路徑為預設值,同時新增一個小工具,當我在編輯某篇文章時,將預設儲存螢幕截圖的目錄,改成我的 Hugo 靜態檔案存放的對應路徑,用完再切回預設目錄。

Script 中使用的 info/success,大家替換成 echo 即可。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
###################################################################################
# Screen Capture Location
###################################################################################

function scapture-here() {
    info 'Changing default screencapture location from:'
    defaults read com.apple.screencapture location

    defaults write com.apple.screencapture location $(pwd -P)
    success 'Changed default screencapture location to:'
    defaults read com.apple.screencapture location

    info 'Remember to execute `screencapture-default`'
}

function scapture-default() {
    info 'Changing default screencapture location from:'
    defaults read com.apple.screencapture location

    defaults write com.apple.screencapture location ${PATH_DEFAULT_SCREENCAPTURE}
    success 'Changed default screencapture location to:'
    defaults read com.apple.screencapture location
}

圖片 Images

使用 ImageOptim 讓圖片載入加速。

圖片來源主要是 Unsplash 或是個人出差出遊累積的大量照片(早期出門一天平均產生一兩千張照片,近年有比較收斂些)(好啦,都是拍吃的或是拍飛機居多,哈哈)。每篇文章會特地做 ogimage 以及 twitter card 處理,都在 Front Matter 搞定。你說偷懶、沒空的時候怎麼辦?身為一位負責任的工程師,凡走過必留下預設值 :p

工作流程

(2016 拍攝於西班牙馬德里一家書店,那天會議下班後原本想去的圖書館沒開放。)

前置作業

  • 閱讀,大量閱讀 ,這部份另開一局做拆解。基本流程設計是從閱讀後的筆記與總結中,抽取出可以轉寫成文的靈感,放入待辦清單中。
  • 筆記,剛才有提過,目前主力使用 Joplin 搭配 Dropbox 同步,有在考慮 Joplin Server。
  • 筆記,另外還有使用 Instapaper 等工具,待另開一文分享。
  • 紙本筆記本,從小學開始我身邊一定都會帶或大或小的紙本筆記本,也曾一度用便條紙做實驗,直到遇到 FIELD NOTES 之後就沒換過了。對我來說大小適中,我通常使用 Original Dot-Graph 或是 Original Graph Paper 方便書寫時對齊。通常都趁著 Black Friday 進一些庫存。
  • 待辦清單,之前使用 OmniFocus ,但後來為了完整跨平台與協作改用另一套。

作業中

  • 從待辦清單中安排一個時段,撰寫一個寫作主題,例如本篇。
  • 接著在 CLI 中開始建立 Hugo 內容檔案,並將對應該篇文章的靜態圖檔目錄建立起來。未來若覺得 slug 想要修改,直接在 Front Matter 中修改即可,檔名和目錄名稱就不做更動,例如本篇我就從 hugo-workflow 修改成 my-hugo-workflow
  • 或是想要回頭修改既有內容檔案,則快速切換到 Hugo 專案目錄。
1
2
3
4
5
6
❯ hugonew hugo-workflow

or

❯ blogd
❯ code .
  • 開啟本地端預覽,
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
❯ blogserv
Start building sites …

                   | EN  | ZH
-------------------+-----+------
  Pages            | 123 | 220
  Paginator pages  |   6 |  18
  Non-page files   |   2 |   2
  Static files     | 487 | 487
  Processed images |   0 |   0
  Aliases          |  65 |  83
  Sitemaps         |   2 |   1
  Cleaned          |   0 |   0

Built in 1077 ms
Watching for changes in /Users/dwchiang/projects/ernestchiang/www/{archetypes,content,data,layouts,static,themes}
Watching for config changes in /Users/dwchiang/projects/ernestchiang/www/config.toml
Environment: "development"
Serving pages from memory
Running in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender
Web Server is available at http://localhost:1313/ (bind address 127.0.0.1)
Press Ctrl+C to stop

Change detected, rebuilding site.
2021-06-19 15:14:59.831 +0800
Source changed "/Users/dwchiang/projects/ernestchiang/www/content/posts/2021/2021-06-19-hugo-workflow.zh.md": WRITE
Total in 374 ms
  • 因為這個 terminal 已被 hugo server 使用中,所以使用 iTerm2 Cmd + Shift + T 開啟同一路徑在另一個分頁。

  • 切換到 Hugo 專案中的靜態圖檔目錄後,
1
❯ scapture-here
  • 暫離、或是完成編輯,不再需要將螢幕截圖傳送到靜態圖檔目錄:
1
❯ scapture-default
  • 書寫時,從前述各個筆記系統搜尋相關材料,盡力讓相關的資訊或知識藉由 URL 關聯起來,方便自己或讀者交叉參照。
  • 相比於 WordPress 之類的系統,Hugo 讓我專注在內容寫作。
  • 完成草稿後,使用 Hugo 在地預覽模式閱讀個幾遍,若內容有值得標記畫底線之處,使用 自定義的 Hugo Shortcode 來畫底線,範例可以參考這一篇 AWS re:Invent Keynote 筆記

後製作業

  • 初版內容整理完成後,會再抽空多看幾次。檢查中英文版本是否能正確切換、檢查站內相對應連結能否順利抵達、回顧寫作過程中有沒有觀察到新的需求,要來更新這個 Hugo 工作流程,讓未來的自己更有效率(效率偏執但應該還不到狂,我有導入適量的偷懶來做平衡(炸 XDD)。
  • Blog 主要是寫給自己(以及未來的家人?!)看的,倒也不追求發表速度(Hugo 很快,但不急),對於內容的查證相對比較在意。
  • 抽空批次讓 ImageOptim 整理一下圖檔們。
  • 版本控制、備份與部署。
  • 目前是部署到 GitHub Pages 然後搭配自己的 domain name。未來也許會試試看 Amazon S3 + CloudFront 玩些變化。

後記

Hugo 以及這套個人工作流程,不一定適合每一個人(倒是,這個句型幾乎適合每一個場景)。若您對其中哪個環節感興趣,歡迎一起交流討論,一起增進效率 :)

comments powered by Disqus