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

DevTools mimarisi yenileme: 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 geçmişte Geliştirici Araçları'nda nasıl çalıştığını ve JavaScript dosyalarına CSS yüklemek için web standardı bir çözüme geçişe hazırlık amacıyla (nihayetinde) Geliştirici Araçları'nda CSS'mizi nasıl modernleştirdiğimizi açıklayacağız.

CSS'nin Geliştirici Araçları'ndaki Ö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 de Geliştirici Araçları'nda kullanılan modern web bileşenleri için.

Geliştirici Araçları'ndaki CSS uygulaması yıllar önce tanımlanmıştır ve artık geçerliliğini yitirmiştir. Geliştirici Araçları module.json kalıbını kullanmaya devam etti ve bu dosyaları kaldırmak için çok çalıştı. Bu dosyaların kaldırılmasını engelleyen son engelleyici, CSS dosyalarını yüklemek için kullanılan resources bölümüdür.

Zamanla CSS Modülü Komut Dosyalarına dönüşebilecek farklı potansiyel çözümleri keşfetmek istedik. Amaç, eski sistemin neden olduğu teknik borcu kaldırmak ve CSS Modülü Komut Dosyalarına geçiş sürecini kolaylaştırmaktı.

Geliştirici Araçları'nda bulunan CSS dosyaları, kaldırılma sürecinde olan bir module.json dosyası kullanılarak yüklendiklerinden "eski" olarak kabul edildi. Tüm CSS dosyalarının, CSS dosyasıyla aynı dizinde yer alan bir module.json dosyasında resources altında listelenmesi gerekiyordu.

Kalan module.json dosyası örneği:

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

Daha sonra bu CSS dosyaları, içeriklerindeki bir yoldan eşleme olarak Root.Runtime.cachedResources adlı global nesne haritasını doldurur. Geliştirici Araçları'na stil eklemek için, yüklemek istediğiniz dosyanın tam yoluyla registerRequiredCSS yöntemini çağırmanı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 bunu sayfaya bir <style> öğesi olarak ekler:

Bir 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 (özel öğeler kullanarak) kullanıma sunduğumuzda başlangıçta CSS'yi bileşen dosyalarındaki satır içi <style> etiketleriyle kullanmaya karar verdik. Bu durum, beraberinde başka zorluklar da getiriyor:

  • Söz dizimi vurgulama desteği yoktur. Satır içi CSS için söz dizimi vurgulaması sağlayan eklentiler, .css dosyalarında yazılan CSS'deki söz dizimi vurgulama ve otomatik tamamlama özellikleri kadar başarılı değildir.
  • Performansı genel olarak derleyin. Satır içi CSS aynı zamanda satır içi CSS için bir adet CSS dosyaları ve satır içi CSS için olmak üzere iki geçiş kartı olması gerektiği anlamına da geliyordu. Bu, tüm CSS'nin bağımsız CSS dosyalarında yazılması durumunda kaldırabileceğimiz bir performans ek yüküydü.
  • Meydan okumayı sadeleştirme. Satır içi CSS kolayca küçültülemediğinden hiçbir CSS küçültülmedi. Geliştirici Araçları'nın sürüm derlemesinin dosya boyutu, aynı web bileşeninin birden fazla örneği tarafından oluşturulan kopya CSS ile de artırıldı.

Staj projemin hedefi, hem eski altyapıyla hem de Geliştirici Araçları'nda kullanılan yeni web bileşenleriyle çalışan CSS altyapısı için bir çözüm bulmaktı.

Olası çözümleri araştırma

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

  • Derleme sisteminin CSS dosyalarıyla nasıl başa çıkacağını anlama.
  • 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 bölüm için farklı olası çözümleri inceledik ve bunlar aşağıda özetlenmiştir.

CSS Dosyalarını İçe Aktarma

TypeScript dosyalarında CSS'nin içe aktarılması ve kullanılmasıyla ilgili hedef, web standartlarına mümkün olduğunca yakın kalmak, DevTools genelinde tutarlılığı sağlamak ve HTML'mizde yinelenen CSS'leri önlemekti. Ayrıca, değişikliklerimizi CSS Modül Komut Dosyaları gibi yeni web platformu standartlarına taşımamızı mümkün kılan bir çözüm seçebilmek istiyorduk.

