Pengorbanan CSS-in-JS

Foto oleh Artem Bali

Baru-baru ini saya menulis gambaran umum tingkat CSS-in-JS yang lebih tinggi, kebanyakan berbicara tentang masalah yang coba dipecahkan oleh pendekatan ini. Penulis perpustakaan jarang menginvestasikan waktu untuk menggambarkan timbal balik dari solusi mereka. Kadang-kadang itu karena mereka terlalu bias, dan kadang-kadang mereka hanya tidak tahu bagaimana pengguna menerapkan alat ini. Jadi ini adalah upaya untuk menggambarkan pengorbanan yang saya lihat sejauh ini. Saya pikir penting untuk menyebutkan bahwa saya adalah penulis JSS, jadi saya harus dianggap bias.

Dampak sosial

Ada lapisan orang yang bekerja di platform web dan tidak tahu apa-apa tentang JavaScript. Orang-orang itu dibayar untuk menulis HTML dan CSS. CSS-in-JS telah membuat dampak besar pada alur kerja pengembang. Perubahan yang benar-benar transformatif tidak akan pernah bisa dilakukan tanpa ada orang yang tertinggal. Saya tidak tahu apakah CSS-in-JS harus menjadi satu-satunya cara, tetapi adopsi massal adalah tanda masalah yang jelas dengan menggunakan CSS dalam aplikasi modern.

Sebagian besar masalah adalah ketidakmampuan kita untuk berkomunikasi secara akurat kasus penggunaan di mana CSS-in-JS bersinar dan bagaimana menggunakannya dengan benar untuk suatu tugas. Banyak penggemar CSS-in-JS telah berhasil mempromosikan teknologi ini, tetapi tidak banyak kritik yang berbicara tentang pengorbanan dengan cara yang konstruktif, tanpa mengayunkan alat-alat murah. Akibatnya, kami membiarkan banyak pengorbanan tersembunyi dan tidak melakukan upaya keras untuk memberikan penjelasan dan solusi.

CSS-in-JS adalah upaya untuk membuat case use yang kompleks lebih mudah untuk ditangani, jadi jangan dorong di tempat yang tidak diperlukan!

Biaya runtime

Ketika CSS dihasilkan dari JavaScript saat runtime, di browser, ada overhead yang melekat. Overhead Runtime bervariasi dari perpustakaan ke perpustakaan. Ini adalah tolok ukur umum yang baik, tetapi pastikan untuk membuat tes Anda sendiri. Perbedaan utama pada saat runtime muncul tergantung pada kebutuhan untuk memiliki parsing CSS penuh dari string template, jumlah optimisasi, detail implementasi gaya dinamis, algoritma hashing dan biaya integrasi kerangka kerja. *

Selain potensi runtime overhead, Anda perlu mempertimbangkan 4 strategi bundling yang berbeda, karena beberapa perpustakaan CSS-in-JS mendukung beberapa strategi dan terserah kepada pengguna untuk menerapkannya. *

Strategi 1: Generasi Runtime saja

Pembuatan CSS Runtime adalah teknik yang menghasilkan string CSS dalam JavaScript dan kemudian menyuntikkan string tersebut menggunakan tag gaya ke dalam dokumen. Teknik ini menghasilkan Style Sheet, BUKAN gaya inline.

Imbalan dari pembuatan runtime adalah ketidakmampuan untuk menyediakan konten gaya pada tahap awal, saat dokumen mulai memuat. Pendekatan ini biasanya cocok untuk aplikasi tanpa konten yang dapat bermanfaat segera. Biasanya, aplikasi semacam itu membutuhkan interaksi pengguna sebelum bisa benar-benar bermanfaat bagi pengguna. Seringkali aplikasi semacam itu bekerja dengan konten yang sangat dinamis sehingga menjadi usang segera setelah Anda memuatnya, jadi Anda perlu membuat pipa pembaruan sejak awal, misalnya, Twitter. Selain itu, ketika pengguna masuk, tidak perlu menyediakan HTML untuk SEO.

Jika interaksi membutuhkan JavaScript, bundel perlu dimuat sebelum aplikasi siap. Misalnya, Anda dapat menampilkan konten saluran default saat memuat Slack dalam dokumen, tetapi kemungkinan pengguna ingin mengubah saluran tepat setelah itu. Jadi, jika Anda memuat konten awal hanya untuk membuangnya segera.

Persepsi kinerja aplikasi semacam itu dapat ditingkatkan dengan placeholder dan trik lain agar aplikasi terasa lebih instan daripada yang sebenarnya. Aplikasi semacam itu biasanya data yang berat, jadi mereka tidak akan berguna secepat artikel.

Strategi 2: Generasi Runtime dengan Critical CSS

CSS kritis adalah jumlah minimal CSS yang diperlukan untuk menata halaman dalam keadaan awal. Itu diberikan menggunakan tag gaya di kepala dokumen. Teknik ini banyak digunakan dengan dan tanpa CSS-in-JS. Dalam kedua kasus, Anda cenderung melipatgandakan aturan CSS, satu kali sebagai bagian dari CSS Kritis dan satu kali sebagai bagian dari bundel JavaScript atau CSS. Ukuran CSS Kritis bisa sangat besar tergantung pada jumlah konten. Biasanya, dokumen tidak akan di-cache.

