Memodernisasi infrastruktur CSS di DevTools

Pembaruan arsitektur DevTools: Memodernisasi infrastruktur CSS di DevTools

Postingan ini adalah bagian dari serangkaian postingan blog yang menjelaskan perubahan yang kami lakukan pada arsitektur DevTools dan cara pembuatannya. Kami akan menjelaskan bagaimana CSS bekerja di DevTools secara historis dan bagaimana kami telah memodernisasi CSS di DevTools sebagai persiapan untuk (akhirnya) bermigrasi ke solusi standar web untuk memuat CSS di file JavaScript.

Status CSS sebelumnya di DevTools

DevTools mengimplementasikan CSS dengan dua cara berbeda: satu untuk file CSS yang digunakan di bagian lama DevTools, satu untuk komponen web modern yang digunakan di DevTools.

Implementasi CSS di DevTools didefinisikan bertahun-tahun yang lalu dan sekarang sudah ketinggalan zaman. DevTools berhenti menggunakan pola module.json dan ada upaya besar dalam menghapus file ini. Pemblokir terakhir untuk penghapusan file ini adalah bagian resources, yang digunakan untuk memuat file CSS.

Kami ingin menghabiskan waktu untuk mengeksplorasi berbagai solusi potensial yang pada akhirnya dapat berubah menjadi Skrip Modul CSS. Tujuannya adalah untuk menghilangkan utang teknis yang disebabkan oleh sistem lama, dan juga membuat proses migrasi ke Skrip Modul CSS menjadi lebih mudah.

Setiap file CSS yang ada di DevTools dianggap sebagai 'lama' karena dimuat menggunakan file module.json, yang sedang dalam proses penghapusan. Semua file CSS harus dicantumkan di resources dalam file module.json di direktori yang sama dengan file CSS.

Contoh file module.json yang tersisa:

{
  "resources": [
    "serviceWorkersView.css",
    "serviceWorkerUpdateCycleView.css"
  ]
}

File CSS ini kemudian akan mengisi peta objek global yang disebut Root.Runtime.cachedResources sebagai pemetaan dari jalur ke kontennya. Untuk menambahkan gaya ke DevTools, Anda harus memanggil registerRequiredCSS dengan jalur yang tepat ke file yang ingin dimuat.

Contoh panggilan registerRequiredCSS:

constructor() {
  …
  this.registerRequiredCSS('ui/legacy/components/quick_open/filteredListWidget.css');
  …
}

Tindakan ini akan mengambil konten file CSS dan memasukkannya sebagai elemen <style> ke halaman menggunakan fungsi appendStyle.

Fungsi appendStyle yang menambahkan CSS menggunakan elemen gaya inline:

const content = Root.Runtime.cachedResources.get(cssFile) || '';

if (!content) {
  console.error(cssFile + ' not preloaded. Check module.json');
}

const styleElement = document.createElement('style');
styleElement.textContent = content;
node.appendChild(styleElement);

Saat memperkenalkan komponen web modern (menggunakan elemen kustom), kami memutuskan untuk menggunakan CSS melalui tag <style> inline dalam file komponen itu sendiri. Hal ini menimbulkan tantangan tersendiri:

  • Kurangnya dukungan sorotan sintaksis. Plugin yang menyediakan penyorotan sintaksis untuk CSS inline cenderung tidak sebaik penyorotan sintaksis dan fitur pelengkapan otomatis untuk CSS yang ditulis dalam file .css.
  • Overhead performa build. CSS inline juga berarti perlu ada dua penerusan untuk analisis lint: satu untuk file CSS dan satu untuk CSS inline. Ini adalah overhead performa yang bisa kita hapus jika semua CSS ditulis dalam file CSS mandiri.
  • Tantangan dalam minifikasi. CSS inline tidak dapat diperkecil dengan mudah, sehingga tidak ada CSS yang diminifikasi. Ukuran file build rilis DevTools juga ditingkatkan oleh CSS duplikat yang diperkenalkan oleh beberapa instance komponen web yang sama.

Tujuan proyek magang saya adalah menemukan solusi untuk infrastruktur CSS yang berfungsi dengan infrastruktur lama dan komponen web baru yang digunakan di DevTools.

Meneliti solusi potensial

