Kenapa saya tidak menggunakan komponen web

Saya menulis ini terutama untuk diri saya sendiri di masa depan, sehingga saya memiliki tempat untuk merujuk ketika seseorang bertanya kepada saya mengapa saya skeptis tentang komponen web dan mengapa Svelte tidak dikompilasi ke dalam komponen web secara default. (Namun, dapat dikompilasi ke dalam komponen web, serta diintegrasikan dengan mereka, sebagaimana dibuktikan oleh peringkat yang sangat baik pada Elemen Kustom Di Mana Saja ).


Tak satu pun dari yang berikut ini harus ditafsirkan sebagai kritik atas kerja keras yang dilakukan pada komponen web. Mungkin saya juga membuat kesalahan dalam publikasi ini, dalam hal ini saya akan senang untuk mengubah Saya juga tidak menyatakan bahwa Anda tidak boleh menggunakan komponen web. Mereka memiliki ruang lingkup sendiri. Saya hanya menjelaskan mengapa mereka tidak cocok untuk saya.


1. Peningkatan progresif


Ini mungkin kepercayaan kuno, tapi saya percaya bahwa situs web harus bekerja tanpa JavaScript sebanyak mungkin. Komponen web tanpa JS tidak berfungsi. Ini normal untuk hal-hal yang inheren interaktif, seperti elemen bentuk khusus (<cool-datepicker>), tetapi itu tidak normal untuk navigasi situs, misalnya. Atau bayangkan komponen <twitter-share> yang merangkum logika membangun URL untuk dikirim ke Twitter . Saya bisa menerapkannya di Svelte , yang merender HTML berikut kepada saya di server:


 <a target="_blank" noreferrer href="..." class="svelte-1jnfxx"> Tweet this </a> 

Dengan kata lain, <a> biasa dalam semua kemegahannya tersedia.


Saat JavaScript diaktifkan, peningkatan progresif terjadi - alih-alih membuka tab baru, jendela sembulan kecil terbuka. Tetapi bahkan tanpa JS, komponen masih berfungsi dengan baik.


Dalam kasus komponen web HTML, akan terlihat seperti ini:


 <twitter-share text="..." url="..." via="..."/> 

... yang tidak berguna dan tidak cocok untuk digunakan jika JS diblokir, atau karena beberapa alasan telah rusak, atau pengguna memiliki browser lama.


Selain itu, class="svelte-1jnfxx" memberi kita enkapsulasi gaya tanpa DOM Shadow. Yang membawa kita ke poin berikutnya.


2. CSS dalam, eh ... JS


Jika Anda ingin menggunakan Shadow DOM untuk merangkum gaya, maka Anda harus memasukkan CSS Anda di <style> . Satu-satunya cara praktis untuk melakukan ini, jika Anda ingin menghindari memuat berkedip konten (FOUC), adalah dengan menanamkan CSS sebagai string dalam JavaScript yang mendefinisikan sisa logika komponen web Anda.


Ini bertentangan dengan saran peningkatan kinerja yang berbunyi: "kurang JavaScript, tolong." Komunitas CSS-in-JS, khususnya, telah banyak dikritik karena tidak menggunakan file CSS untuk CSS, dan di sini kita kembali dengan komponen web.


Di masa depan, kita akan dapat menggunakan Modul CSS serta Lembar Gaya Konstruktif untuk mengatasi masalah ini. Kami juga akan memiliki kesempatan untuk merancang bagian internal Shadow DOM melalui ::theme and ::part . Tapi di sini bukan tanpa masalah.


3. Kelelahan platform



Ini adalah mahkota yang menyakitkan bagi saya - saya telah mengiklankan hal-hal ini sebagai "Masa Depan" selama beberapa tahun, tetapi untuk mengimbangi saat ini, kami harus mengisi platform dengan banyak fitur yang berbeda, memperburuk kesenjangan antara browser.

Pada saat penulisan, di https://crbug.com , pelacak bug Chrome, 61.000 bug terbuka yang menunjukkan kompleksitas luar biasa dalam menulis peramban modern.


