Hapus kode yang tidak digunakan

Dalam codelab ini, tingkatkan performa aplikasi berikut dengan menghapus dependensi yang tidak digunakan dan tidak diperlukan.

Screenshot aplikasi

Ukur

Sebaiknya ukur terlebih dahulu performa situs sebelum menambahkan pengoptimalan.

  • Untuk melihat pratinjau situs, tekan Lihat Aplikasi. Lalu tekan Layar Penuh layar penuh.

Lanjutkan dan klik anak kucing kesayangan Anda! Realtime Database Firebase digunakan dalam aplikasi ini. Itulah sebabnya skor diperbarui secara real time dan disinkronkan dengan setiap orang yang menggunakan aplikasi tersebut. 🐈

  1. Tekan `Control+Shift+J` (atau `Command+Option+J` di Mac) untuk membuka DevTools.
  2. Klik tab Network
  3. Centang kotak Disable cache.
  4. Muat ulang aplikasi.

Ukuran paket asli 992 KB

JavaScript senilai hampir 1 MB sedang dikirimkan untuk memuat aplikasi sederhana ini!

Lihat peringatan project di DevTools.

  • Klik tab Konsol.
  • Pastikan Warnings diaktifkan di dropdown level di samping input Filter.

Filter peringatan

  • Lihat peringatan yang ditampilkan.

Peringatan konsol

Firebase, yang merupakan salah satu library yang digunakan dalam aplikasi ini, berfungsi sama dengan memberikan peringatan yang memberi tahu developer agar tidak mengimpor seluruh paketnya tetapi hanya komponen yang digunakan. Dengan kata lain, ada library tidak terpakai yang dapat dihapus dalam aplikasi ini agar dapat dimuat lebih cepat.

Ada kalanya library tertentu digunakan, tetapi mungkin ada alternatif yang lebih sederhana. Konsep penghapusan library yang tidak diperlukan akan dibahas nanti dalam tutorial ini.

Menganalisis paket

Ada dua dependensi utama dalam aplikasi:

  • Firebase: platform yang menyediakan sejumlah layanan yang berguna untuk aplikasi iOS, Android, atau web. Di sini, Realtime Database-nya digunakan untuk menyimpan dan menyinkronkan informasi untuk setiap anak kucing secara real time.
  • Moment.js: library utilitas yang mempermudah penanganan tanggal dalam JavaScript. Tanggal lahir setiap anak kucing disimpan dalam database Firebase, dan moment digunakan untuk menghitung usianya dalam beberapa minggu.

Bagaimana dua dependensi saja dapat berkontribusi pada ukuran paket yang hampir 1 MB? Salah satu alasannya adalah setiap dependensi pada akhirnya dapat memiliki dependensinya sendiri, jadi ada lebih dari dua dependensi jika setiap kedalaman/cabang "hierarki" dependensi dipertimbangkan. Sangat mudah bagi aplikasi untuk menjadi besar relatif lebih cepat jika banyak dependensi disertakan.

Lakukan analisis pemaket untuk mendapatkan gambaran yang lebih baik tentang apa yang terjadi. Ada berbagai alat buatan komunitas yang dapat membantu melakukannya, seperti webpack-bundle-analyzer.

Paket untuk alat ini sudah disertakan dalam aplikasi sebagai devDependency.

"devDependencies": {
  //...
  "webpack-bundle-analyzer": "^2.13.1"
},

Ini berarti dapat digunakan secara langsung di file konfigurasi webpack. Impor di awal webpack.config.js:

const path = require("path");

//...
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
  .BundleAnalyzerPlugin;

Sekarang tambahkan sebagai plugin di bagian paling akhir file dalam array plugins:

module.exports = {
  //...
  plugins: [
    //...
    new BundleAnalyzerPlugin()
  ]
};

Saat aplikasi dimuat ulang, Anda akan melihat visualisasi seluruh paket, bukan aplikasi itu sendiri.

Penganalisis Paket Webpack

Tidak secantik melihat beberapa anak kucing 👀, tapi tetap sangat membantu. Mengarahkan kursor ke salah satu paket akan menunjukkan ukurannya yang direpresentasikan dalam tiga cara berbeda:

Ukuran statistik Ukuran sebelum minifikasi atau kompresi.
Ukuran terurai Ukuran paket sebenarnya dalam paket setelah dikompilasi. Webpack versi 4 (yang digunakan dalam aplikasi ini) meminifikasi file yang dikompilasi secara otomatis, itulah sebabnya ukuran ini lebih kecil daripada ukuran statistik.
Ukuran gzip Ukuran paket setelah dikompresi dengan encoding gzip. Topik ini dibahas dalam panduan terpisah.

Dengan alat webpack-bundle-analyzer, akan lebih mudah untuk mengidentifikasi paket yang tidak digunakan atau tidak diperlukan yang merupakan persentase besar dari paket.

Menghapus paket yang tidak digunakan

Visualisasi menunjukkan bahwa paket firebase terdiri dari banyak lebih dari sekadar database. Ini mencakup paket tambahan seperti:

  • firestore
  • auth
  • storage
  • messaging
  • functions

Semua ini adalah layanan luar biasa yang disediakan oleh Firebase (dan lihat dokumentasi untuk mempelajari lebih lanjut), tetapi tidak ada satu pun layanan yang digunakan dalam aplikasi, jadi tidak ada alasan untuk mengimpor semuanya.

