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 cara kerja CSS di DevTools secara historis dan cara kami memodernisasi CSS di DevTools sebagai persiapan untuk (pada akhirnya) bermigrasi ke solusi standar web untuk memuat CSS dalam file JavaScript.
Status CSS Sebelumnya di DevTools
DevTools menerapkan 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 ditentukan bertahun-tahun yang lalu dan sekarang sudah tidak berlaku lagi. DevTools tetap menggunakan pola module.json
dan telah dilakukan upaya besar untuk menghapus file ini. Pemblokir terakhir untuk penghapusan file ini adalah bagian resources
, yang digunakan untuk memuat file CSS.
Kami ingin meluangkan waktu untuk mempelajari berbagai solusi potensial yang pada akhirnya dapat berubah menjadi Skrip Modul CSS. Tujuannya adalah untuk menghapus utang teknis yang disebabkan oleh sistem lama, tetapi juga mempermudah proses migrasi ke Skrip Modul CSS.
Semua 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 bagian 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 menyisipkannya sebagai elemen <style>
ke dalam 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 pada awalnya 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 sebagus fitur penyorotan sintaksis dan pelengkapan otomatis untuk CSS yang ditulis dalam file
.css
. - Membuat overhead performa. CSS inline juga berarti bahwa harus ada dua tahap untuk linting: satu untuk file CSS dan satu untuk CSS inline. Ini adalah overhead performa yang dapat kita hapus jika semua CSS ditulis dalam file CSS mandiri.
- Tantangan dalam minifikasi. CSS inline tidak dapat diminifikasi dengan mudah, sehingga tidak ada CSS yang diminifikasi. Ukuran file build rilis DevTools juga meningkat karena CSS duplikat yang diperkenalkan oleh beberapa instance komponen web yang sama.
Tujuan project 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 cara sistem build menangani file CSS.
- Mencari tahu cara file CSS diimpor dan digunakan oleh DevTools.
Kami telah mempelajari berbagai kemungkinan solusi untuk setiap bagian dan solusi tersebut diuraikan di bawah.
Mengimpor File CSS
Tujuan mengimpor dan menggunakan CSS dalam file TypeScript adalah untuk tetap mengikuti standar web sebanyak mungkin, menerapkan konsistensi di seluruh DevTools, dan menghindari CSS duplikat di HTML kita. Kami juga ingin dapat memilih solusi yang memungkinkan kami memigrasikan perubahan ke standar platform web baru, seperti Skrip Modul CSS.
Karena alasan ini, pernyataan @import dan tag tampaknya tidak cocok untuk DevTools. Hal ini tidak akan seragam dengan impor di seluruh DevTools dan akan menghasilkan Flash Of Unstyled Content (FOUC). Migrasi ke Skrip Modul CSS akan lebih sulit karena impor harus ditambahkan secara eksplisit dan ditangani secara berbeda 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, kita 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 paket
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 potensi bundler untuk melakukan transformasi ini bagi kami. DevTools sudah menggunakan Rollup dalam build produksinya, tetapi menambahkan salah satu alat pembuat paket ke build produksi dapat berpotensi menimbulkan masalah performa saat menggunakan sistem build saat ini. Integrasi kami dengan sistem build GN Chromium mempersulit proses bundling sehingga penggabungan cenderung tidak terintegrasi dengan baik dengan sistem build Chromium saat ini.
Sebagai gantinya, kami mempelajari opsi untuk menggunakan sistem build GN saat ini untuk melakukan transformasi ini.
Infrastruktur baru untuk menggunakan CSS di DevTools
Solusi baru ini melibatkan penggunaan adoptedStyleSheets
untuk menambahkan gaya ke Shadow DOM tertentu saat menggunakan sistem build GN untuk membuat 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:
- Standar ini sedang dalam proses menjadi standar web modern
- Mencegah CSS duplikat
- Menerapkan gaya hanya ke Shadow DOM dan ini menghindari masalah yang disebabkan oleh nama class atau pemilih ID duplikat dalam file CSS
- Mudah dimigrasikan ke standar web mendatang seperti Skrip Modul CSS dan Pernyataan Impor
Satu-satunya pengecualian untuk solusi ini adalah pernyataan import
mengharuskan file .css.js
diimpor. Agar GN dapat 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 sangat bagus karena kita dapat mengimpor file CSS dan mengadopsinya dengan mudah. Selain itu, kita juga dapat dengan mudah melakukan minifikasi build produksi, 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 iconButton.css.js
yang dihasilkan dari skrip.
Memigrasikan kode lama menggunakan aturan ESLint
Meskipun komponen web dapat dimigrasikan dengan mudah secara manual, proses untuk memigrasikan penggunaan lama registerRequiredCSS
lebih rumit. Dua fungsi utama yang mendaftarkan gaya lama adalah registerRequiredCSS
dan createShadowRootWithCoreStyles
. Kami memutuskan bahwa karena langkah-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. Hal ini berguna karena ESLint telah mengurai kode menjadi Abstract Syntax Tree(singkatan dari AST) dan kita dapat membuat kueri node panggilan tertentu yang merupakan panggilan untuk mendaftarkan CSS.
Masalah terbesar yang kami hadapi saat menulis Aturan ESLint migrasi adalah menangkap 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 dapat memastikan bahwa kita dapat memberi tahu pengguna saat file .css.js
yang diimpor tidak dibuat secara otomatis oleh sistem build karena hal ini mencegah error file tidak ditemukan saat runtime.
Salah satu kelemahan menggunakan aturan ESLint untuk migrasi adalah kita tidak dapat mengubah file build GN yang diperlukan di sistem. Perubahan ini harus dilakukan secara manual oleh pengguna di setiap direktori. Meskipun memerlukan lebih banyak pekerjaan, ini adalah cara yang baik untuk mengonfirmasi bahwa setiap file .css.js
yang diimpor sebenarnya dihasilkan oleh sistem build.
Secara keseluruhan, menggunakan aturan ESLint untuk migrasi ini sangat membantu karena kami dapat dengan cepat memigrasikan kode lama ke infrastruktur baru dan dengan tersedianya AST, kami juga dapat menangani beberapa kasus ekstrem dalam aturan dan memperbaikinya secara otomatis dan andal menggunakan API fixer ESLint.
Apa selanjutnya?
Sejauh ini, semua komponen web di Chromium DevTools telah dimigrasikan untuk menggunakan infrastruktur CSS baru, bukan menggunakan gaya inline. Sebagian besar penggunaan lama registerRequiredCSS
juga telah dimigrasikan untuk menggunakan sistem baru. Yang tersisa hanyalah menghapus file module.json
sebanyak mungkin, lalu memigrasikan infrastruktur saat ini untuk menerapkan Skrip Modul CSS di masa mendatang.
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.
- Kirim masukan dan permintaan fitur kepada kami di crbug.com.
- Laporkan masalah DevTools menggunakan Opsi lainnya > Bantuan > Laporkan masalah DevTools di DevTools.
- Tweet ke @ChromeDevTools.
- Berikan komentar di video YouTube Yang baru di DevTools atau video YouTube Tips DevTools.