Setiap kali kami menambahkan fitur baru ke platform, kami meningkatkan kompleksitas - menciptakan potensi bug baru dan memperkecil kemungkinan bahwa Chrome akan memiliki pesaing baru. Ini juga menciptakan kesulitan bagi pengembang yang didorong untuk mempelajari fitur-fitur baru ini (beberapa di antaranya, seperti Impor HTML atau versi asli standar Elemen Kustom, belum berakar di luar Google dan sekarang sedang dalam proses penghapusan).


4. Polifilis


Fakta bahwa Anda perlu menggunakan polyfile untuk mendukung browser lama tidak berkontribusi pada perkembangan situasi. Dan sama sekali tidak membantu artikel tentang Constructable Stylesheets yang ditulis di Google (hai Jason!) Jangan menyebutkan bahwa fitur ini hanya tersedia di Chrome. (Ketiga penulis spesifikasi bekerja untuk Google. Webkit tampaknya memiliki keraguan tentang beberapa aspek dari standar ini).


5. Komposisi


Ini dapat berguna untuk mengontrol kapan isi slot perlu dirender. Bayangkan Anda memiliki <html-include> untuk memuat beberapa konten tambahan saat terlihat:


 <p>Toggle the section for more info:</p> <toggled-section> <html-include src="./more-info.html"/> </toggled-section> 

Tiba-tiba! Sekalipun kita belum membuka toggled-section , tetapi browser telah meminta more-info.html , beserta semua gambar dan sumber daya lain yang ada di sana.


Ini karena isi slot diberikan di komponen web terlebih dahulu . Pada kenyataannya, ternyata dalam kebanyakan kasus Anda ingin membuat konten slot dengan malas. Svelte v2 mengadopsi model redning proaktif untuk memenuhi standar web, tetapi ini ternyata menjadi sumber utama ketidaknyamanan - kami tidak dapat membuat sesuatu yang mirip dengan React Router, misalnya. Di Svelte v3, kami menjauh dari perilaku komponen web dan tidak pernah melihat ke belakang.


Sayangnya, ini adalah salah satu karakteristik dasar DOM. Yang membawa kita ke ...


6. Kebingungan antara properti dan atribut


Properti dan atribut pada dasarnya adalah hal yang sama, bukan?


 const button = document.createElement('button'); button.hasAttribute('disabled'); // false button.disabled = true; button.hasAttribute('disabled'); // true button.removeAttribute('disabled'); button.disabled; // false 

Yah, hampir:


 typeof button.disabled; // 'boolean' typeof button.getAttribute('disabled'); // 'object' button.disabled = true; typeof button.getAttribute('disabled'); // 'string' 

Ada nama yang tidak cocok:


 div = document.createElement('div'); div.setAttribute('class', 'one'); div.className; // 'one' div.className = 'two'; div.getAttribute('class'); // 'two' 

... dan ada yang tidak disetujui sama sekali:


 input = document.createElement('input'); input.getAttribute('value'); // null input.value = 'one'; input.getAttribute('value'); // null input.setAttribute('value', 'two'); input.value; // 'one' 

Tapi kita bisa berurusan dengan kebiasaan ini, interaksi format string (HTML) dan DOM. Ada sejumlah fitur yang terbatas, mereka didokumentasikan, sehingga kita setidaknya bisa belajar tentang mereka, jika kita punya waktu dan kesabaran.


