在本程式碼研究室中,您將移除所有未使用的和不需要的依附元件,以提升下列應用程式的效能。
測量
建議您先評估網站的效能,再進行最佳化。
- 如要預覽網站,請按下「View App」。然後按下「Fullscreen」圖示 。
請按一下你最喜歡的小貓咪!這個應用程式會使用 Firebase 的即時資料庫,因此分數會即時更新,並與使用該應用程式的其他使用者同步。🐈
- 按下 Control+Shift+J 鍵 (或在 Mac 上為 Command+Option+J 鍵) 開啟開發人員工具。
- 按一下 [網路] 分頁標籤。
- 勾選「Disable cache」核取方塊。
- 重新載入應用程式。
為載入這個簡易應用程式,系統準備了將近 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 版 (這個應用程式會使用) 自動壓縮已編譯的檔案,因此小於統計資料大小。 |
Gzip 壓縮大小 | 套件使用 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 起經過的毫秒數表示。如果可以使用相同格式計算目前的日期和時間,就可以建立一個小函式,以便以星期為單位找出每隻小貓的年齡。
如往常一樣,請勿在操作時複製貼上內容。首先,請從 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
等程式庫可大幅簡化這項作業。
凡事都需要權衡利弊,因此請務必評估是否值得投入心力和時間,推出自訂解決方案,而非仰賴第三方程式庫。