在本程式碼實驗室中,您將移除未使用的不必要依附元件,提升下列應用程式的效能。

評估
建議您先評估網站成效,再進行最佳化。
- 如要預覽網站,請按下「View App」,然後按下「Fullscreen」
。
快點選你最喜歡的小貓!這個應用程式使用 Firebase 的即時資料庫,因此分數會即時更新,並與使用該應用程式的所有其他使用者同步。🐈
- 按下「Control + Shift + J」鍵 (在 Mac 上為「Command + Option + J」鍵) 開啟開發人員工具。
- 按一下 [網路] 分頁標籤。
- 勾選「停用快取」核取方塊。
- 重新載入應用程式。

載入這個簡單的應用程式,需要傳送將近 1 MB 的 JavaScript!
查看開發人員工具中的專案警告。
- 按一下「Console」分頁標籤。
- 確認
Filter輸入旁邊的層級下拉式選單中已啟用Warnings。

- 查看顯示的警告。

Firebase 是這個應用程式使用的其中一個程式庫,它會提供警告,讓開發人員知道不要匯入整個套件,而只匯入使用的元件。換句話說,這個應用程式中有未使用的程式庫,可以移除這些程式庫,加快載入速度。
有時,您可能使用了特定程式庫,但其實有更簡單的替代方案。本教學課程稍後會探討移除不必要程式庫的概念。
分析套裝組合
應用程式有兩個主要依附元件:
- Firebase:這個平台為 iOS、Android 或網頁應用程式提供多項實用服務。這裡使用即時資料庫,即時儲存及同步處理每隻小貓的資訊。
- Moment.js:公用程式庫,可讓您更輕鬆地在 JavaScript 中處理日期。每隻小貓的出生日期都會儲存在 Firebase 資料庫中,並使用
moment計算小貓的週齡。
為什麼只有兩個依附元件,套件大小卻接近 1 MB?其中一個原因是,任何依附元件都可能會有自己的依附元件,因此如果考量到依附元件「樹狀結構」的每個深度/分支,依附元件的數量會遠超過兩個。如果應用程式包含許多依附元件,就很容易在短時間內變得龐大。
分析套件組合,進一步瞭解情況。社群建構了許多不同的工具,可協助您完成這項工作,例如 webpack-bundle-analyzer。
這項工具的套件已做為 devDependency 包含在應用程式中。
"devDependencies": {
//...
"webpack-bundle-analyzer": "^2.13.1"
},
這表示可以直接在 webpack 設定檔中使用。在 webpack.config.js 的最開頭匯入:
const path = require("path");
//...
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
.BundleAnalyzerPlugin;
現在,請在檔案結尾的 plugins 陣列中,將其新增為外掛程式:
module.exports = {
//...
plugins: [
//...
new BundleAnalyzerPlugin()
]
};
應用程式重新載入時,您應該會看到整個套件的視覺化圖表,而不是應用程式本身。

雖然不像看小貓 🐱 那麼可愛,但還是非常實用。 將滑鼠游標懸停在任何套件上,會以三種不同方式顯示其大小:
| 統計資料大小 | 縮減或壓縮前的大小。 |
|---|---|
| 剖析後大小 | 套件編譯後,套件組合中實際套件的大小。webpack 第 4 版 (用於這個應用程式) 會自動壓縮已編譯的檔案,因此檔案大小會小於統計資料大小。 |
| Gzip 壓縮後的大小 | 套件經 gzip 編碼壓縮後的大小。這個主題會在另一份指南中說明。 |
使用 webpack-bundle-analyzer 工具,可以更輕鬆地找出未使用的或不必要的套件,這些套件在套件中占了很大比例。
移除未使用的套件
圖表顯示 firebase 套件不只包含資料庫,還包含許多其他內容。其中包含其他套件,例如:
firestoreauthstoragemessagingfunctions
這些都是 Firebase 提供的優質服務 (詳情請參閱說明文件),但應用程式並未使用這些服務,因此不必全部匯入。
還原 webpack.config.js 中的變更,再次查看應用程式:
- 從外掛程式清單中移除
BundleAnalyzerPlugin:
plugins: [
//...
new BundleAnalyzerPlugin()
];
- 現在,請從檔案頂端移除未使用的匯入項目:
const path = require("path");
//...
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
應用程式現在應該可以正常載入。修改 src/index.js,更新 Firebase 匯入項目。
import firebase from 'firebase';
import firebase from 'firebase/app';
import 'firebase/database';
現在重新載入應用程式時,不會顯示開發人員工具警告。開啟開發人員工具的「Network」面板,也會顯示套件大小大幅縮減:

套裝組合大小已縮減超過一半。Firebase 提供許多不同的服務,開發人員可以選擇只納入實際需要的服務。在這個應用程式中,只有 firebase/database 用於儲存及同步處理所有資料。firebase/app 匯入作業一律為必要,可為各項服務設定 API 介面。
許多其他熱門程式庫 (例如 lodash) 也允許開發人員選擇性匯入套件的不同部分。只要更新應用程式中的程式庫匯入項目,僅納入正在使用的項目,就能大幅提升效能,不必費太多功夫。
雖然套件大小已大幅縮減,但仍有許多工作要做!😈
移除不必要的套件
與 Firebase 不同,moment 程式庫的部分內容無法輕易匯入,但或許可以完全移除?
每隻可愛小貓的生日都會以 Unix 格式 (毫秒) 儲存在 Firebase 資料庫中。

這是特定日期和時間的時間戳記,以自 1970 年 1 月 1 日 00:00 UTC 起經過的毫秒數表示。如果目前的日期和時間可以採用相同格式計算,則可以建構一個小型函式,以週為單位找出每隻小貓的年齡。
一如往常,請盡量不要複製及貼上。首先,請從 src/index.js 的匯入項目中移除 moment。
import firebase from 'firebase/app';
import 'firebase/database';
import * as moment from 'moment';
Firebase 事件監聽器會處理資料庫中的值變更:
favoritesRef.on("value", (snapshot) => { ... })
在上方新增一個小型函式,用於計算指定日期起算的週數:
const ageInWeeks = birthDate => {
const WEEK_IN_MILLISECONDS = 1000 * 60 * 60 * 24 * 7;
const diff = Math.abs((new Date).getTime() - birthDate);
return Math.floor(diff / WEEK_IN_MILLISECONDS);
}
在這個函式中,系統會計算目前日期和時間 (new Date).getTime() 與出生日期 (birthDate 引數,已以毫秒為單位) 之間的毫秒差,並除以一週的毫秒數。
最後,您可以在事件監聽器中改用以下函式,移除所有 moment 例項:
favoritesRef.on("value", (snapshot) => {
const { kitties, favorites, names, birthDates } = snapshot.val();
favoritesScores = favorites;
kittiesList.innerHTML = kitties.map((kittiePic, index) => {
const birthday = moment(birthDates[index]);
return `
<li>
<img src=${kittiePic} onclick="favKittie(${index})">
<div class="extra">
<div class="details">
<p class="name">${names[index]}</p>
<p class="age">${moment().diff(birthday, 'weeks')} weeks old</p>
<p class="age">${ageInWeeks(birthDates[index])} weeks old</p>
</div>
<p class="score">${favorites[index]} ❤</p>
</div>
</li>
`})
});
現在,請重新載入應用程式,並再次查看「Network」(網路) 面板。

套件大小再次縮減超過一半!
結論
完成本程式碼實驗室後,您應該已充分瞭解如何分析特定套件,以及移除未使用或不需要的套件為何如此實用。開始使用這項技術最佳化應用程式之前,請務必瞭解,在大型應用程式中,這項技術可能會更複雜。
關於移除未使用的程式庫,請嘗試找出套件中哪些部分正在使用,哪些部分未使用。如果某個套件看起來很神秘,似乎未在任何地方使用,請退一步檢查哪些頂層依附元件可能需要該套件。請試著找出方法,盡可能將兩者分離。
移除不必要的程式庫時,情況可能會稍微複雜一些。請務必與團隊密切合作,看看是否有機會簡化部分程式碼集。在這個應用程式中移除 moment 看似每次都是正確的做法,但如果需要處理時區和不同的語言代碼,該怎麼辦?或者,如果日期操作更複雜,該怎麼辦?在操作及剖析日期/時間時,事情可能會變得非常棘手,而 moment 和 date-fns 等程式庫可大幅簡化這項作業。
凡事都有取捨,因此請務必評估是否值得花費心力,推出自訂解決方案,而不是依賴第三方程式庫。