Komponen web membuat perbedaan. Tidak ada lagi jaminan tentang hubungan antara properti dan atribut, dan Anda, sebagai pengembang komponen web, diminta untuk mendukung keduanya. Yang membawa kita ke hal seperti itu:


 class MyThing extends HTMLElement { static get observedAttributes() { return ['foo', 'bar', 'baz']; } get foo() { return this.getAttribute('foo'); } set foo(value) { this.setAttribute('foo', value); } get bar() { return this.getAttribute('bar'); } set bar(value) { this.setAttribute('bar', value); } get baz() { return this.hasAttribute('baz'); } set baz(value) { if (value) { this.setAttribute('baz', ''); } else { this.removeAttribute('baz'); } } attributeChangedCallback(name, oldValue, newValue) { if (name === 'foo') { // ... } if (name === 'bar') { // ... } if (name === 'baz') { // ... } } } 

Anda dapat melakukan yang sebaliknya - attributeChangedCallback getter dan setters callback atributChangedCallback. Bagaimanapun, kenyamanan bekerja dengan itu hanya menyedihkan. Pada saat yang sama, ada cara sederhana dan tidak ambigu dalam kerangka kerja untuk mentransfer data ke suatu komponen.


7. Desain bocor


Item ini agak kabur, tetapi bagiku aneh bahwa attributeChangedCallback hanyalah metode kelas. Anda benar-benar dapat melakukan hal berikut:


 const element = document.querySelector('my-thing'); element.attributeChangedCallback('w', 't', 'f'); 

Atribut belum berubah, tetapi kode berperilaku seolah-olah itu terjadi. Tentu saja, selalu ada banyak cara untuk melakukan kerusakan pada JavaScript, tetapi ketika saya melihat detail implementasi mencuat dengan cara ini, menurut saya ada sesuatu yang salah dengan desainnya.


8. DOM buruk


Ok, kita sudah menetapkan bahwa DOM itu buruk. Tetapi masih sulit untuk melebih-lebihkan betapa tidak nyamannya membuat aplikasi interaktif.


Beberapa bulan yang lalu, saya menulis sebuah artikel, "Tulis kode lebih sedikit," untuk menggambarkan bagaimana Svelte dapat menulis komponen lebih efisien daripada kerangka kerja seperti React dan Vue. Tidak ada perbandingan dengan DOM vanilla, tetapi harus. Singkatnya, kami memiliki komponen sederhana <Adder a={1} b={2}/> :


 <script> export let a; export let b; </script> <input type="number" bind:value={a}> <input type="number" bind:value={b}> <p>{a} + {b} = {a + b}</p> 

Itu saja. Sekarang tuliskan hal yang sama melalui komponen web:


 class Adder extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); this.shadowRoot.innerHTML = ` <input type="number"> <input type="number"> <p></p> `; this.inputs = this.shadowRoot.querySelectorAll('input'); this.p = this.shadowRoot.querySelector('p'); this.update(); this.inputs[0].addEventListener('input', e => { this.a = +e.target.value; }); this.inputs[1].addEventListener('input', e => { this.b = +e.target.value; }); } static get observedAttributes() { return ['a', 'b']; } get a() { return +this.getAttribute('a'); } set a(value) { this.setAttribute('a', value); } get b() { return +this.getAttribute('b'); } set b(value) { this.setAttribute('b', value); } attributeChangedCallback() { this.update(); } update() { this.inputs[0].value = this.a; this.inputs[1].value = this.b; this.p.textContent = `${this.a} + ${this.b} = ${this.a + this.b}`; } } customElements.define('my-adder', Adder); 

Ya


Perhatikan bahwa jika kita secara bersamaan mengubah a dan b , maka kita akan memiliki dua pembaruan terpisah. Sebagian besar kerangka kerja tidak menderita dari masalah ini.


9. Nama global


Saya tidak akan fokus pada hal ini untuk waktu yang sangat lama, cukuplah untuk mengatakan bahwa bahaya bekerja dalam ruang nama tunggal telah lama diketahui dan dibongkar.


10. Semua masalah ini sudah diselesaikan.


Kesedihan terbesar adalah bahwa kita sudah memiliki model komponen yang baik. Kami masih belajar, tetapi tugas dasar - menyinkronkan tampilan dengan keadaan tertentu melalui memperbarui DOM dalam gaya berorientasi komponen - telah diselesaikan beberapa tahun yang lalu. Dan kami masih menambahkan fitur ke platform web hanya untuk mengejar apa yang sudah kami miliki di perpustakaan dan kerangka kerja.


Karena sumber daya kita tidak terbatas, waktu yang dihabiskan untuk satu tugas berarti kurangnya perhatian pada tugas lain. Energi signifikan dihabiskan untuk komponen web, meskipun ada ketidakpedulian umum dari para pengembang. Apa yang bisa kita capai dengan menghabiskan energi ini untuk sesuatu yang lain?

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


All Articles