Dukungan CSS-in-JS di DevTools

Alex Rudenko
Alex Rudenko

Artikel ini membahas dukungan CSS-in-JS di DevTools yang diluncurkan sejak Chrome 85 dan, secara umum, apa yang kami maksud dengan CSS-in-JS dan perbedaannya dengan CSS reguler yang telah didukung oleh DevTools sejak lama.

Apa yang dimaksud dengan CSS-in-JS?

Definisi CSS-in-JS agak samar. Secara luas, ini adalah pendekatan untuk mengelola kode CSS menggunakan JavaScript. Misalnya, hal ini dapat berarti bahwa konten CSS ditentukan menggunakan JavaScript dan output CSS akhir dihasilkan secara langsung oleh aplikasi.

Dalam konteks DevTools, CSS-in-JS berarti konten CSS dimasukkan ke dalam halaman menggunakan CSSOM API. CSS reguler dimasukkan menggunakan elemen <style> atau <link>, dan memiliki sumber statis (misalnya, node DOM atau resource jaringan). Sebaliknya, CSS-in-JS sering kali tidak memiliki sumber statis. Kasus khusus di sini adalah konten elemen <style> dapat diperbarui menggunakan CSSOM API, sehingga sumber menjadi tidak sinkron dengan stylesheet CSS yang sebenarnya.

Jika Anda menggunakan library CSS-in-JS (misalnya styled-component, Emotion, JSS), library tersebut mungkin memasukkan gaya menggunakan CSSOM API di balik layar, bergantung pada mode pengembangan dan browser.

Mari kita lihat beberapa contoh cara memasukkan stylesheet menggunakan CSSOM API yang mirip dengan yang dilakukan library CSS-in-JS.

// Insert new rule to an existing CSS stylesheet
const element = document.querySelector('style');
const stylesheet = element.sheet;
stylesheet.replaceSync('.some { color: blue; }');
stylesheet.insertRule('.some { color: green; }');

Anda juga dapat membuat stylesheet yang benar-benar baru:

// Create a completely new stylesheet
const stylesheet = new CSSStyleSheet();
stylesheet.replaceSync('.some { color: blue; }');
stylesheet.insertRule('.some { color: green; }');

// Apply constructed stylesheet to the document
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];

Dukungan CSS di DevTools

Di DevTools, fitur yang paling umum digunakan saat menangani CSS adalah panel Gaya. Di panel Gaya, Anda dapat melihat aturan yang berlaku untuk elemen tertentu dan Anda dapat mengedit aturan serta melihat perubahan di halaman secara real time.

Sebelum tahun lalu, dukungan untuk aturan CSS yang diubah menggunakan CSSOM API agak terbatas: Anda hanya dapat melihat aturan yang diterapkan, tetapi tidak dapat mengeditnya. Sasaran utama kami tahun lalu adalah memungkinkan pengeditan aturan CSS-in-JS menggunakan panel Gaya. Terkadang kita juga menyebut gaya CSS-in-JS "dibuat" untuk menunjukkan bahwa gaya tersebut dibuat menggunakan Web API.

Mari kita pelajari detail cara kerja pengeditan Gaya di DevTools.

Mekanisme pengeditan gaya di DevTools

Mekanisme pengeditan gaya di DevTools

Saat Anda memilih elemen di DevTools, panel Gaya akan ditampilkan. Panel Gaya mengeluarkan perintah CDP yang disebut CSS.getMatchedStylesForNode untuk mendapatkan aturan CSS yang berlaku untuk elemen. CDP adalah singkatan dari Chrome DevTools Protocol dan merupakan API yang memungkinkan frontend DevTools mendapatkan informasi tambahan tentang halaman yang diperiksa.

Saat dipanggil, CSS.getMatchedStylesForNode mengidentifikasi semua stylesheet dalam dokumen dan mengurainya menggunakan parser CSS browser. Kemudian, alat ini membuat indeks yang mengaitkan setiap aturan CSS dengan posisi di sumber stylesheet.

