Mengurangi ukuran bundel dengan Webpack Analyzer dan React Lazy / Suspense

Seiring meningkatnya kompleksitas aplikasi klien, ukuran bundel mereka menjadi semakin banyak. Dalam situasi ini, orang yang paling menderita, dipaksa, karena berbagai alasan, menggunakan koneksi internet yang lambat. Apalagi setiap hari justru semakin memburuk.



Penulis artikel, terjemahan yang kami terbitkan hari ini, bekerja di Wix. Dia ingin berbicara tentang bagaimana dia dapat mengurangi ukuran satu bundel sekitar 80%, menggunakan Webpack Analyzer dan React Lazy / Suspense.

Seberapa awal optimasi dimulai?


Jika Anda baru saja mulai bekerja pada aplikasi web baru Anda, maka Anda mungkin mencoba untuk fokus membuatnya, sehingga untuk berbicara, "lepas landas", mencoba membuatnya bekerja. Anda mungkin tidak terlalu memperhatikan kinerja atau ukuran bundel. Saya bisa mengerti itu. Namun, pengalaman saya menunjukkan bahwa kinerja dan ukuran bundel harus diurus sejak awal. Arsitektur aplikasi yang baik dan "refleksi masa depan proyek" yang tepat waktu akan menghemat banyak waktu dan membantu Anda untuk tidak menumpuk utang teknis yang serius. Jelas, sulit untuk "meramalkan" segalanya di muka, tetapi Anda harus berusaha sangat keras untuk melakukan semuanya dengan benar sejak hari pertama bekerja di proyek.

Berikut adalah beberapa alat hebat yang menurut saya harus digunakan sejak awal. Alat-alat ini akan membantu Anda mengenali paket NPM "bermasalah" bahkan sebelum mereka menempati tempat penting dalam aplikasi.

UndBundlephobia


Bundlephobia adalah situs yang memberi tahu Anda seberapa banyak paket NPM tertentu akan meningkatkan ukuran bundel. Ini adalah alat yang hebat untuk membantu programmer membuat keputusan yang tepat mengenai pilihan paket pihak ketiga yang mungkin ia butuhkan. Bundlephobia membantu mendesain arsitektur aplikasi sehingga ukurannya tidak terlalu besar. Gambar berikut menunjukkan hasil memeriksa perpustakaan populer untuk bekerja dengan waktu, yang disebut momen. Anda dapat melihat bahwa perpustakaan ini cukup besar - hampir 66 Kb dalam bentuk terkompresi. Bagi banyak pengguna yang bekerja di Internet berkecepatan tinggi, ini bukan apa-apa. Namun, perlu diperhatikan waktu pengunduhan paket ini di jaringan 2G / 3G. Ini, masing-masing, adalah 2,2 dan 1,32 detik. Dan, perhatikan, kita hanya membicarakan paket yang satu ini.


Hasil analisis paket momen Bundlephobia

Cost Biaya Impor


Biaya Impor adalah ekstensi yang sangat menarik bagi banyak editor kode populer (memiliki lebih dari satu juta unduhan untuk Kode VS ). Itu dapat menunjukkan "biaya" dari paket impor. Saya terutama menyukainya karena membantu mengidentifikasi area masalah pada aplikasi saat mengerjakannya. Gambar berikut (diambil dari halaman Biaya Impor GitHub) menunjukkan contoh yang sangat baik dari dampak pada dimensi proyek dari pendekatan yang berbeda untuk mengimpor entitas. Jadi, mengimpor satu-satunya properti uniqueId dari Lodash mengarah ke impor seluruh perpustakaan ke proyek (70 Kb). Dan jika Anda langsung mengimpor fungsi uniqueId , maka hanya 2 Kb yang akan ditambahkan ke ukuran proyek. Baca lebih lanjut tentang Biaya Impor di sini .


"Biaya" mengimpor seluruh perpustakaan Lodash ke proyek dan hanya satu fungsi spesifik dari perpustakaan ini

Kasus bundel besar yang tidak masuk akal


Jadi, Anda telah membuat aplikasi luar biasa. Ini bekerja sangat baik di Internet kecepatan tinggi Anda dan di komputer Anda yang paling kuat, penuh dengan RAM. Anda merilisnya ke dunia nyata. Setelah beberapa waktu, keluhan mulai datang dari Anda atau dari analis Anda sendiri. Keluhan ini terkait dengan waktu muat aplikasi. Sesuatu yang serupa baru-baru ini terjadi pada saya ketika kami, di Wix, meluncurkan fitur baru yang sedang saya kerjakan.

