Flutter Hot Reload 慢到 8 秒?開發時間成本計算與編譯效能改善方向

Published on: | Last updated:

最近在看 Flutter… Hot Reload 這個功能,本來是賣點。但好像很多人卡在這邊。

改個東西,等 8 秒。聽起來還好?一天下來,很可怕。

思考一下這個成本… 真的不只是那幾秒鐘而已。

重點一句話

Flutter 的 Hot Reload 如果變慢,不只是開發體驗變差,算下來一個工程師一年可能會讓公司多花掉一兩百萬台幣的隱形成本。問題通常不在 Flutter 本身,而是專案的寫法和設定。

這個「慢」,到底是怎麼虧錢的?

原文算了一筆帳,蠻驚人的。用美國的薪資來看。

一個 Flutter 開發者,平均薪水十萬美金。時薪大概 50 美金。

如果 Hot Reload 一次 8 秒。一天改個兩百次…很正常吧,調 UI 的時候。

8 秒 * 200 次 = 1600 秒。差不多 26 分鐘。

但真正的問題不是這 26 分鐘。是「等待」打斷了心流 [context switching]。你可能就去回個訊息、看一下別的東西,然後思緒要再拉回來,可能就要花掉好幾分鐘。

這樣一來一回,一天浪費掉 2-3 小時的專注時間,好像也不是不可能。

一天損失 200 美金。一年下來… 5 萬美金。差不多 160 萬台幣。

一個十人團隊,一年就燒掉一千多萬。只是因為 Hot Reload 很慢。這數字…嗯,有點誇張,但背後的道理是對的。

開發者等待 Hot Reload 的心流中斷示意
開發者等待 Hot Reload 的心流中斷示意

為什麼 Flutter 特別有感?

因為一切都是 Widget。跟原生開發的思維不太一樣。

  • Widget Tree 太深:一層包一層,像千層蛋糕。Hot Reload 要全部檢查一次,當然慢。
  • 狀態管理 [State Management]:這是大魔王。一個小地方狀態變了,結果整個頁面、甚至整個 App 都跟著重畫 [rebuild],那速度肯定上不來。
  • 各種資源:圖片、字體… 這些東西每次都要重新載入的話,也是個負擔。
  • 原生程式碼:如果你的專案混了很多平台原生碼 [platform-specific code],編譯時間也會被拖下去。

我自己是覺得,State Management 絕對是頭號戰犯。很多人為了方便,一個 `setState` 就搞定,但這通常就是災難的開始。

怎麼做:幾個可以動手的方向

與其說是「最佳實踐」,不如說是一些「別再這樣寫了」的提醒。很多時候,問題都出在一些小習慣上。

第一步:檢查你的 Widget 架構

這是最快,也最容易有成效的。核心概念就是:不要讓不該重畫的 Widget 一直重畫。

最簡單的武器就是 `const`。

只要一個 Widget 跟它的參數在編譯時期就能確定下來,就給它 `const`。這樣 Flutter 就知道「喔,這個東西不會變,Hot Reload 時直接跳過它」。

聽起來很基本,但超級多人會忘記。

在程式碼中加上 const 關鍵字來避免不必要的重建
在程式碼中加上 const 關鍵字來避免不必要的重建

改寫前 [Before]:


// 每次 parent 重建,底下全部跟著跑一次
class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          ComplexWidget(), // 重建
          AnotherComplexWidget(), // 重建
        ],
      ),
    );
  }
}
    

改寫後 [After]:


// 加上 const,這些 widget 就被快取了
class MyWidget extends StatelessWidget {
  const MyWidget({super.key}); // 建構子也 const

  @override
  Widget build(BuildContext context) {
    return const Scaffold( // const!
      body: Column(
        children: [
          ComplexWidget(), // 假設它也是 const
          AnotherComplexWidget(), // 假設它也是 const
        ],
      ),
    );
  }
}
    

光是這個動作,對於靜態為主的頁面,Hot Reload 時間可能就少掉一半以上。

第二步:搞定狀態管理 [State Management]

這部分水很深。BLoC、Provider、Riverpod、GetX... 各有各的擁護者。

但核心原則不變:讓狀態的更新,只影響到「真正需要」用到這個狀態的 Widget。

用 `Provider` 或 `Riverpod` 這類工具,可以比較精準地控制。例如 `Consumer` 或 `ref.watch` 只會監聽你指定的那個狀態,而不是整個物件。

