📦解決 SwiftSyntax 編譯超慢的問題
我過去對於推廣使用 Point-Free 的許多套件有所保留,因為使用 Swift Macros 來簡化語法,連帶依賴的 SwiftSyntax 會浪費大量的編譯時間。我甚至為了這個問題而換電腦。幸好自從 Xcode 16.4 以後獲得解決了!
在繼續 Swift Dependencies 推坑系列之前,我想先介紹一下對於開發體驗十分重要的東西:Prebuilt SwiftSyntax。
Swift Macros 的理想 vs 現實
2023 年,Swift Macros 作為 Swift 5.9 的一個重要功能推出,方便 library 開發者自行創造更簡便的語法。
Apple 的 frameworks 開始採用 Macros 簡化語法,例如 SwiftData 的 @Model
、@Query
,SwiftUI 的 @Entry
。
但是實務上,Swift Macros 並沒有像 property wrapper 等簡化語法的功能一樣被第三方開發者廣泛使用。一個實際的理由就是因為增加了明顯的編譯時間。
Swift Macros 的用意是提供簡單的語法,並且會自動被開展成較為複雜的版本。而為了做到產生語法的效果,Swift Macros 依賴於 SwiftSyntax 這個 library 去產生合法的 Swift 語法。
這個 SwiftSyntax 過去是以 Package 的方式來使用。換言之,一旦專案使用到任何 Swift Macros,就需要有 SwiftSyntax 的參與。SwiftSyntax 不僅會一併被加入專案原始碼,也要完整編譯整個 library。
編譯 SwiftSyntax 相當費時
SwiftSyntax 並不是一個小 library。在 Apple silicon 的 Mac 上編譯,需要至少一分鐘的編譯時間。在一些 CI server(包括 Xcode Cloud)上更是有機會延長數分鐘。這個問題困擾我的程度,甚至到了把 MacBook Air M2 換成 MacBook Pro M3 Max 這麼嚴重。
如果是 SwiftUI 的模組引用了使用 Swift Macros 的套件,那麼 SwiftSyntax 增加的編譯時間,基本上就可以破壞 Preview 即時更新的效果。
對於使用 library 的開發者來說,雖然能夠享受到優雅、簡化過的語法,但是增加許多編譯時間,完全得不償失。
開發者社群對於 Swift Macros 這樣的矛盾一直頗為無奈,也有一些開發者試圖自行編譯 SwiftSyntax 成 binary 與 xcframework。例如:
但這些都不是一勞永逸的辦法,最好還是要由 Apple 出面解決。