Untuk mempercepat Anda, mari bicarakan peluang baru ini. Ini adalah bilah kemajuan baru yang terletak di bagian atas panel samping dari antarmuka pengaturan situs pengguna. Tujuan dari mekanisme ini adalah untuk menarik perhatian pengguna ke berbagai langkah yang perlu dia lakukan agar proyek bisnisnya memiliki peluang keberhasilan yang lebih baik (terhubung ke SEO, menambah wilayah pengiriman barang, menambahkan produk pertama , dan sebagainya).

Bilah kemajuan diperbarui secara otomatis dengan menghubungkan ke server menggunakan soket web. Saat pengguna menyelesaikan semua langkah yang disarankan, jendela sembulan akan muncul dengan selamat. Setelah jendela ini ditutup, bilah progres disembunyikan dan tidak pernah ditampilkan lagi ketika bekerja dengan situs tempat Anda menggunakannya. Inilah yang baru saja kita bicarakan.


Progress Bar dan Jendela Selamat

Apa yang terjadi Mengapa analis kami mengeluh kepada saya bahwa waktu buka halaman telah meningkat? Ketika saya memeriksa keadaan hubungan menggunakan tab Jaringan alat pengembang Chrome, segera menjadi jelas bagi saya bahwa bundel saya cukup besar. Yakni, ukurannya 190 Kb.


Ukuran bundel ditemukan menggunakan Alat Pengembang Chrome

"Mengapa benda kecil ini membutuhkan bungkusan yang relatif besar?" Tapi kebenarannya - mengapa?

▍ Mencari titik-titik masalah dalam bundel


Setelah saya menyadari bahwa ukuran bundel itu terlalu besar, sekarang saatnya untuk mencari tahu alasannya. Di sinilah Webpack Bundle Analyzer berguna - alat yang hebat untuk mengidentifikasi bidang masalah bundel. Ini membuka tab browser baru dan menampilkan informasi ketergantungan.

Inilah yang terjadi setelah saya menganalisis bundel dengan alat ini.


Hasil Analisis Webpack Bundle

Dengan bantuan penganalisa, saya dapat mendeteksi "penjahat". Paket lottie-web digunakan di sini, yang menambahkan 61,45 Kb ke ukuran bundel. Lottie adalah pustaka JavaScript yang sangat bagus yang memungkinkan penggunaan alat peramban standar untuk menghasilkan animasi yang dibuat di Adobe After Effect. Dalam kasus saya, itu sehingga desainer kami membutuhkan animasi yang bagus, yang dilakukan ketika jendela dengan selamat muncul. Dia membuat animasi ini dan memberikannya kepada saya dalam bentuk file JSON, yang saya transfer ke paket Lottie dan mendapatkan animasi yang indah. Selain paket lottie-web, saya juga punya file JSON dengan deskripsi animasi. Ukuran file ini adalah 26 Kb. Akibatnya, perpustakaan Lottie, file JSON, dan juga beberapa dependensi kecil tambahan "menelan biaya" sekitar 94 Kb. Dan ini hanya sebuah animasi dari jendela dengan selamat kepada pengguna. Pengguna, ketika dia melihat ucapan selamat ini, seharusnya senang. Semua ini membuatku sedih.

React Lazy / Suspense technology hadir untuk menyelamatkan


Setelah saya menemukan penyebab masalahnya, sekarang saatnya untuk menyelesaikan masalah ini. Jelas bahwa tidak perlu memuat di awal pekerjaan semua yang diperlukan untuk animasi. Bahkan, ada kemungkinan besar bahwa selama sesi pengguna saat ini, dia tidak perlu menunjukkan jendela dengan selamat. Kemudian saya berkenalan dengan teknologi React Lazy / Suspense yang baru muncul dan berpikir bahwa sekarang saya mungkin memiliki kesempatan yang baik untuk mengujinya.

Jika Anda tidak terbiasa dengan konsep komponen "lazy" (malas), maka ketahuilah bahwa artinya adalah membagi aplikasi menjadi potongan-potongan kecil kode. Mengunduh fragmen ini dilakukan hanya saat dibutuhkan. Dalam kasus saya, ini dinyatakan dalam fakta bahwa saya perlu memilih dari fungsional utama progress bar komponen yang bertanggung jawab untuk menunjukkan ucapan selamat. Itu perlu memuat komponen ini hanya ketika pengguna menyelesaikan urutan langkah yang direkomendasikan.