官方的 Flutter.dev 文件其實寫得很清楚,但大家常常急著開發就忽略了。國外很多大神級開發者,像 Remi Rousselet (Riverpod 的作者),他會一再強調這種「分離」的重要性。

在台灣,我看社群討論比較多還是停留在「哪個好用」,比較少深入到對 build performance 的影響。但這真的很重要。


// 只更新需要的部分
Consumer<CartModel>(
  builder: (context, cart, child) {
    // 這個 Text 只會在 cart model 變動時重建
    return Text('Total price: ${cart.totalPrice}');
  },
)
    

跟直接在外面 `setState` 整個頁面相比,效能是天差地遠。

常見效能問題跟解法對照

我整理了一下,大概是這幾個問題循環。

常見問題 (The Pain) 直覺解法 (Quick Fix) 更好的解法 (The Real Fix)
只是改個顏色,整個頁面都在轉圈圈。 直接在最外層的 `StatefulWidget` 裡面用 `setState`。嗯...最快,也最糟。 把顏色變成一個狀態,用 `Provider`/`Riverpod` 管理,只讓那個 Widget `Consumer`。
我的 Widget Tree 長得跟聖誕樹一樣,五顏六色又複雜。 算了,不管了,能動就好...[很多人都這樣] 到處加上 `const`。然後把大的 Widget 拆成小的、獨立的 `StatelessWidget`。
只是加了幾張圖,Hot Reload 就慢了三秒。 把圖片壓縮一下。 檢查 `pubspec.yaml` 是不是把整個 `assets/` 資料夾都包進去了。只寫需要的路徑。還有,考慮用 SVG。
我的 IDE (Android Studio / VS Code) 跑起來好卡,感覺快不行了。 重開 IDE...[治標不治本] 增加 IDE 的記憶體分配 (例如 4GB 以上)。然後把 `.dart_tool` 跟 `build` 資料夾從檔案索引中排除。

第三步:優化你的開發環境和資源

有時候問題不在程式碼,在工具。

  • `pubspec.yaml`:不要寫 `assets/` 這種懶人包。明確指定 `assets/images/`、`assets/icons/`。你不會希望一堆用不到的測試圖片也被打包進去。
  • IDE 設定:幫 `Android Studio` 或 `VS Code` 多加點記憶體。Flutter DevTools 裡的 Performance tab 跟 Widget Inspector 是你的好朋友,學會看懂它們。
  • 圖片:能用 SVG 就用 SVG,不要放一堆 `1x`, `2x`, `3x` 的 PNG。圖片壓縮也是基本功。
優化前後 Hot Reload 時間大幅縮短的成果
優化前後 Hot Reload 時間大幅縮短的成果

一個實際的改善路線圖 [Roadmap]

如果真的要動手,可以這樣分階段。

第一週:評估 & 測量

  • 先計時。現在 Hot Reload 到底要多久?誠實地記錄下來。
  • 用 Flutter Inspector 打開,看看你的 Widget Tree 有多深。截圖存證。
  • 建立一個基準線。

第二週:簡單的勝利 [Quick Wins]

  • 把所有能加 `const` 的地方全部加上去。這是 CP 值最高的。
  • 整理 `pubspec.yaml` 裡的 assets。
  • 升級 Flutter 到最新的穩定版。

第三週之後:深入重構

  • 選定一個狀態管理方案 (如果還沒定),然後開始重構那些用 `setState` 的重災區。
  • 拆分那些過於龐大的 Widget。
  • 開始研究 `lazy loading`,讓不是馬上要用到的資源晚點再載入。

持續做下去,然後監控。這不是一次性的工作。

所以,結論是?

這件事好像沒有一個終極答案。寫 App 就是一個不斷取捨的過程。

但 Hot Reload 的速度,確實直接反應了專案的健康程度。它慢,通常代表你的程式碼架構有地方出問題了。把它當作一個警訊,而不是單純的「開發工具問題」。

花點時間在這些基礎建設上,長期來看,省下的不只是編譯時間,還有開發者的理智線... 還有公司的錢。

你覺得你的專案,最卡的地方是哪裡?是 Widget 太深,還是狀態管理一團亂?可以留言分享一下。

Related to this topic:

Comments

撥打專線 LINE免費通話