0%

【文章翻譯】Optimizing performance in Flutter web apps with tree shaking and deferred loading

【文章內容使用 Gemini 1.5 Pro 自動產生】

為 Flutter 網頁應用程式最佳化效能:使用 Tree Shaking 和延遲載入

為了提供最佳的使用者體驗,應用程式快速載入非常重要。透過縮減 Flutter 網頁應用程式的 JavaScript 捆綁包,可以改善其初始載入時間。Dart 編譯器包含 Tree Shaking 和延遲載入等功能,這兩者都可以縮減 JavaScript 捆綁包。本文將解釋它們的工作原理以及如何在應用程式中使用它們。

預設的 Tree Shaking

在編譯 Flutter 網頁應用程式時,JavaScript 捆綁包是由 dart2js 編譯器生成的。發行版本具有 最高級別的優化,其中包括對您的程式碼進行 Tree Shaking。

Tree Shaking 是一個消除無用程式碼的過程,它只包含保證會執行的程式碼。這表示您不必擔心應用程式中包含的函式庫的大小,因為未使用的類別或函數將被排除在編譯的 JavaScript 捆綁包之外。

若要查看 Tree Shaking 的實際運作方式:

  1. 建立一個 Dart 檔案 greeter.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
abstract class Greeter {
String greet(String name);
}

class EnglishGreeter implements Greeter {
String greet(String name) => 'Hello $name!';
}

class SwedishGreeter implements Greeter {
String greet(String name) => 'Hej $name!';
}

void main() {
print(EnglishGreeter().greet('World'));
}
  1. 在您的終端機中執行 dart2js -O4 greeter.dart,並查看生成的輸出檔案 out.js

在生成的 JavaScript 程式碼中,沒有任何對 SwedishGreeter 類別的引用,也沒有包含 Hej $name 字串,因為它在編譯器進行 Tree Shaking 時被移除。

編譯器只能透過靜態分析來找出哪些程式碼可達,哪些是無用程式碼。以以下範例為例,其中根據系統地區設定定義了 greeter

1
2
3
4
5
6
Locale locale = Localizations.localeOf(context);
if (locale.languageCode == 'sv') {
greeter = SwedishGreeter();
} else {
greeter = EnglishGreeter();
}

編譯器不知道使用者的系統地區設定,因此 EnglishGreeterSwedishGreeter 都包含在 JavaScript 捆綁包中。對於此類用例,延遲載入可以幫助縮減初始捆綁包的大小。

使用延遲載入僅在需要時載入程式碼

延遲載入(也稱為懶惰載入)允許您在需要時載入函式庫。它可以用於載入應用程式中很少使用的功能。請注意,延遲載入是 dart2js 的一項功能,因此這不適用於 Flutter 行動應用程式。在最簡單的情況下,將匯入的套件或檔案標記為延遲載入,並在使用它之前等待它載入:

1
2
3
4
5
6
import 'greeter.dart' deferred as greeter;

void main() async {
await greeter.loadLibrary();
runApp(App(title: greeter.EnglishGreeter().greet('World')));
}

編譯此程式碼將生成兩個 JavaScript 檔案。當在延遲匯入上呼叫 loadLibrary 時,它將載入 greeter 函式庫。

在 Flutter 中,所有內容都是 Widget,您可能想要使用 FutureBuilder。Widget 的 build 方法預期是同步的,因此您不能在 build 方法中對 loadLibrary 呼叫 await。但是,您可以在 build 方法中返回 FutureBuilder,也可以用它在函式庫載入時顯示不同的 UI:

1
2
3
4
5
6
7
8
9
10
11
12
import 'greeter.dart' deferred as greeter;

FutureBuilder(
future: greeter.loadLibrary(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Text(greeter.greet('World'));
} else {
return Text('Loading...');
}
},
)

若要親自嘗試(請查看 GitHub 上的完整範例),請打開 Chrome DevTools 並點擊 網路 標籤以檢查網路活動。重新載入頁面,查看函式庫何時載入和匯入。在以下螢幕截圖中,載入 main.dart.js_1.part.js 檔案是延遲的:

Flutter Gallery 支援 70 多種語言,但大多數使用者只使用一種語言。延遲載入本地化字串是使用此功能的絕佳方法。例如,在 Flutter Gallery 中實作本地化字串的延遲載入之後,應用程式的初始 JavaScript 捆綁包大小減少了一半。如果您的 Flutter 網頁應用程式中有很多本地化字串,請考慮延遲載入這些檔案。gen_l10n.dart 腳本 包含 --use-deferred-loading 旗標,可用於此目的(目前僅在 1.19 SDK master channel 上提供)。

這篇文章是關於我們在提高 Flutter Gallery 效能時所學到的知識的一部分。我希望您覺得它有用,並且學到了一些可以應用到您的 Flutter 網頁應用程式中的知識!


透過 Tree Shaking 和延遲載入最佳化 Flutter 網頁應用程式的效能 最初發佈在 Flutter 上的 Medium,人們在那裡透過突出顯示和回應這個故事來繼續討論。