Tanpa Critical CSS, aplikasi satu halaman berat konten statis dengan runtime CSS-in-JS harus menunjukkan placeholder alih-alih konten. Ini buruk karena bisa berguna bagi pengguna jauh lebih awal, meningkatkan aksesibilitas pada perangkat kelas bawah dan untuk koneksi bandwidth rendah.

Dengan CSS kritis, runtime pembuatan CSS dapat dilakukan pada tahap selanjutnya, tanpa memblokir UI pada fase awal. Namun berhati-hatilah, pada perangkat seluler kelas bawah, yang berusia sekitar 5+ tahun, generasi CSS dari JavaScript dapat berdampak negatif pada kinerja. Ini sangat tergantung pada jumlah CSS yang dihasilkan dan pustaka yang digunakan, sehingga tidak dapat digeneralisasi.

Imbalan dari strategi ini adalah biaya ekstraksi CSS Kritis dan biaya pembuatan CSS runtime.

Strategi 3: Hanya ekstraksi build-time

Strategi ini adalah yang default di web tanpa CSS-in-JS. Beberapa perpustakaan CSS-in-JS memungkinkan Anda untuk mengekstrak CSS statis pada waktu membangun. * Dalam hal ini, tidak ada overhead runtime yang terlibat, CSS dirender pada halaman menggunakan tag tautan. Biaya pembuatan CSS dibayarkan sekali sebelumnya.

Ada 2 pengorbanan utama di sini:

  1. Anda tidak dapat menggunakan beberapa API dinamis yang ditawarkan CSS-in-JS saat runtime, karena Anda tidak memiliki akses ke negara. Seringkali Anda masih tidak dapat menggunakan properti khusus CSS, karena mereka tidak didukung di setiap browser dan tidak dapat di-polyfill pada saat build secara alami. Dalam hal ini, Anda harus melakukan solusi untuk tema dinamis dan gaya berdasarkan keadaan. *
  2. Tanpa CSS Kritis dan dengan cache kosong, Anda akan memblokir cat pertama, sampai bundel CSS Anda dimuat. Elemen tautan di kepala dokumen memblokir rendering HTML.
  3. Spesifisitas non-deterministik dengan pemisahan bundel berbasis halaman dalam aplikasi satu halaman. *

Strategi 4: Ekstraksi build-time dengan Critical CSS

Strategi ini juga tidak unik untuk CSS-in-JS. Ekstraksi statis penuh dengan CSS kritis memberikan kinerja terbaik saat bekerja dengan aplikasi yang lebih statis. Pendekatan ini masih memiliki pengorbanan yang disebutkan sebelumnya dari CSS statis, kecuali bahwa tag tautan pemblokiran dapat dipindahkan ke bagian bawah dokumen.

Ada 4 strategi rendering CSS utama. Hanya 2 dari mereka yang khusus untuk CSS-in-JS dan tidak ada yang berlaku untuk semua perpustakaan.

Aksesibilitas

CSS-in-JS dapat mengurangi aksesibilitas bila digunakan dengan cara yang salah. Ini akan terjadi ketika sebagian besar situs konten statis diimplementasikan tanpa ekstraksi CSS Kritis sehingga HTML tidak dapat dicat sebelum bundel JavaScript dimuat dan dievaluasi. Ini juga dapat terjadi ketika file CSS besar dirender menggunakan tag tautan pemblokiran di kepala dokumen, yang merupakan masalah paling populer saat ini dengan penyematan tradisional dan tidak khusus untuk CSS-in-JS.

Pengembang harus bertanggung jawab atas aksesibilitas. Masih ada ide keliru yang kuat bahwa koneksi internet yang tidak stabil adalah masalah negara-negara yang secara ekonomi lemah. Kita cenderung lupa bahwa kita memiliki masalah konektivitas setiap hari ketika kita memasuki sistem kereta bawah tanah atau bangunan besar. Koneksi seluler bebas kabel yang stabil adalah mitos. Bahkan tidak mudah untuk memiliki koneksi WiFi yang stabil, misalnya, jaringan WI-FI 2,4 GHz bisa mendapat gangguan dari oven microwave!

Biaya CSS Kritis dengan Server-side Rendering

Untuk mendapatkan ekstraksi Critical CSS untuk CSS-in-JS, kita perlu SSR. SSR adalah proses menghasilkan HTML final untuk keadaan aplikasi tertentu di server. Bahkan, ini bisa menjadi proses yang cukup rumit dan mahal. Ini membutuhkan sejumlah siklus CPU di server untuk setiap permintaan HTTP.

CSS-in-JS biasanya memanfaatkan fakta bahwa ia terhubung ke pipeline rendering HTML. * Ia tahu HTML apa yang di-render dan CSS apa yang dibutuhkan sehingga mampu menghasilkan jumlah minimal absolut dari itu. CSS kritis menambahkan overhead tambahan ke rendering HTML di server karena CSS itu juga perlu dikompilasi menjadi string CSS final. Dalam beberapa skenario, sulit atau bahkan tidak mungkin untuk melakukan cache pada server.

