編譯器跑得快,不會直接讓你的產品變快。
微軟去年公開把 TypeScript 編譯器以 Go 重寫的計畫後,社群討論一直沒停過。對長期被 tsc 拖慢 CI、被 IDE 卡頓折磨的團隊來說,這是好消息;但把它當成「升級就有感」的銀彈,恐怕會失望。在決定要不要把工具鏈整套換掉之前,值得先把問題拆清楚。
為什麼這次重寫值得關注
過去幾年,前端工具鏈大量轉向系統程式語言:esbuild 用 Go、SWC 與 Biome 用 Rust、Turbopack 也是 Rust。這些工具大多解決「轉譯」與「打包」的速度問題,但型別檢查仍然得回到 tsc,因為只有官方編譯器有完整且正確的型別語意。
這就形成一個尷尬的狀態:你可以用 esbuild 在毫秒內打包,但 tsc --noEmit 在大型 monorepo 上動輒跑幾分鐘。CI 等型別檢查的時間,往往比實際打包還長。
TypeScript 改用 Go 重寫,瞄準的就是這塊。官方公開示範時宣稱效能有數量級的提升,語意與舊版保持一致。對「型別檢查是 CI 瓶頸」的團隊而言,這是真正有感的改進,因為它不是換一個第三方近似實作,而是官方本身的引擎更快。
但快的不是你的產品
話說回來,工具鏈升級的效益常被高估。我們在報價或顧問會議時,通常會建議客戶先做兩件事,再決定要不要花成本遷移:
第一,量自己的 baseline。不是相信 benchmark,而是把 CI 拆開來看:安裝依賴、型別檢查、單元測試、打包、部署,分別佔多少時間。假設一個典型情境:CI 總共跑 8 分鐘,其中型別檢查只佔 40 秒——那把編譯器換掉,省的是那 40 秒,不是 8 分鐘。
第二,看你的痛點是 cold start 還是 incremental。新一代編譯器在全量檢查時優勢最明顯,但很多團隊真正的痛是「改一個檔案、IDE 卡半秒」,這部分牽涉到 language server 的 incremental 計算策略,跟編譯器底層語言不一定成正比。
還有相容性的代價。如果你用了一些依賴 tsc 行為細節的工具——例如某些自製的 transformer plugin、ts-node 的某些模式、或仰賴 Program API 的 lint 工具——切過去前要先盤點。重寫版會盡力保持語意一致,但生態系工具未必都跟得上。
// 示意:在決定遷移前,先量自己的數字
// 實際指令請參考官方文件
const before = await measure(() => runTsc('--noEmit'));
const after = await measure(() => runNewTsc('--noEmit'));
console.log({ before, after, ciTotal });
// 如果省下的時間,相對 ciTotal 不到個位數百分比
// 那這次遷移的價值可能在開發體驗,而不是 CI
我們的觀察
工具鏈會持續往系統語言遷移,這是趨勢,沒必要抗拒;但「跟進熱門技術」與「解決自己的瓶頸」是兩件事。如果你的團隊已經被型別檢查時間拖到不敢拆 PR、不敢開嚴格模式,那這次重寫是該認真評估的;如果只是覺得別人在用所以也想用,先去量你自己的 CI 數字,往往會發現真正該優化的是別的環節。技術選型的價值,從來不是來自工具本身有多快,而是來自它有沒有對準你現在最痛的那一段。
