在本程式碼研究室中,移除任何未使用和不需要的依附元件,改善下列應用程式的效能。
測量
建議您先評估網站的成效,再加入最佳化調整。
- 如要預覽網站,請按下「查看應用程式」,然後按下「全螢幕」圖示 。
快點選喜愛的小貓吧!此應用程式會使用 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()
]
};
應用程式重新載入時,您應該會看到整個套件的視覺化效果,而非應用程式本身。
這可不像看到小貓一樣可愛,但為你提供極為實用的資訊。 將滑鼠遊標懸停在任一套件上,便會以三種不同方式顯示套件的大小:
統計資料大小 | 未壓縮或壓縮前的大小。 |
---|---|
剖析大小 | 套件編譯後實際套件的大小。第 4 版的 webpack (此應用程式使用) 會自動壓縮已編譯的檔案,因此這個值會小於統計資料大小。 |
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';
現在應用程式重新載入時,系統不會顯示開發人員工具警告。開啟開發人員工具的「Network」面板後,還會顯示套件大小大幅縮減:
已移除超過一半的組合大小。Firebase 提供多種不同的服務,讓開發人員可以選擇只納入實際需要的服務。在此應用程式中,只有 firebase/database
用於儲存及同步處理所有資料。您必須一律使用 firebase/app
匯入功能,以便為各項不同的服務設定 API 介面。
其他許多熱門程式庫 (例如 lodash
) 也可讓開發人員選擇性匯入套件的不同部分。您不必耗費太多工作時間,在應用程式中更新程式庫匯入作業,只納入正在使用的項目,可大幅提升效能。
雖然套件大小已大幅縮減,但仍需花費更多心力!😈
移除不需要的套件
與 Firebase 不同,雖然某些 moment
程式庫的匯入作業無法輕鬆完成,但也許可以完全移除?
每個可愛小貓的生日都會以 Unix 格式 (毫秒) 儲存在 Firebase 資料庫中。
這是特定日期和時間的時間戳記,以世界標準時間 1970 年 1 月 1 日 00:00 起經過的毫秒數表示。如果可以以相同格式計算目前的日期和時間,則可以建構一個小型函式來找出每隻小貓在數週的年齡。
一如往常,請按照此步驟嘗試複製及貼上。首先,請將 moment
從 src/index.js
的匯入項目中移除。
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
等程式庫會大幅簡化這項作業。
所有功能都要權衡利弊,要評估推出自訂解決方案 (而非依賴第三方程式庫) 是否值得這麼做。