Apa Kerangka Web yang Dipecahkan Dan Bagaimana Melakukannya Tanpa Mereka (Bagian 1)
Diterbitkan: 2022-03-10Saya baru-baru ini menjadi sangat tertarik untuk membandingkan kerangka kerja dengan JavaScript vanilla. Ini dimulai setelah beberapa frustrasi saya telah menggunakan React di beberapa proyek freelance saya, dan dengan kenalan saya baru-baru ini yang lebih akrab dengan standar web sebagai editor spesifikasi.
Saya tertarik untuk melihat apa persamaan dan perbedaan antara kerangka kerja , apa yang ditawarkan platform web sebagai alternatif yang lebih ramping, dan apakah itu cukup. Tujuan saya bukan untuk menghancurkan kerangka kerja, melainkan untuk memahami biaya dan manfaat, untuk menentukan apakah ada alternatif, dan untuk melihat apakah kita dapat belajar darinya, bahkan jika kita memutuskan untuk menggunakan kerangka kerja.
Di bagian pertama ini, saya akan mendalami beberapa fitur teknis yang umum di seluruh kerangka kerja, dan bagaimana beberapa kerangka kerja yang berbeda mengimplementasikannya. Saya juga akan melihat biaya penggunaan kerangka kerja tersebut.
Kerangka
Saya memilih empat kerangka kerja untuk dilihat: React, menjadi yang dominan saat ini, dan tiga pesaing baru yang mengklaim melakukan sesuatu secara berbeda dari React.
- Reaksi
“React membuatnya mudah untuk membuat UI interaktif. Tampilan deklaratif membuat kode Anda lebih dapat diprediksi dan lebih mudah untuk di-debug.” - SolidJS
“Solid mengikuti filosofi yang sama dengan React… Namun memiliki implementasi yang sama sekali berbeda yang tidak menggunakan DOM virtual.” - Langsing
“Svelte adalah pendekatan baru yang radikal untuk membangun antarmuka pengguna… langkah kompilasi yang terjadi saat Anda membangun aplikasi. Alih-alih menggunakan teknik seperti perbedaan DOM virtual, Svelte menulis kode yang memperbarui DOM secara operasi saat status aplikasi Anda berubah.” - Lit
“Membangun di atas standar Komponen Web, Lit hanya menambahkan … reaktivitas, template deklaratif, dan beberapa fitur yang bijaksana.”
Untuk meringkas apa yang dikatakan kerangka kerja tentang pembedanya:
- React membuat pembuatan UI lebih mudah dengan tampilan deklaratif.
- SolidJS mengikuti filosofi React tetapi menggunakan teknik yang berbeda.
- Svelte menggunakan pendekatan waktu kompilasi untuk UI.
- Lit menggunakan standar yang ada, dengan beberapa fitur ringan yang ditambahkan.
Apa yang Dipecahkan oleh Kerangka Kerja?
Kerangka itu sendiri menyebutkan kata-kata deklaratif, reaktivitas, dan DOM virtual. Mari selami apa artinya itu.
Pemrograman Deklaratif
Pemrograman deklaratif adalah paradigma di mana logika didefinisikan tanpa menentukan aliran kontrol. Kami menjelaskan hasil yang dibutuhkan, bukan langkah apa yang akan membawa kami ke sana.
Pada hari-hari awal kerangka kerja deklaratif, sekitar tahun 2010, API DOM jauh lebih terbuka dan bertele-tele, dan menulis aplikasi web dengan JavaScript imperatif membutuhkan banyak kode boilerplate. Saat itulah konsep "model-view-viewmodel" (MVVM) menjadi lazim, dengan kerangka kerja Knockout dan AngularJS yang saat itu merupakan terobosan, menyediakan lapisan deklaratif JavaScript yang menangani kompleksitas itu di dalam perpustakaan.
MVVM bukanlah istilah yang banyak digunakan saat ini, dan ini merupakan variasi dari istilah lama “pengikatan data”.
Pengikatan Data
Pengikatan data adalah cara deklaratif untuk mengekspresikan bagaimana data disinkronkan antara model dan antarmuka pengguna.
Semua kerangka kerja UI populer menyediakan beberapa bentuk pengikatan data, dan tutorialnya dimulai dengan contoh pengikatan data.
Berikut adalah pengikatan data di JSX (SolidJS dan React):
function HelloWorld() { const name = "Solid or React"; return ( <div>Hello {name}!</div> ) }
Pengikatan data dalam Lit:
class HelloWorld extends LitElement { @property() name = 'lit'; render() { return html`<p>Hello ${this.name}!</p>`; } }
Pengikatan data di Svelte:
<script> let name = 'world'; </script> <h1>Hello {name}!</h1>
Reaktivitas
Reaktivitas adalah cara deklaratif untuk mengekspresikan penyebaran perubahan.
Ketika kami memiliki cara untuk mengekspresikan pengikatan data secara deklaratif, kami membutuhkan cara yang efisien untuk kerangka kerja untuk menyebarkan perubahan.
Mesin React membandingkan hasil rendering dengan hasil sebelumnya, dan menerapkan perbedaan pada DOM itu sendiri. Cara menangani propagasi perubahan ini disebut DOM virtual.
Di SolidJS, ini dilakukan secara lebih eksplisit, dengan penyimpanan dan elemen bawaannya. Misalnya, elemen Show
akan melacak apa yang telah berubah secara internal, bukan DOM virtual.
Di Svelte, kode "reaktif" dibuat. Svelte tahu peristiwa mana yang dapat menyebabkan perubahan, dan itu menghasilkan kode langsung yang menarik garis antara peristiwa dan perubahan DOM.
Di Lit, reaktivitas dicapai menggunakan properti elemen, yang pada dasarnya mengandalkan reaktivitas bawaan elemen kustom HTML.
Logika
Ketika sebuah kerangka kerja menyediakan antarmuka deklaratif untuk pengikatan data, dengan implementasi reaktivitasnya, ia juga perlu menyediakan beberapa cara untuk mengekspresikan beberapa logika yang secara tradisional ditulis secara imperatif. Blok bangunan dasar logika adalah "jika" dan "untuk", dan semua kerangka kerja utama memberikan beberapa ekspresi dari blok bangunan ini.
bersyarat
Selain mengikat data dasar seperti angka dan string, setiap kerangka menyediakan primitif "bersyarat". Di React, tampilannya seperti ini:
const [hasError, setHasError] = useState(false); return hasError ? <label>Message</label> : null; … setHasError(true);
SolidJS menyediakan komponen kondisional bawaan, Show
:
<Show when={state.error}> <label>Message</label> </Show>
Svelte memberikan arahan #if
:
{#if state.error} <label>Message</label> {/if}
Di Lit, Anda akan menggunakan operasi ternary eksplisit dalam fungsi render
:
render() { return this.error ? html`<label>Message</label>`: null; }
Daftar
Kerangka dasar umum lainnya adalah penanganan daftar. Daftar adalah bagian penting dari UI — daftar kontak, notifikasi, dll. — dan agar berfungsi secara efisien, mereka harus reaktif, tidak memperbarui seluruh daftar saat satu item data berubah.
Di Bereaksi, penanganan daftar terlihat seperti ini:
contacts.map((contact, index) => <li key={index}> {contact.name} </li>)
React menggunakan atribut key
khusus untuk membedakan antara item daftar, dan memastikan bahwa seluruh daftar tidak diganti dengan setiap render.
Di SolidJS, elemen bawaan for
dan index
digunakan:
<For each={state.contacts}> {contact => <DIV>{contact.name}</DIV> } </For>
Secara internal, SolidJS menggunakan tokonya sendiri bersama dengan for
dan index
untuk memutuskan elemen mana yang akan diperbarui saat item berubah. Ini lebih eksplisit daripada React, memungkinkan kita untuk menghindari kerumitan DOM virtual.
Svelte menggunakan each
direktif, yang ditranspilasikan berdasarkan pembarunya:
{#each contacts as contact} <div>{contact.name}</div> {/each}
Lit menyediakan fungsi repeat
, yang bekerja mirip dengan pemetaan daftar berbasis key
React:
repeat(contacts, contact => contact.id, (contact, index) => html`<div>${contact.name}</div>`
Model Komponen
Satu hal yang berada di luar cakupan artikel ini adalah model komponen dalam kerangka kerja yang berbeda dan bagaimana hal itu dapat ditangani dengan menggunakan elemen HTML khusus.
Catatan : Ini adalah topik besar, dan saya berharap untuk membahasnya di artikel mendatang karena yang ini akan menjadi terlalu panjang. :)
Biaya
Kerangka kerja menyediakan pengikatan data deklaratif, kontrol aliran primitif (bersyarat dan daftar), dan mekanisme reaktif untuk menyebarkan perubahan.
Mereka juga menyediakan hal-hal utama lainnya, seperti cara untuk menggunakan kembali komponen, tetapi itu adalah subjek untuk artikel terpisah.
Apakah kerangka kerja berguna? Ya. Mereka memberi kita semua fitur yang nyaman ini. Tapi apakah itu pertanyaan yang tepat untuk ditanyakan? Menggunakan kerangka kerja membutuhkan biaya. Mari kita lihat berapa biayanya.
Ukuran bundel
Saat melihat ukuran bundel, saya suka melihat ukuran non-Gzip yang diperkecil. Itu ukuran yang paling relevan dengan biaya CPU dari eksekusi JavaScript.
- ReactDOM sekitar 120 KB.
- SolidJS adalah sekitar 18 KB.
- Litnya sekitar 16 KB.
- Langsing sekitar 2 KB, tetapi ukuran kode yang dihasilkan bervariasi.
Tampaknya kerangka kerja hari ini melakukan pekerjaan yang lebih baik daripada Bereaksi menjaga ukuran bundel tetap kecil. DOM virtual membutuhkan banyak JavaScript.
Membangun
Entah bagaimana kami terbiasa "membangun" aplikasi web kami. Mustahil untuk memulai proyek front-end tanpa menyiapkan Node.js dan bundler seperti Webpack, berurusan dengan beberapa perubahan konfigurasi terbaru dalam paket awal Babel-TypeScript, dan semua jazz itu.
Semakin ekspresif dan semakin kecil ukuran bundel kerangka kerja, semakin besar beban alat pembuatan dan waktu transpilasi.
Svelte mengklaim bahwa DOM virtual adalah overhead murni. Saya setuju, tetapi mungkin "membangun" (seperti dengan Svelte dan SolidJS) dan mesin templat sisi klien khusus (seperti dengan Lit) juga murni overhead, dari jenis yang berbeda?
Men-debug
Dengan pembangunan dan transpilasi datang jenis biaya yang berbeda.
Kode yang kami lihat saat menggunakan atau men-debug aplikasi web benar-benar berbeda dari yang kami tulis. Kami sekarang mengandalkan alat debugging khusus dengan berbagai kualitas untuk merekayasa balik apa yang terjadi di situs web dan untuk menghubungkannya dengan bug dalam kode kami sendiri.
Di React, tumpukan panggilan tidak pernah menjadi “milik Anda” — React menangani penjadwalan untuk Anda. Ini berfungsi dengan baik ketika tidak ada bug. Tetapi cobalah untuk mengidentifikasi penyebab render ulang infinite-loop dan Anda akan berada dalam dunia yang menyakitkan.
Di Svelte, ukuran bundel pustaka itu sendiri kecil, tetapi Anda akan mengirimkan dan men-debug sejumlah besar kode yang dihasilkan secara samar yang merupakan implementasi reaktivitas Svelte, yang disesuaikan dengan kebutuhan aplikasi Anda.
Dengan Lit, ini bukan tentang membangun, tetapi untuk men-debugnya secara efektif, Anda harus memahami mesin templatnya. Ini mungkin alasan terbesar mengapa sentimen saya terhadap kerangka kerja skeptis.
Saat Anda mencari solusi deklaratif khusus, Anda berakhir dengan debugging imperatif yang lebih menyakitkan. Contoh dalam dokumen ini menggunakan TypeScript untuk spesifikasi API, tetapi kode itu sendiri tidak memerlukan transpilasi.
peningkatan
Dalam dokumen ini, saya telah melihat empat kerangka kerja, tetapi ada lebih banyak kerangka kerja daripada yang dapat saya hitung (AngularJS, Ember.js, dan Vue.js, untuk beberapa nama). Dapatkah Anda mengandalkan kerangka kerja, pengembangnya, mindshare-nya, dan ekosistemnya untuk bekerja untuk Anda seiring dengan perkembangannya?
Satu hal yang lebih membuat frustrasi daripada memperbaiki bug Anda sendiri adalah harus menemukan solusi untuk bug kerangka kerja. Dan satu hal yang lebih membuat frustrasi daripada bug kerangka kerja adalah bug yang terjadi saat Anda meningkatkan kerangka kerja ke versi baru tanpa memodifikasi kode Anda.
Benar, masalah ini juga ada di browser, tetapi ketika itu terjadi, itu terjadi pada semua orang, dan dalam kebanyakan kasus, perbaikan atau solusi yang diterbitkan sudah dekat. Selain itu, sebagian besar pola dalam dokumen ini didasarkan pada API platform web yang matang; tidak selalu ada kebutuhan untuk pergi dengan tepi berdarah.
Ringkasan
Kami menyelam lebih dalam untuk memahami kerangka kerja masalah inti yang coba dipecahkan dan bagaimana mereka menyelesaikannya, dengan fokus pada pengikatan data, reaktivitas, kondisional, dan daftar. Kami juga melihat biayanya.
Di Bagian 2, kita akan melihat bagaimana masalah ini dapat diatasi tanpa menggunakan kerangka kerja sama sekali, dan apa yang dapat kita pelajari darinya. Pantau terus!
Terima kasih khusus kepada orang-orang berikut untuk tinjauan teknis: Yehonatan Daniv, Tom Bigelajzen, Benjamin Greenbaum, Nick Ribal dan Louis Lazaris.