Anda mungkin bertanya, mengapa perlu mengurai CSS lagi? Masalahnya di sini adalah karena alasan performa, browser itu sendiri tidak memperhatikan posisi sumber aturan CSS dan, oleh karena itu, tidak menyimpannya. Namun, DevTools memerlukan posisi sumber untuk mendukung pengeditan CSS. Kami tidak ingin pengguna Chrome biasa membayar penalti performa, tetapi kami ingin pengguna DevTools memiliki akses ke posisi sumber. Pendekatan penguraian ulang ini mengatasi kedua kasus penggunaan dengan kerugian minimal.

Selanjutnya, implementasi CSS.getMatchedStylesForNode meminta mesin gaya browser untuk memberikan aturan CSS yang cocok dengan elemen yang diberikan. Terakhir, metode ini mengaitkan aturan yang ditampilkan oleh mesin gaya dengan kode sumber dan memberikan respons terstruktur tentang aturan CSS sehingga DevTools mengetahui bagian aturan mana yang merupakan pemilih atau properti. Hal ini memungkinkan DevTools mengedit pemilih dan properti secara independen.

Sekarang, mari kita lihat pengeditan. Ingat bahwa CSS.getMatchedStylesForNode menampilkan posisi sumber untuk setiap aturan? Hal ini sangat penting untuk pengeditan. Saat Anda mengubah aturan, DevTools akan mengeluarkan perintah CDP lain yang benar-benar memperbarui halaman. Perintah ini menyertakan posisi asli fragmen aturan yang sedang diperbarui dan teks baru yang akan digunakan untuk memperbarui fragmen.

Di backend, saat menangani panggilan edit, DevTools akan memperbarui stylesheet target. Fungsi ini juga memperbarui salinan sumber stylesheet yang dikelolanya dan memperbarui posisi sumber untuk aturan yang diperbarui. Sebagai respons terhadap panggilan edit, frontend DevTools akan mendapatkan kembali posisi yang diperbarui untuk fragmen teks yang baru saja diperbarui.

Hal ini menjelaskan mengapa mengedit CSS-in-JS di DevTools tidak langsung berfungsi: CSS-in-JS tidak memiliki sumber sebenarnya yang disimpan di mana pun dan aturan CSS berada di memori browser dalam struktur data CSSOM.

Cara kami menambahkan dukungan untuk CSS-in-JS

Jadi, untuk mendukung pengeditan aturan CSS-in-JS, kami memutuskan bahwa solusi terbaiknya adalah membuat sumber untuk stylesheet yang dibuat yang dapat diedit menggunakan mekanisme yang ada yang dijelaskan di atas.

Langkah pertama adalah mem-build teks sumber. Mesin gaya browser menyimpan aturan CSS di class CSSStyleSheet. Class tersebut adalah class yang instance-nya dapat Anda buat dari JavaScript seperti yang telah dibahas sebelumnya. Kode untuk mem-build teks sumber adalah sebagai berikut:

String InspectorStyleSheet::CollectStyleSheetRules() {
  StringBuilder builder;
  for (unsigned i = 0; i < page_style_sheet_->length(); i++) {
    builder.Append(page_style_sheet_->item(i)->cssText());
    builder.Append('\n');
  }
  return builder.ToString();
}

Fungsi ini melakukan iterasi pada aturan yang ditemukan dalam instance CSSStyleSheet dan membuat satu string darinya. Metode ini dipanggil saat instance class InspectorStyleSheet dibuat. Class InspectorStyleSheet menggabungkan instance CSSStyleSheet dan mengekstrak metadata tambahan yang diperlukan oleh DevTools:

