移除用不到的程式碼

在本程式碼研究室中,移除任何未使用和不需要的依附元件,改善下列應用程式的效能。

應用程式螢幕截圖

測量

建議您先評估網站的成效,再加入最佳化調整。

  • 如要預覽網站,請按下「查看應用程式」,然後按下「全螢幕」圖示 全螢幕

快點選喜愛的小貓吧!此應用程式會使用 Firebase 的即時資料庫,因此分數會即時更新,並與該應用程式的所有使用者同步。🐈

  1. 按下 `Control+Shift+J 鍵 (在 Mac 上為 Command+Option+J 鍵) 開啟開發人員工具。
  2. 按一下 [網路] 分頁標籤。
  3. 勾選「停用快取」核取方塊。
  4. 重新載入應用程式。

原始組合大小為 992 KB

已產生將近 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 Bundle 分析工具

這可不像看到小貓一樣可愛,但為你提供極為實用的資訊。 將滑鼠遊標懸停在任一套件上,便會以三種不同方式顯示套件的大小:

統計資料大小 未壓縮或壓縮前的大小。
剖析大小 套件編譯後實際套件的大小。第 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」面板後,還會顯示套件大小大幅縮減:

套件大小縮減至 480 KB

已移除超過一半的組合大小。Firebase 提供多種不同的服務,讓開發人員可以選擇只納入實際需要的服務。在此應用程式中,只有 firebase/database 用於儲存及同步處理所有資料。您必須一律使用 firebase/app 匯入功能,以便為各項不同的服務設定 API 介面。

其他許多熱門程式庫 (例如 lodash) 也可讓開發人員選擇性匯入套件的不同部分。您不必耗費太多工作時間,在應用程式中更新程式庫匯入作業,只納入正在使用的項目,可大幅提升效能。

雖然套件大小已大幅縮減,但仍需花費更多心力!😈

移除不需要的套件

與 Firebase 不同,雖然某些 moment 程式庫的匯入作業無法輕鬆完成,但也許可以完全移除?

每個可愛小貓的生日都會以 Unix 格式 (毫秒) 儲存在 Firebase 資料庫中。

以 Unix 格式儲存的出生日期

這是特定日期和時間的時間戳記,以世界標準時間 1970 年 1 月 1 日 00:00 起經過的毫秒數表示。如果可以以相同格式計算目前的日期和時間,則可以建構一個小型函式來找出每隻小貓在數週的年齡。

一如往常,請按照此步驟嘗試複製及貼上。首先,請將 momentsrc/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」面板。

套件大小縮減至 225 KB

套裝組合的大小再縮減了一半以上!

結語

透過本程式碼研究室,您應該會瞭解如何分析特定套件,以及移除未使用或不需要套件的好處。在開始使用這項技術最佳化應用程式之前,請特別注意,這在大型應用程式中可能會非常複雜

關於移除未使用的程式庫,請嘗試找出使用套件的哪些部分以及哪些部分未使用。針對看起來並未在任何地方使用的神秘套件,您可以退一步,檢查哪些頂層依附元件可能需要這個套件。試著找出彼此分離的方法

移除不需要的程式庫時,可能會遭遇更複雜的問題。請務必與團隊密切合作,確認是否有可能簡化程式碼集的部分。從這個應用程式中移除 moment 看起來是每次都沒問題,但如果需要處理時區和不同語言代碼的情況,該怎麼辦?或者,如果有更複雜的日期操控呢?處理及剖析日期/時間時可能變得不太容易,而 momentdate-fns 等程式庫會大幅簡化這項作業。

所有功能都要權衡利弊,要評估推出自訂解決方案 (而非依賴第三方程式庫) 是否值得這麼做。