Rendering kotak hitam

Anda perlu mengetahui bagaimana perpustakaan CSS-in-JS yang Anda gunakan merender CSS Anda. Misalnya, orang sering tidak menyadari bagaimana Komponen dan Emosi yang Ditata menerapkan gaya dinamis. Gaya dinamis adalah sintaks yang memungkinkan penggunaan fungsi JavaScript di dalam deklarasi gaya Anda. Fungsi-fungsi tersebut menerima alat peraga dan mengembalikan blok CSS.

Untuk menjaga kekhususan urutan sumber, kedua pustaka yang disebutkan di atas menghasilkan aturan CSS baru jika mengandung deklarasi dinamis dan pembaruan komponen dengan alat peraga baru. Untuk menunjukkan apa yang saya maksud, saya membuat kotak pasir ini. Di JSS kami memutuskan untuk mengambil tradeoff yang berbeda, yang memungkinkan kami untuk memperbarui properti dinamis tanpa menghasilkan aturan CSS baru. *

Curam kurva pembelajaran

Bagi orang-orang yang terbiasa dengan CSS, tetapi baru mengenal JavaScript, jumlah awal pekerjaan untuk mempercepat dengan CSS-in-JS mungkin cukup besar.

Anda tidak perlu menjadi pengembang JavaScript profesional untuk menulis CSS-in-JS, sampai pada titik di mana logika kompleks terlibat. Kami tidak dapat menggeneralisasikan kompleksitas penataan, karena sangat tergantung pada penggunaannya. Dalam kasus di mana CSS-in-JS menjadi kompleks, kemungkinan implementasi dengan vanilla CSS akan menjadi lebih kompleks.

Untuk gaya dasar CSS-in-JS, kita perlu tahu cara mendeklarasikan variabel, cara menggunakan string templat, dan menginterpolasi nilai-nilai JavaScript. Jika notasi objek digunakan, seseorang perlu tahu cara bekerja dengan objek JavaScript dan sintaksis berbasis objek khusus perpustakaan. Jika gaya dinamis terlibat, orang perlu tahu cara menggunakan fungsi dan kondisi JavaScript.

Secara keseluruhan ada kurva belajar, kita tidak bisa menyangkalnya. Kurva pembelajaran ini biasanya tidak jauh lebih besar daripada pembelajaran Sass. Bahkan, saya membuat kursus egghead ini untuk menunjukkan ini.

Tidak ada interoperabilitas

Kebanyakan lib CSS-in-JS tidak dapat dioperasikan. Ini berarti bahwa gaya yang ditulis menggunakan satu pustaka tidak dapat dirender menggunakan pustaka yang berbeda. Secara praktis itu berarti Anda tidak dapat mengalihkan seluruh aplikasi Anda dengan mudah dari satu implementasi ke implementasi lainnya. Ini juga berarti bahwa Anda tidak dapat dengan mudah membagikan UI Anda di NPM tanpa membawa pustaka pilihan CSS-in-JS ke dalam bundel konsumen kecuali Anda memiliki ekstraksi statis build-time untuk CSS Anda.

Kami sudah mulai bekerja pada format ISTF yang seharusnya memperbaiki masalah ini, tetapi sayangnya kami belum punya waktu untuk membawanya ke keadaan siap-produksi. *

Saya pikir berbagi kerangka kerja komponen agnostik UI yang dapat digunakan kembali dalam domain publik masih merupakan masalah yang umumnya sulit dipecahkan.

Risiko keamanan

Dimungkinkan untuk memperkenalkan kebocoran keamanan dengan CSS-in-JS. Seperti halnya aplikasi sisi klien, Anda harus selalu lolos dari input pengguna sebelum membuatnya, selalu.

Artikel ini akan memberi Anda lebih banyak wawasan dan beberapa contoh buruk.

Nama kelas yang tidak dapat dibaca

Beberapa orang masih menganggap penting bahwa kita menyimpan nama kelas yang dapat dibaca di web. Saat ini, banyak perpustakaan CSS-in-JS menyediakan nama kelas yang bermakna berdasarkan nama deklarasi atau nama komponen dalam mode pengembangan. Beberapa dari mereka bahkan membiarkan Anda menyesuaikan fungsi generator nama kelas.

Dalam mode produksi, kebanyakan dari mereka menghasilkan nama yang lebih pendek untuk muatan yang lebih kecil. Ini adalah tradeoff yang harus dibuat oleh pengguna perpustakaan dan menyesuaikan perpustakaan jika diperlukan.

Kesimpulan

Ada pengorbanan, dan saya mungkin bahkan tidak menyebutkan semuanya. Tetapi kebanyakan dari mereka tidak berlaku secara universal untuk semua CSS-in-JS. Mereka bergantung pada perpustakaan yang Anda gunakan dan bagaimana Anda menggunakannya.

* Dibutuhkan artikel khusus untuk menjelaskan kalimat ini. Beri tahu saya di Twitter (@ oleg008) tentang yang mana yang ingin Anda baca lebih lanjut.