Kembalikan perubahan di webpack.config.js untuk melihat aplikasi lagi:

  • Hapus BundleAnalyzerPlugin di daftar plugin:
plugins: [
  //...
  new BundleAnalyzerPlugin()
];
  • Sekarang, hapus impor yang tidak digunakan dari bagian atas file:
const path = require("path");

//...
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

Sekarang aplikasi akan dimuat secara normal. Ubah src/index.js untuk mengupdate impor Firebase.

import firebase from 'firebase';
import firebase from 'firebase/app';
import 'firebase/database';

Sekarang saat aplikasi dimuat ulang, peringatan DevTools tidak ditampilkan. Membuka panel Network DevTools juga menunjukkan pengurangan ukuran paket yang bagus:

Ukuran paket dikurangi menjadi 480 KB

Lebih dari setengah ukuran paket dihapus. Firebase menyediakan berbagai layanan berbeda dan memberi developer opsi untuk hanya menyertakan layanan yang benar-benar diperlukan. Dalam aplikasi ini, hanya firebase/database yang digunakan untuk menyimpan dan menyinkronkan semua data. Impor firebase/app, yang menyiapkan platform API untuk setiap layanan yang berbeda, selalu diperlukan.

Banyak library populer lainnya, seperti lodash, juga memungkinkan developer mengimpor berbagai bagian paket mereka secara selektif. Tanpa melakukan banyak pekerjaan, memperbarui impor library dalam aplikasi untuk hanya menyertakan apa yang sedang digunakan dapat menghasilkan peningkatan performa yang signifikan.

Meskipun ukuran paket telah sedikit berkurang, masih banyak pekerjaan yang harus dilakukan. 😈

Menghapus paket yang tidak diperlukan

Tidak seperti Firebase, mengimpor bagian library moment tidak dapat dilakukan dengan mudah, tetapi mungkin dapat dihapus sepenuhnya?

Ulang tahun setiap anak kucing lucu disimpan dalam format Unix (milidetik) di database Firebase.

Tanggal lahir disimpan dalam format Unix

Ini adalah stempel waktu dari tanggal dan waktu tertentu yang diwakili oleh jumlah milidetik yang telah berlalu sejak 1 Januari 1970 00.00 UTC. Jika tanggal dan waktu saat ini dapat dihitung dengan format yang sama, fungsi kecil untuk menemukan usia setiap anak kucing dalam beberapa minggu mungkin dapat dibuat.

Seperti biasa, cobalah untuk tidak menyalin dan menempel seperti yang Anda lakukan di sini. Mulailah dengan menghapus moment dari impor di src/index.js.

import firebase from 'firebase/app';
import 'firebase/database';
import * as moment from 'moment';

Ada pemroses peristiwa Firebase yang menangani perubahan nilai dalam database kita:

favoritesRef.on("value", (snapshot) => { ... })

Di atas ini, tambahkan fungsi kecil untuk menghitung jumlah minggu dari tanggal tertentu:

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);
}

Pada fungsi ini, selisih milidetik antara tanggal dan waktu saat ini (new Date).getTime() dan tanggal lahir (argumen birthDate, sudah dalam milidetik) dihitung dan dibagi dengan jumlah milidetik dalam satu minggu.

Terakhir, semua instance moment dapat dihapus di pemroses peristiwa dengan memanfaatkan fungsi ini:

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>
    `})
});

Sekarang muat ulang aplikasi dan lihat panel Network sekali lagi.

Ukuran paket dikurangi menjadi 225 KB

Ukuran paket kami pun berkurang lebih dari setengahnya!

Kesimpulan

Dengan codelab ini, Anda harus memiliki pemahaman yang baik tentang cara menganalisis paket tertentu dan alasan mengapa paket tersebut sangat berguna untuk menghapus paket yang tidak digunakan atau tidak diperlukan. Sebelum mulai mengoptimalkan aplikasi dengan teknik ini, penting untuk diketahui bahwa hal ini bisa jauh lebih kompleks pada aplikasi yang lebih besar.

Terkait dengan menghapus library yang tidak digunakan, cobalah untuk mencari tahu bagian mana dari paket yang digunakan dan bagian mana yang tidak. Untuk paket yang tampak misterius yang sepertinya tidak digunakan di mana pun, mundur sejenak dan periksa dependensi tingkat atas mana yang mungkin membutuhkannya. Cobalah mencari cara untuk mungkin memisahkan mereka satu sama lain.

Dalam hal menghapus library yang tidak diperlukan, segalanya bisa menjadi sedikit lebih rumit. Penting untuk bekerja sama dengan tim Anda dan melihat apakah ada potensi untuk menyederhanakan bagian codebase. Menghapus moment dalam aplikasi ini mungkin tampak tepat untuk dilakukan setiap saat, tetapi bagaimana jika ada zona waktu dan lokal berbeda yang perlu ditangani? Atau bagaimana jika ada manipulasi tanggal yang lebih rumit? Banyak hal dapat menjadi sangat rumit jika memanipulasi dan menguraikan tanggal/waktu, dan library seperti moment dan date-fns menyederhanakannya secara signifikan.

Semuanya memiliki konsekuensi, dan penting untuk mengukur apakah kompleksitas dan upaya yang diperlukan untuk meluncurkan solusi kustom sepadan, bukan mengandalkan library pihak ketiga.