Bu nedenle @import ifadeleri ve etiketleri Geliştirici Araçları için uygun görünmüyordu. Geliştirici Araçları'nın geri kalanındaki içe aktarma işlemleri için aynı biçimde olmaz ve Flash Of Unstyled Content (FOUC) durumuna neden olur. İçe aktarma işlemlerinin, <link> etiketlerine göre açıkça farklı şekilde eklenmesi ve ele alınması gerekeceğinden, CSS Modülü Komut Dosyalarına taşıma işlemi 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ı CSSStyleSheet nesnesi olarak içe aktarmanın bir yolunu bulmayı tercih ettik. Böylece dosyayı Shadow Dom'a ekleyebiliyoruz (DevTools birkaç yıldır Gölge DOM'u kullanıyor) ve adoptedStyleSheets özelliğini kullanıyor.

Paketleyici seçenekleri

CSS dosyalarını CSSStyleSheet nesnesine dönüştürüp TypeScript dosyasında kolayca değiştirebileceğimiz bir yönteme ihtiyacımız vardı. Bu dönüşümü bizim için gerçekleştirmesi amacıyla hem Rollup'ı hem de webpack'i potansiyel paketleyiciler olarak değerlendirdik. DevTools üretim derlemesinde zaten Rollup aracını kullanıyor, ancak iki paketleyiciden birini üretim derlemesine eklemek, mevcut derleme sistemimizle çalışırken potansiyel performans sorunlarına yol açabilir. Chromium'un GN derleme sistemi ile entegrasyonumuz, gruplamayı daha zor hale getirir ve bu nedenle, paketleyiciler mevcut Chromium derleme sistemiyle iyi bir şekilde entegre olmaz.

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

Geliştirici Araçları'nda CSS kullanma için yeni altyapı

Yeni çözüm, document veya ShadowRoot tarafından alınabilecek CSSStyleSheet nesneleri oluşturmak amacıyla GN derleme sistemini kullanırken belirli bir Gölge DOM'ye stil eklemek için adoptedStyleSheets kullanılmasını 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 birçok avantajı vardır:

  • Modern bir web standardı olma yolunda ilerlemektedir
  • CSS'nin kopyalanmasını önler
  • Stilleri yalnızca Gölge DOM'a uygular ve 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ı gibi gelecekteki web standartlarına kolayca geçiş

Çözümle ilgili tek uyarı, import ifadelerinin .css.js dosyasının içe aktarılmasının gerekmesiydi. GN'nin derleme sırasında CSS dosyası oluşturmasını sağlamak için generate_css_js_files.js komut dosyasını yazdık. Derleme sistemi artık her CSS dosyasını işler ve bunları, 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 benimseyebildiğimiz için bu harika bir özelliktir. Ayrıca artık üretim derlemesini kolayca küçülterek dosya boyutundan tasarruf edebiliriz:

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;

Örnek, komut dosyasından iconButton.css.js oluşturdu.

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

Web bileşenleri manuel olarak kolayca taşınabilse de registerRequiredCSS ürününün eski kullanımlarını taşıma işlemi daha karmaşıktı. Eski stilleri kaydeden iki ana işlev şunlardı: registerRequiredCSS ve createShadowRootWithCoreStyles. Bu çağrıları taşıma adımları oldukça mekanik olduğundan, düzeltmeleri uygulamak ve eski kodları 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 özel bir dizi özel kural kullanmaktadır. Bu, ESLint'in kodu zaten Soyut Söz Dizimi Ağacı'na(kısaltma AST) alır ve CSS'nin kaydedilmesine yönelik ç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, sıra dışı durumları yakalamaktı. Hangi uç durumların kayda alınmaya 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 bunu kullanıcıya bildirebildiğimizden emin olmak istedik. Bu durum, çalışma zamanında dosya bulunamayan hataları önleyecektir.

Taşıma için ESLint kurallarını kullanmanın dezavantajı, sistemde gerekli GN derleme dosyasını değiştiremememizdi. Bu değişikliklerin her dizinde kullanıcı tarafından manuel olarak yapılması gerekiyordu. Bu işlem daha fazla çalışma gerektirse de içe aktarılan her .css.js dosyasının gerçekten derleme sistemi tarafından oluşturulduğunu doğrulamanın iyi bir yoluydu.

Genel olarak, bu geçiş için ESLint kurallarını kullanmak çok faydalı oldu. Eski kodu yeni altyapıya hızlıca taşıyabildik. Ayrıca AST'nin hazır olması, kuraldaki çeşitli uç durumları ele alabilmemizi ve ESLint’in düzeltme API'sini kullanarak bunları güvenilir bir şekilde otomatik olarak düzeltmemizi sağladı.

Sırada ne var?

Şu ana kadar Chromium Geliştirici Araçları'ndaki tüm web bileşenleri, satır içi stilleri kullanmak yerine yeni CSS altyapısını kullanacak şekilde taşındı. registerRequiredCSS ürününün eski kullanımlarının çoğu da yeni sistemi kullanmak üzere taşındı. Geriye sadece mümkün olduğunca fazla module.json dosyasını kaldırıp bu mevcut altyapıyı taşıyarak gelecekte CSS Modülü Komut Dosyaları'nı uygulamaya koymanız yeterli.

Önizleme kanallarını indirme

Varsayılan geliştirme tarayıcınız olarak Chrome Canary, Yeni geliştirilenler veya Beta'yı kullanmayı düşünün. Bu önizleme kanallarıyla Geliştirici Araçları'nın en yeni özelliklerine erişebilir, son teknoloji ürünü web platformu API'lerini test edebilir ve sitenizdeki sorunları kullanıcılarınızdan önce tespit edebilirsiniz!

Chrome Geliştirici Araçları ekibiyle iletişim kurma

Yayındaki yeni özellikler ve değişiklikler ya da Geliştirici Araçları ile ilgili diğer konular hakkında konuşmak için aşağıdaki seçenekleri kullanın.

  • crbug.com adresinden öneri veya geri bildirim gönderin.
  • Geliştirici Araçları'nda, Diğer seçenekler   Diğer > Yardım > Geliştirici Araçları sorunu bildir'i kullanarak Geliştirici Araçları sorunlarını bildirin.
  • @ChromeDevTools adresine tweet gönderin.
  • Geliştirici Araçları'ndaki YouTube videoları veya Geliştirici Araçları İpuçları YouTube videolarındaki yenilikler hakkındaki görüşlerinizi bizimle paylaşın.