Menerapkan performance budget sederhana

15 December, 2018

Baca-baca tentang The Cost of JavaScript nya Addy Osmani yang selalu menekankan performance budgeting, membuat saya tertarik untuk menerapkannya di proyek kecil- kecilan saya, yakni di blog ini.

Sepemahaman saya, performance budgeting simplenya adalah seperti ini: Ingin berapa detik situs kamu dimuat di jaringan X?, misal: Situs saya ingin bisa dimuat selama 3 detik di jaringan Slow 3G, disitu kita bisa mulai budgeting, misal untuk mencapai target yang sudah kita buat diatas, total byte yang harus diunduh oleh user adalah 288kb. Nah, dari situ baru bisa kita rancang, misal:

  • HTML: 7kb
  • CSS: 9kb
  • JS: 76kb
  • Images: 182kb
  • Fonts: 14kb

Total: 288kb. Kita harus mengatur strategi-strategi tentang bagaimana agar angka tersebut bisa (setidaknya) dicapai. HTML, dengan menggunakan PRPL Pattern (App Shell), app shell saya hanya 1.6kb. Disini kita bisa prefetch halaman-halaman html lain yang tidak blocking render. Atau setidaknya sudah menampilkan "Useful Content". Yang sisanya bisa dimuat di idle time, atau dengan bantuan interaksi user (klik tombol Load More)

Lalu CSS, misal dengan tree shaking. Biasanya kita meload "Full" kode CSS untuk semua halaman (Hello Bootstrap!, 18kb + minified & gzipped). Belum ditambah custom CSS untuk menyesuaikan dengan keinginan kita. Dengan component-based, target 9kb bisa dicapai karena kita memecah nya menjadi bagian yang lebih kecil. Misal, untuk "global CSS" disitus ini hanya sebesar 838b, plus pemuatan chunk CSS lain untuk Fragment & Component yang dilakukan tanpa blocking render (dan itu cuma memakan 335b (Fragment) + 293b (Chunk di app shell, toast). Total 1,47kb).

JS yang harus tricky! App shell ku sudah memakan 40.6kb untuk web app sesederhana ini! Belum ditambah kode JS yang digunakan di Fragment Index (715b), dan kode JS untuk Toast (yang ada di app shell juga, sekitar 587b). Total 41.3kb! Yes, ternyata tercapai gan! Karena saya hanya meload yang sekiranya dibutuhkan di fragment itu saja.

Sekarang Images. Di app shell tidak ada images, jadi 182kb bisa dialokasikan ke budget lain :))

Fonts. Ini lumayan mahal menurut saya. Di situs saya ini tidak menggunakan custom font aneh-aneh (pakai font kesayangan saya, jika tidak ada, fallback ke default browser). Tapi disini saya menggunakan Ionicons, dan ini memakan 49.6kb. Over budget dibagian font, tapi bisa kita ambil dari budget di JS tersebut.

Ada beberapa yang tidak saya hitung disini, seperti: 3rd party library (OneSignal, GA, dan GTM). Tapi karena tidak non-blocking render (menggunakan async), jadi dianggap tidak berpengaruh. Juga untuk CSS lain seperti NormalizeCss dan Prism, karena memang di app shell ini tidak digunakan sama sekali. Jadi, daripada mubazir, mending kita pakai untuk prefetch file-file tersebut, karena bisa diasumsikan user akan mengakses halaman list posts & post detail, yang mana file css tersebut akan digunakan, dan user tinggal menikmati apa yang sudah mereka bayar diawal.


Tapi, untuk kasus sekarang, saya hanya me-limit file app shell bundle sebesar 108kb. Besar? Tidak juga. Sangat mustahil bila file entrypoint pada aplikasi yang sangat besar & kompleks berukuran < 666kb. Pasti lebih. Karena aplikasi yang saya buat masih kecil banget, jadi untuk latihan, saya pilih nilai yang kecil (alias, nilai yang sama dengan username saya di internet), jadi bisa untuk berfikir tentang bagaimana cara mengurangi jumlah byte pada file ini.

Budget

Saya menggunakan bundlesize untuk membantu saya dalam budgeting. Saya sengaja memilih untuk menjalankan nya di CI agar proses lebih automated. Langkahnya:

  • Saya membuat perubahan terkait kode di branch baru
  • Saya mem-push perubahan tersebut
  • Saya melakukan pull request
  • Pull request bisa di "Approve" ketika 2 proses berhasil dijalankan
  • Proses Pertama, apakah proses build di CI berhasil? Jika tidak, tolak pull request
  • Proses kedua bundlesSize, apakah file app.[hash].js lebih dari 108kb? Jika ya, tolak pull request

Mengapa dilakukan di CI? Karena menunggu npm run build atau yarn build is so boring. Dan karena ini Open Source, jadi banyak layanan CI yang memberikan layanan nya secara gratis untuk project oss. Saya mem-push ke branch master langsung hanya ketika membuat tulisan baru disini. Jika terkait kode, maka perubahan harus melalui branch lain.

Dengan budgeting ini kita akan berlatih untuk bisa berfikir bagaimana membuat/menulis kode yang sebisa mungkin memiliki ukuran yang kecil. Apakah mungkin? Coba fikirkan tentang React vs Preact, yang memiliki API yang hampir sama, namun memiliki "Bundle Size" yang beda jauh. Tapi kan di Preact enggak bisa X, enggak ada React.Children misalnya. Yang membuat 'library' yang dibuat untuk React tidak bisa digunakan di Preact, misalnya. Tapi Preact memiliki preact-compat yang bisa membantu anda untuk menyelesaikan masalah itu (dan terpisah dari core preact).

Faktor yang paling berpengaruh disini adalah Images. Ya, bagaimana cara delivery images agar halaman kita tetap lean. Meskipun images tidak termasuk render blocking resources, tapi tetap karena disetiap website 30% konten dari website tersebut adalah gambar. Karena sisanya adalah tulisan, iya gak?