在本程式碼研究室中,請移除所有未使用的多餘依附元件,藉此提升下列應用程式的效能。
測量
建議您先評估網站成效,再進行最佳化。
- 如要預覽網站,請按下「查看應用程式」,然後按下「全螢幕」圖示
。
請按一下你最喜歡的小貓!這個應用程式使用 Firebase 的即時資料庫,因此分數會即時更新,並與使用應用程式的其他人同步。🐈
- 按下 `Control+Shift+J` 鍵 (在 Mac 上為 `Command+Option+J` 鍵) 開啟開發人員工具。
- 按一下 [網路] 分頁標籤。
- 選取「停用快取」核取方塊。
- 重新載入應用程式。
載入這個簡單的應用程式時,系統會傳送將近 1 MB 的 JavaScript!
查看開發人員工具中的專案警告。
- 按一下「控制台」分頁標籤。
- 確認
Filter
輸入內容旁邊的層級下拉式選單中已啟用Warnings
。
- 查看顯示的警告。
Firebase 是這個應用程式使用的程式庫之一,它會提供警告,提醒開發人員不要匯入整個套件,只匯入使用的元件。換句話說,這個應用程式中有未使用的程式庫,可以移除以加快載入速度。
此外,有時您可能會使用特定程式庫,但其實有更簡單的替代方案。本教學課程稍後會探討如何移除不必要的程式庫。
分析套件
應用程式有兩個主要依附元件:
- Firebase:這個平台提供許多實用服務,適用於 iOS、Android 或網頁應用程式。這裡使用即時資料庫,即時儲存及同步處理每隻小貓的資訊。
- Moment.js:實用程式庫,可簡化 JavaScript 中的日期處理作業。每隻小貓的出生日期都會儲存在 Firebase 資料庫中,並用來計算牠們的週齡。
moment
為什麼只有兩個依附元件,套件大小卻將近 1 MB?其中一個原因是,任何依附元件本身也可能會有自己的依附元件,因此如果考慮依附元件「樹狀結構」的每個深度/分支,依附元件數量就不只兩個。如果包含許多依附元件,應用程式很快就會變大。
分析 bundler,進一步瞭解發生了什麼事。社群開發了許多不同的工具,可協助您完成這項作業,例如 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 版 (本應用程式使用此版本) 會自動縮減編譯後的檔案,因此檔案大小會小於統計資料大小。 |
Gzipped size | 以 gzip 編碼壓縮後,套件的大小。這個主題會在另一份指南中說明。 |
使用 webpack-bundle-analyzer 工具,可輕鬆找出佔據軟體包大部分空間的未使用或不必要套件。
移除未使用的套件
從視覺化結果可以看出,firebase
套件包含的內容不只資料庫,還有許多其他項目。當中包含其他套件,例如:
firestore
auth
storage
messaging
functions
這些都是 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';
現在重新載入應用程式時,開發人員工具警告不會顯示。開啟開發人員工具的「網路」面板,也會顯示組合大小的顯著縮減:
移除超過一半的套裝組合大小。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
等程式庫可大幅簡化這項作業。
所有事物都是一種取捨,因此請務必評估是否值得投入複雜度和心力,推出自訂解決方案,而不是依賴第三方程式庫。