Bereaksi 16.6.0 (dan versi yang lebih baru) memiliki API sederhana yang dirancang untuk membuat komponen malas. Ini adalah React.lazy dan React.Suspense . Pertimbangkan sebuah contoh:

 const OtherComponent = React.lazy(() => import('./OtherComponent')); function MyComponent() {  return (    <div>      <React.Suspense fallback={<div>Loading...</div>}>        <OtherComponent />      </React.Suspense>    </div>  ); } 

Kami memiliki komponen yang menampilkan elemen <div> , dan di dalamnya ada komponen Suspense yang membungkus komponen OtherComponent . Jika Anda melihat baris pertama dari contoh ini, Anda dapat melihat bahwa OtherComponent tidak diimpor langsung ke dalam kode. Biasanya, impor seperti ini terlihat seperti import OtherComponent from './OtherComponent'; .

Sebaliknya, perintah impor dibingkai sebagai fungsi yang mengambil jalur file. Mekanisme ini berfungsi karena Webpack memiliki alat pemisah kode bawaan. Ketika konstruksi yang sama hadir dalam kode, janji dikembalikan, yang, setelah mengunduh file, diselesaikan dengan konten file ini. Tim impor kami dibungkus dalam fungsi React.lazy .

Dalam materi render yang dikembalikan oleh MyComponent , OtherComponent dibungkus dalam komponen React.Suspense yang memiliki properti fallback . Dalam kasus kami, ternyata ketika rendering mencapai OtherComponent , pemuatan komponen yang sesuai dimulai. Sementara itu, apa yang ditulis ke properti fallback diberikan. Dalam contoh ini, ini adalah teks Loading… Faktanya, itu saja. Mekanisme ini hanya melakukan pekerjaan mereka.

Benar, ada beberapa fitur yang perlu Anda pertimbangkan saat bekerja dengan Lazy / Suspense.

  1. Komponen yang diimpor dengan cara "malas" harus mengandung ekspor default, yang akan menjadi titik masuk komponen. Ekspor yang disebutkan tidak dapat digunakan di sini.
  2. Anda perlu membungkus komponen yang diimpor menggunakan fungsi React.lazy di komponen React.Suspense . Komponen React.Suspense menyediakan properti fallback . Kalau tidak, kesalahan akan terjadi. Namun, jika Anda tidak ingin membuat apa pun hingga komponen selesai pemuatan malas, Anda dapat menulis null pada fallback tanpa berusaha mengelak dari keharusan untuk menulis sesuatu di properti ini dengan cara yang rumit.

Apakah menggunakan React Lazy / Suspense membantu saya?


Ya, itu membantu! Pemecahan kode bekerja dengan luar biasa. Mari kita lihat hasil menganalisis bundel baru menggunakan Webpack.


Hasil Webpack Bundle Analyzer setelah Pemecahan Kode

Seperti yang Anda lihat, ukuran bundel saya berkurang sekitar 50% - hingga 96 Kb. Hebat!

Lantas apa, sekarang masalahnya selesai? Tidak, sayangnya. Ketika saya melihat halaman, ternyata pop-up dengan selamat kehilangan posisi.


Jendela ucapan selamat tidak muncul di tempat Anda membutuhkannya

Masalahnya adalah saya “meminta” jendela untuk membuka dengan mengubah status komponen Bereaksi. Sementara itu, saya telah membuat null (yaitu, saya belum memberikan apa pun) menggunakan komponen React.Suspense . Setelah malas memuat data yang diperlukan, materi yang relevan ditambahkan ke DOM. Namun, penentuan posisi popup sudah dilakukan. Akibatnya, karena fakta bahwa sifat-sifat komponen yang sesuai tidak berubah, komponen ini “tidak tahu” bahwa ia perlu menyelesaikan masalah mengenai penentuan posisi. Jika saya mengubah ukuran jendela browser, jendela pop-up muncul di tempat yang tepat karena fakta bahwa komponen yang sesuai mengamati perubahan dalam properti dan peristiwa mengubah ukuran jendela, memulai, jika perlu, memposisikan ulang.

Bagaimana cara mengatasi masalah ini? Solusinya adalah menghilangkan "perantara".