void InspectorStyleSheet::UpdateText() {
  String text;
  bool success = InspectorStyleSheetText(&text);
  if (!success)
    success = InlineStyleSheetText(&text);
  if (!success)
    success = ResourceStyleSheetText(&text);
  if (!success)
    success = CSSOMStyleSheetText(&text);
  if (success)
    InnerSetText(text, false);
}

Dalam cuplikan ini, kita melihat CSSOMStyleSheetText yang memanggil CollectStyleSheetRules secara internal. CSSOMStyleSheetText dipanggil jika stylesheet tidak inline atau stylesheet resource. Pada dasarnya, kedua cuplikan ini sudah memungkinkan pengeditan dasar stylesheet yang dibuat menggunakan konstruktor new CSSStyleSheet().

Kasus khusus adalah stylesheet yang terkait dengan tag <style> yang telah diubah menggunakan CSSOM API. Dalam hal ini, stylesheet berisi teks sumber dan aturan tambahan yang tidak ada dalam sumber. Untuk menangani kasus ini, kita memperkenalkan metode untuk menggabungkan aturan tambahan tersebut ke dalam teks sumber. Di sini, urutan penting karena aturan CSS dapat disisipkan di tengah teks sumber asli. Misalnya, bayangkan elemen <style> asli berisi teks berikut:

/* comment */
.rule1 {}
.rule3 {}

Kemudian, halaman menyisipkan beberapa aturan baru menggunakan JS API yang menghasilkan urutan aturan berikut: .rule0, .rule1, .rule2, .rule3, .rule4. Teks sumber yang dihasilkan setelah operasi penggabungan akan terlihat seperti berikut:

.rule0 {}
/* comment */
.rule1 {}
.rule2 {}
.rule3 {}
.rule4 {}

Pemeliharaan komentar dan indentasi asli penting untuk proses pengeditan karena posisi teks sumber aturan harus akurat.

Aspek lain yang khusus untuk stylesheet CSS-in-JS adalah stylesheet tersebut dapat diubah oleh halaman kapan saja. Jika aturan CSSOM yang sebenarnya tidak sinkron dengan versi teks, pengeditan tidak akan berfungsi. Untuk itu, kami memperkenalkan yang disebut probe, yang memungkinkan browser memberi tahu bagian backend DevTools saat stylesheet diubah. Stylesheet yang diubah kemudian disinkronkan selama panggilan berikutnya ke CSS.getMatchedStylesForNode.

Dengan semua bagian ini, pengeditan CSS-in-JS sudah berfungsi, tetapi kita ingin meningkatkan UI untuk menunjukkan apakah stylesheet telah dibuat. Kami telah menambahkan atribut baru bernama isConstructed ke CSS.CSSStyleSheetHeader CDP yang digunakan frontend untuk menampilkan sumber aturan CSS dengan benar:

Stylesheet yang dapat dibuat

Kesimpulan

Untuk merangkum cerita kita di sini, kita telah membahas kasus penggunaan yang relevan terkait CSS-in-JS yang tidak didukung DevTools dan membahas solusi untuk mendukung kasus penggunaan tersebut. Bagian yang menarik dari implementasi ini adalah kita dapat memanfaatkan fungsi yang ada dengan membuat aturan CSS CSSOM memiliki teks sumber reguler, sehingga tidak perlu menata ulang sepenuhnya pengeditan gaya di DevTools.

Untuk mengetahui latar belakang selengkapnya, lihat proposal desain kami atau bug pelacakan Chromium yang mereferensikan semua patch terkait.

Mendownload saluran pratinjau

Sebaiknya gunakan Chrome Canary, Dev, atau Beta sebagai browser pengembangan default Anda. Saluran pratinjau ini memberi Anda akses ke fitur DevTools terbaru, memungkinkan Anda menguji API platform web canggih, dan membantu Anda menemukan masalah di situs sebelum pengguna melakukannya.

Hubungi tim Chrome DevTools

Gunakan opsi berikut untuk membahas fitur baru, update, atau hal lain yang terkait dengan DevTools.