優化 Zsh 啟動速度的老招:延遲執行
Zsh 啟動速度是一個 QoL 問題,優化它的速度不會讓你程式寫的更好,但是會讓你過的更開心。
很多東西其實是我們需要,但是我們不會馬上就用到,那優化方式顯而易見就是延遲執行等到有空再跑,這時候就要請出 zsh-defer 了,它的概念很簡單,把指令註冊到清單裡面登記給 zle(Zsh Line Editor),zle 等到閒置時就會自己執行這些東西,就這麼簡單。
另一種延遲執行的方式是用假的 function 代理(定義一個和指令同名的空殼函式,等第一次呼叫才載入真正的工具並且把指令轉交執行),zsh-defer 對比用假 function 代理的好處是,假的 function 在你第一次執行時一定會卡,zsh-defer 的 zle 則會自己初始化,而且永遠不會卡住終端。
zsh-defer 聽起來很完美,但是有些工具執行時不等 zle fire,就會發生找不到路徑的錯誤,這該怎麼解決呢?有兩種方案可以完成,第一種是針對每種工具各自的解法,如 VS Code 會對他自己開啟的 shell 注入環境變數 VSCODE_RESOLVING_ENVIRONMENT,那就在 .zshrc 裡面檢查:
_mise_activate() { eval "$(mise activate zsh)" }
if [[ -n $VSCODE_RESOLVING_ENVIRONMENT ]]; then
_mise_activate
else
zsh-defer _mise_activate
fi
另外一種是自己手寫路徑,每一個工具都在 zshrc 手動加入 PATH,自然也就沒有找不到路徑的問題。
兩種方法的選擇取決於你是外部工具多(VS Code 或是其他會呼叫指令的外部工具),還是內部工具多(node、Python、Rust 等等),不過真的需要這樣處理的內部工具也不多,主要是 nvm/mise 這種需要 eval 不直接提供 PATH 的管理軟體才會遇到。
附帶一提,用 time zsh -lic exit 分析 Zsh 效能沒有意義。你可以理解成網頁效能的 benchmark 從 DOMContentLoaded load SI TTI FMP LCP 一路演化,就是因為發現前面那些指標沒有真正意義,因此才又換了一個更有實質意義的指標作為標準,而 time zsh -lic exit 這個測試也是沒有意義的,請用 zsh-bench 測試你的 Zsh 效能。