Masalah ini dapat dibagi menjadi dua bagian yang berbeda:

  • Mencari tahu bagaimana sistem build menangani file CSS.
  • Mencari tahu bagaimana file CSS diimpor dan digunakan oleh DevTools.

Kita telah melihat beberapa solusi potensial untuk setiap bagian dan hal tersebut diuraikan di bawah ini.

Mengimpor File CSS

Tujuan dengan mengimpor dan menggunakan CSS di file TypeScript adalah untuk tetap sedekat mungkin dengan standar web, menerapkan konsistensi di seluruh DevTools, dan menghindari CSS duplikat di HTML kami. Kami juga ingin dapat memilih solusi yang memungkinkan migrasi perubahan kami ke standar platform web baru, seperti CSS Module Script.

Karena alasan ini, pernyataan @import dan tag sepertinya tidak cocok untuk DevTools. Keduanya tidak akan seragam dengan impor di seluruh DevTools dan menghasilkan Flash Of Unstyled Content (FOUC). Migrasi ke Skrip Modul CSS akan lebih sulit karena impor harus secara eksplisit ditambahkan dan ditangani secara berbeda daripada dengan tag <link>.

const output = LitHtml.html`
<style> @import "css/styles.css"; </style>
<button> Hello world </button>`
const output = LitHtml.html`
<link rel="stylesheet" href="styles.css">
<button> Hello World </button>`

Solusi potensial menggunakan @import atau <link>.

Sebagai gantinya, kami memilih untuk menemukan cara mengimpor file CSS sebagai objek CSSStyleSheet sehingga kita dapat menambahkannya ke Shadow Dom (DevTools menggunakan Shadow DOM selama beberapa tahun sekarang) menggunakan properti adoptedStyleSheets-nya.

Opsi pemaket

Kita memerlukan cara untuk mengonversi file CSS menjadi objek CSSStyleSheet sehingga kita dapat dengan mudah memanipulasinya dalam file TypeScript. Kami mempertimbangkan Rollup dan webpack sebagai pemaket potensial untuk melakukan transformasi ini bagi kami. DevTools sudah menggunakan Rollup dalam build produksinya, tetapi menambahkan pemaket ke build produksi dapat berpotensi menimbulkan masalah performa saat bekerja dengan sistem build kita saat ini. Integrasi kami dengan sistem build GN Chromium membuat pemaketan menjadi lebih sulit, sehingga pemaket cenderung tidak terintegrasi secara baik dengan sistem build Chromium saat ini.

Sebagai gantinya, kami mengeksplorasi opsi untuk menggunakan sistem build GN saat ini untuk melakukan transformasi ini.

Infrastruktur baru penggunaan CSS di DevTools

Solusi baru ini melibatkan penggunaan adoptedStyleSheets untuk menambahkan gaya ke Shadow DOM tertentu saat menggunakan sistem build GN untuk menghasilkan objek CSSStyleSheet yang dapat diadopsi oleh document atau ShadowRoot.

// CustomButton.ts

// Import the CSS style sheet contents from a JS file generated from CSS
import customButtonStyles from './customButton.css.js';
import otherStyles from './otherStyles.css.js';

export class CustomButton extends HTMLElement{
  …
  connectedCallback(): void {
    // Add the styles to the shadow root scope
    this.shadow.adoptedStyleSheets = [customButtonStyles, otherStyles];
  }
}

Menggunakan adoptedStyleSheets memiliki beberapa manfaat, termasuk:

  • Ini sedang dalam proses menjadi standar web modern
  • Mencegah CSS duplikat
  • Menerapkan gaya hanya pada Shadow DOM dan akan menghindari masalah yang disebabkan oleh nama class atau pemilih ID duplikat dalam file CSS
  • Mudah dimigrasikan ke standar web mendatang seperti CSS Module Scripts dan Import Assertion

Satu-satunya peringatan untuk solusi ini adalah bahwa pernyataan import memerlukan file .css.js untuk diimpor. Untuk memungkinkan GN membuat file CSS selama proses build, kita menulis skrip generate_css_js_files.js. Sistem build kini memproses setiap file CSS dan mengubahnya menjadi file JavaScript yang secara default mengekspor objek CSSStyleSheet. Hal ini bagus karena kita dapat mengimpor file CSS dan mengadopsinya dengan mudah. Selain itu, sekarang kita juga dapat meminifikasi build produksi dengan mudah, sehingga menghemat ukuran file:

const styles = new CSSStyleSheet();
styles.replaceSync(
  // In production, we also minify our CSS styles
  /`${isDebug ? output : cleanCSS.minify(output).styles}
  /*# sourceURL=${fileName} */`/
);

export default styles;

Contoh yang dibuat iconButton.css.js dari skrip.

Memigrasikan kode lama menggunakan aturan ESLint

Meskipun komponen web dapat dimigrasikan dengan mudah secara manual, proses migrasi penggunaan registerRequiredCSS lama lebih rumit. Dua fungsi utama yang mendaftarkan gaya lama adalah registerRequiredCSS dan createShadowRootWithCoreStyles. Kami memutuskan bahwa karena langkah untuk memigrasikan panggilan ini cukup mekanis, kami dapat menggunakan aturan ESLint untuk menerapkan perbaikan dan memigrasikan kode lama secara otomatis. DevTools sudah menggunakan sejumlah aturan kustom khusus untuk codebase DevTools. Ini berguna karena ESLint telah mengurai kode menjadi Abstract Syntax Tree(abbr. AST) dan kita dapat mengkueri {i>node<i} panggilan tertentu yang merupakan panggilan untuk mendaftarkan CSS.

Masalah terbesar yang kami hadapi saat menulis Aturan ESLint migrasi adalah merekam kasus ekstrem. Kami ingin memastikan bahwa kami mendapatkan keseimbangan yang tepat antara mengetahui kasus ekstrem mana yang layak diambil dan mana yang harus dimigrasikan secara manual. Kita juga ingin memastikan bahwa kita dapat memberi tahu pengguna saat file .css.js yang diimpor tidak otomatis dihasilkan oleh sistem build karena hal ini akan mencegah error pada file tidak ditemukan saat runtime.

Satu kelemahan menggunakan aturan ESLint untuk migrasi adalah kami tidak dapat mengubah file build GN yang diperlukan dalam sistem. Perubahan ini harus dilakukan secara manual oleh pengguna di setiap direktori. Meskipun memerlukan lebih banyak upaya, ini adalah cara yang baik untuk mengonfirmasi bahwa setiap file .css.js yang diimpor benar-benar dihasilkan oleh sistem build.

Secara keseluruhan, penggunaan aturan ESLint untuk migrasi ini sangat membantu karena kami dapat memigrasikan kode lama dengan cepat ke infrastruktur baru dan memiliki AST yang tersedia berarti kami juga dapat menangani beberapa kasus ekstrem dalam aturan dan memperbaikinya secara otomatis dengan andal menggunakan API perbaikan ESLint.

Bagaimana selanjutnya?

Sejauh ini, semua komponen web di Chromium DevTools telah dimigrasikan untuk menggunakan infrastruktur CSS baru, bukan menggunakan gaya inline. Sebagian besar penggunaan registerRequiredCSS lama juga telah dimigrasikan untuk menggunakan sistem baru. Anda hanya perlu menghapus sebanyak mungkin file module.json, lalu memigrasikan infrastruktur saat ini untuk menerapkan Skrip Modul CSS di masa mendatang.

Mendownload saluran pratinjau

Pertimbangkan untuk menggunakan Chrome Canary, Dev, atau Beta sebagai browser pengembangan default Anda. Saluran pratinjau ini memberi Anda akses ke fitur DevTools terbaru, menguji API platform web tercanggih, dan menemukan masalah di situs Anda sebelum pengguna melakukannya.

Menghubungi tim Chrome DevTools

Gunakan opsi berikut untuk membahas fitur dan perubahan baru di postingan, atau hal lain yang berkaitan dengan DevTools.

  • Kirim saran atau masukan kepada kami melalui crbug.com.
  • Laporkan masalah DevTools menggunakan Opsi lainnya   Lainnya   > Bantuan > Laporkan masalah DevTools di DevTools.
  • Tweet di @ChromeDevTools.
  • Berikan komentar di video YouTube Apa yang baru di DevTools atau video YouTube Tips DevTools.