Saya pertama-tama harus memuat komponen "malas", dan baru kemudian menulis ke negara yang akan memberi tahu jendela dengan selamat bahwa itu perlu dibuka. Saya bisa melakukan ini menggunakan mekanisme berbagi kode Webpack yang sama, tapi sekarang - tanpa menerapkan impor menggunakan React.lazy :

 async loadAndSetHappyMoment() {  const component = await import(    '../SidebarHappyMoment/SidebarHappyMoment.component'  );  this.SidebarHappyMoment = component.SidebarHappyMoment;  this.setState({    tooltipLevel: TooltipLevel.happyMoment,  }); } 

Fungsi ini dipanggil setelah komponen saya, melalui mekanisme soket web, diberitahu bahwa ia perlu menampilkan jendela dengan selamat. Saya menggunakan fungsi import Webpack (baris kode kedua). Jika Anda ingat, saya katakan di atas bahwa fungsi ini mengembalikan janji, akibatnya saya dapat menggunakan konstruk async/await .

Setelah komponen selesai dimuat, saya menuliskannya ke instance komponen saya (dengan perintah this.SidebarHappyMoment = component.SidebarHappyMoment; ). Ini memberi saya kesempatan untuk menggunakannya nanti saat rendering. Harap perhatikan bahwa sekarang saya dapat menggunakan ekspor yang diberi nama. Dalam kasus saya, saya menggunakan, pada baris di atas, nama SidebarHappyMoment . Dan akhirnya, dan ini tidak kalah pentingnya dari yang lainnya, saya "menginformasikan" jendela yang perlu dibuka, mengubah keadaannya setelah saya tahu bahwa komponen siap untuk operasi.

Akibatnya, kode rendering sekarang terlihat seperti ini:

 renderTooltip() {  if (this.state.tooltipLevel === TooltipLevel.happyMoment) {    return <this.SidebarHappyMoment />;  }  // ... } 

Perhatikan bahwa perintah return <this.SidebarHappyMoment />; mengembalikan this.SidebarHappyMoment - apa yang saya tulis sebelumnya ke instance komponen saya. Sekarang ini adalah fungsi render sinkron normal, sama seperti yang telah Anda gunakan jutaan kali. Dan sekarang jendela dengan selamat ditampilkan di tempat yang seharusnya. Dan masalahnya adalah ia terbuka hanya setelah isinya siap digunakan.

Produk mendefinisikan arsitektur


Jika gagasan dalam judul bagian ini membangkitkan tanda tanya yang kuat dalam imajinasi Anda, maka ketahuilah bahwa inilah masalahnya. Produk mendefinisikan arsitektur.

Ini adalah tentang fakta bahwa produk menentukan apa yang harus terlihat dan interaktif ketika komponen pertama kali diberikan. Ini membantu pengembang untuk mencari tahu apa sebenarnya yang dapat ia pisahkan dari kode utama dan memuatnya nanti, bila perlu. Saya memikirkan situasinya dan "mengingat" bahwa setelah pengguna menyelesaikan langkah-langkah yang disarankan untuk menyiapkan situs, atau jika dia bukan administrator situs, saya tidak perlu menunjukkan kepadanya bilah kemajuan dan apa yang terjadi dengannya. terhubung. Sekarang, menggunakan informasi ini, saya dapat terus berbagi bungkusan. Itu yang saya dapat.


Pemisahan bundel yang berlanjut

Setelah itu, ukuran bundel itu hanya 38 Kb. Dan saya mengingatkan Anda bahwa kami mulai dengan 190 Kb. Ada pengurangan ukuran bundel sebesar 80%. Dan omong-omong, saya sudah melihat kemungkinan lain untuk pemisahan kode. Saya tidak sabar untuk terus mengoptimalkan bundel.

Ringkasan


Pengembang memiliki kemampuan untuk berusaha untuk tetap berada di "zona nyaman" mereka dan tidak mempelajari apa pun selain perangkat kode itu sendiri dan fungsinya. Namun, seorang programmer yang menggunakan alat yang dijelaskan di atas, berpikir kreatif dan bekerja sama dengan spesialis lain, mungkin dapat meningkatkan kinerja aplikasinya dengan secara signifikan mengurangi ukuran bundel yang berisi apa yang diperlukan untuk mulai bekerja dengan aplikasi ini.

Pembaca yang budiman! Apakah Anda menggunakan pemisahan kode untuk mempercepat pemuatan aplikasi web Anda?


Source: https://habr.com/ru/post/id468225/


All Articles