Geliştirici Araçları'nda CSS altyapısını modernleştirme

Geliştirici Araçları mimarisi yenilemesi: Geliştirici Araçları'nda CSS altyapısını modernleştirme

Bu gönderi, Geliştirici Araçları mimarisinde yaptığımız değişiklikleri ve nasıl oluşturulduğunu açıklayan bir dizi blog yayınının bir parçasıdır. CSS'nin Geliştirici Araçları'nda geçmişte nasıl çalıştığını ve CSS'yi JavaScript dosyalarında yüklemeye yönelik standart bir web çözümüne geçmeye hazırlanırken (nihayetinde) CSS'mizi Geliştirici Araçları'nda nasıl modernleştirdiğimizi açıklayacağız.

Geliştirici Araçları'nda CSS'nin önceki durumu

Geliştirici Araçları, CSS'yi iki farklı şekilde uyguladı: biri, Geliştirici Araçları'nın eski bölümünde kullanılan CSS dosyaları, diğeri ise Geliştirici Araçları'nda kullanılan modern web bileşenleri içindi.

DevTools'taki CSS uygulaması yıllar önce tanımlanmış ve artık güncel değildir. Geliştirici Araçları, module.json kalıbını kullanmaya devam etti ve bu dosyaları kaldırmak için büyük çaba harcadı. Bu dosyaların kaldırılmasını engelleyen son öğe, CSS dosyalarını yüklemek için kullanılan resources bölümüdür.

Zaman ayırıp CSS modülü komut dosyalarına dönüşebilecek farklı olası çözümleri keşfetmek istedik. Amaç, eski sistemin neden olduğu teknik borcu ortadan kaldırmak ve CSS modülü komut dosyalarına geçiş sürecini kolaylaştırmaktı.

DevTools'daki CSS dosyaları, kaldırılma sürecinde olan bir module.json dosyası kullanılarak yüklendiği için "eski" olarak kabul edildi. Tüm CSS dosyalarının, CSS dosyasıyla aynı dizindeki bir module.json dosyasında resources altında listelenmeleri gerekiyordu.

Kalan module.json dosyası örneği:

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

Bu CSS dosyaları daha sonra bir yol ile içeriklerinin eşlemesi olarak Root.Runtime.cachedResources adlı bir genel nesne haritasını doldurur. Geliştirici Araçları'na stil eklemek için, yüklemek istediğiniz dosyanın tam yolunu belirterek registerRequiredCSS çağrısını yapmanız gerekir.

Örnek registerRequiredCSS çağrısı:

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

Bu işlem, CSS dosyasının içeriğini alır ve appendStyle işlevini kullanarak sayfaya <style> öğesi olarak ekler:.

Satır içi stil öğesi kullanarak CSS ekleyen appendStyle işlevi:

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);

Modern web bileşenlerini kullanıma sunduğumuzda (özel öğeler kullanılarak), ilk olarak bileşen dosyalarında satır içi <style> etiketleri aracılığıyla CSS kullanmaya karar verdik. Bu durum, kendi zorluklarını da beraberinde getirdi:

  • Söz dizimi vurgulama desteği yok. Satır içi CSS için söz dizimi vurgulama sağlayan eklentiler, .css dosyalarında yazılan CSS'deki söz dizimi vurgulama ve otomatik tamamlama özellikleri kadar iyi değildir.
  • Performans yükü oluşturma Satır içi CSS, linting için iki geçiş yapılması gerektiği anlamına da geliyordu: biri CSS dosyaları, diğeri satır içi CSS için. Tüm CSS'ler bağımsız CSS dosyalarında yazılmış olsaydı bu performans yükü kaldırılabilirdi.
  • Küçültmeyle ilgili zorluk. Satır içi CSS kolayca küçültülemediğinden CSS'nin hiçbiri küçültülmedi. DevTools'un sürüm derlemesinin dosya boyutu, aynı web bileşeninin birden fazla örneği tarafından tanıtılan yinelenen CSS nedeniyle de artmıştı.

Staj projemin amacı, CSS altyapısı için hem eski altyapı hem de DevTools'da kullanılan yeni web bileşenleriyle çalışan bir çözüm bulmaktı.

Potansiyel çözümleri araştırma

Sorun iki farklı bölüme ayrılabilir:

  • Derleme sisteminin CSS dosyalarıyla nasıl çalıştığına karar verme.
  • CSS dosyalarının nasıl içe aktarıldığını ve Geliştirici Araçları tarafından nasıl kullanıldığını anlama

Her bir parça için farklı olası çözümleri inceledik ve bunlar aşağıda özetlenmiştir.

CSS dosyalarını içe aktarma

TypeScript dosyalarına CSS'yi içe aktarıp kullanmanın amacı, web standartlarına olabildiğince sadık kalmak, DevTools'da tutarlılık sağlamak ve HTML'mizde yinelenen CSS'den kaçınmaktı. Ayrıca, değişikliklerimizi CSS Modül Komut Dosyaları gibi yeni web platformu standartlarına taşımamızı sağlayacak bir çözüm seçebilmek istedik.

Bu nedenlerden dolayı @import ifadeleri ve etiketleri, DevTools için uygun bir seçenek olarak görünmüyordu. Bu öğeler, DevTools'un geri kalanındaki içe aktarma işlemleriyle uyumlu olmaz ve stil uygulanmamış içeriğin gösterilmesine (FOUC) neden olur. İçe aktarma işlemlerinin <link> etiketleriyle olduğundan farklı şekilde açıkça eklenmesi ve işlenmesi gerektiğinden CSS modülü komut dosyalarına geçiş daha zor olur.

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>`

@import veya <link> kullanan olası çözümler.

Bunun yerine, CSS dosyasını adoptedStyleSheets özelliğini kullanarak Shadow Dom'a (Geliştirici Araçları birkaç yıldır Gölge DOM'u kullanıyor) ekleyebilmek için CSSStyleSheet nesnesi olarak içe aktarmanın bir yolunu bulmaya karar verdik.

Paketleyici seçenekleri

TypeScript dosyasında kolayca değiştirebilmemiz için CSS dosyalarını CSSStyleSheet nesnesine dönüştürmenin bir yoluna ihtiyacımız vardı. Bu dönüşümü bizim için yapacak potansiyel paketleyiciler olarak hem Rollup hem de webpack'ı değerlendirdik. DevTools, üretim derlemesinde zaten Rollup'u kullanıyor ancak üretim derlemesine bu paketleyicilerden birini eklemek, mevcut derleme sistemimizle çalışırken olası performans sorunlarına neden olabilir. Chromium'un GN derleme sistemi ile entegrasyonumuz, paketlemeyi daha zor hale getiriyor. Bu nedenle, paketleyiciler mevcut Chromium derleme sistemiyle iyi entegre olmuyor.

Bunun yerine, bu dönüşümü bizim için yapmak üzere mevcut GN derleme sistemini kullanma seçeneğini araştırdık.

Geliştirici Araçları'nda CSS'yi kullanmanın yeni altyapısı

Yeni çözüm, belirli bir gölge DOM'a stil eklemek için adoptedStyleSheets'ü, document veya ShadowRoot tarafından benimsenebilecek CSSStyleSheet nesneleri oluşturmak için GN derleme sistemini kullanmayı içerir.

// 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];
  }
}

adoptedStyleSheets kullanmanın aşağıdakiler gibi birçok avantajı vardır:

  • Modern bir web standardı olma yolunda ilerliyor
  • Yinelenen CSS'yi önler
  • Stilleri yalnızca Gölge DOM'a uygular. Bu sayede, CSS dosyalarındaki yinelenen sınıf adları veya kimlik seçicilerden kaynaklanan sorunlar önlenir.
  • CSS Modülü Komut Dosyaları ve İçe Aktarma Onaylarını gibi gelecekteki web standartlarına kolay geçiş

Çözümün tek sakıncası, import ifadelerinin .css.js dosyasının içe aktarılmasını gerektirmesiydi. GN'nin derleme sırasında bir CSS dosyası oluşturmasına izin vermek için generate_css_js_files.js komut dosyasını yazdık. Derleme sistemi artık her CSS dosyasını işler ve varsayılan olarak bir CSSStyleSheet nesnesini dışa aktaran bir JavaScript dosyasına dönüştürür. CSS dosyasını içe aktarıp kolayca kullanabileceğimiz için bu çok iyi. Ayrıca, artık üretim derlemesini kolayca küçülterek dosya boyutunda tasarruf sağlayabiliyoruz:

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;

Komut dosyasından iconButton.css.js oluşturulan örnek.

Eski kodu ESLint kurallarını kullanarak taşıma

Web bileşenleri manuel olarak kolayca taşınabilirken registerRequiredCSS'ün eski kullanımlarının taşınması daha karmaşık bir süreçti. Eski stilleri kaydeden iki ana işlev registerRequiredCSS ve createShadowRootWithCoreStyles idi. Bu çağrıları taşımayla ilgili adımlar oldukça mekanik olduğundan, düzeltmeleri uygulamak ve eski kodu otomatik olarak taşımak için ESLint kurallarını kullanabileceğimize karar verdik. Geliştirici Araçları, halihazırda Geliştirici Araçları kod tabanına özgü bir dizi özel kural kullanmaktadır. ESLint zaten kodu bir Soyut Söz Dizimi Ağacı'na (kısaltması AST) ayrıştırdığı için bu faydalı oldu. AST) ve CSS kaydetme çağrıları olan belirli çağrı düğümlerini sorgulayabiliriz.

Taşıma ESLint Kurallarını yazarken karşılaştığımız en büyük sorun, uç durumları tespit etmekti. Hangi uç durumların yakalanmaya değer olduğunu ve hangilerinin manuel olarak taşınması gerektiğini bilmek arasında doğru dengeyi sağladığımızdan emin olmak istedik. Ayrıca, içe aktarılan bir .css.js dosyası derleme sistemi tarafından otomatik olarak oluşturulmadığında kullanıcıya bunu bildirebilmeyi de istedik. Bu sayede, çalışma zamanında dosya bulunamadı hatalarını önleyebiliriz.

Taşıma işlemi için ESLint kurallarının kullanılmasının bir dezavantajı, sistemdeki gerekli GN derleme dosyasını değiştiremememizdi. Bu değişikliklerin her dizinde kullanıcı tarafından manuel olarak yapılması gerekiyordu. Daha fazla çalışma gerekse de bu, içe aktarılan her .css.js dosyasının aslında derleme sistemi tarafından oluşturulduğunu doğrulamak için iyi bir yöntem oldu.

Eski kodu yeni altyapıya hızlıca taşıyabildiğimiz ve AST'nin hazır olması sayesinde kural içindeki birden fazla uç durumu da ele alabildiğimiz ve ESLint'in fixer API'sini kullanarak bunları otomatik olarak güvenilir bir şekilde düzeltebileceğimiz için bu taşıma işlemi için ESLint kurallarını kullanmak genel olarak çok faydalı oldu.

Sonra ne olur?

Şu ana kadar Chromium Geliştirici Araçları'ndaki tüm web bileşenleri, satır içi stiller kullanmak yerine yeni CSS altyapısını kullanacak şekilde taşındı. registerRequiredCSS'ün eski kullanımlarının çoğu da yeni sisteme taşındı. Tek yapmanız gereken, mümkün olduğunca fazla module.json dosyasını kaldırmak ve ardından gelecekte CSS Modülü Komut Dosyalarını uygulamak üzere bu mevcut altyapıyı taşımaktır.

Önizleme kanallarını indirme

Varsayılan geliştirme tarayıcınız olarak Chrome Canary, Yeni geliştirilenler veya Beta sürümünü kullanabilirsiniz. Bu önizleme kanalları, en son DevTools özelliklerine erişmenizi sağlar, en yeni web platformu API'lerini test etmenize olanak tanır ve sitenizdeki sorunları kullanıcılarınızdan önce bulmanıza yardımcı olur.

Chrome Geliştirici Araçları Ekibi ile iletişime geçme

Yeni özellikler, güncellemeler veya Geliştirici Araçları ile ilgili başka herhangi bir konu hakkında konuşmak için aşağıdaki seçenekleri kullanın.