Aktualisierung der DevTools-Architektur: Modernisierung der CSS-Infrastruktur in den DevTools
Dieser Beitrag ist Teil einer Reihe von Blogbeiträgen, in denen die Änderungen an der Architektur und der Erstellung von DevTools beschrieben werden. Wir erklären, wie CSS in DevTools bisher funktioniert hat und wie wir unser CSS in DevTools modernisiert haben, um auf eine Webstandardlösung für das Laden von CSS in JavaScript-Dateien umzustellen.
Vorheriger CSS-Status in den Entwicklertools
In den DevTools wird CSS auf zwei verschiedene Arten implementiert: eine für CSS-Dateien, die im alten Teil der DevTools verwendet werden, und eine für die modernen Webkomponenten, die in den DevTools verwendet werden.
Die CSS-Implementierung in DevTools wurde vor vielen Jahren definiert und ist jetzt veraltet. In den DevTools wird weiterhin das module.json
-Muster verwendet und es war ein enormer Aufwand erforderlich, diese Dateien zu entfernen. Der letzte Stolperstein für das Entfernen dieser Dateien ist der Abschnitt resources
, mit dem CSS-Dateien geladen werden.
Wir wollten uns Zeit nehmen, um verschiedene potenzielle Lösungen zu untersuchen, die sich schließlich in CSS-Modulscripts verwandeln könnten. Ziel war es, die durch das alte System verursachten technischen Altlasten zu beseitigen und gleichzeitig die Migration zu CSS-Modulscripts zu vereinfachen.
Alle CSS-Dateien in den DevTools wurden als „alt“ eingestuft, da sie über eine module.json
-Datei geladen wurden, die derzeit entfernt wird. Alle CSS-Dateien mussten in einer module.json
-Datei im selben Verzeichnis wie die CSS-Datei unter resources
aufgeführt sein.
Beispiel für eine verbleibende module.json
-Datei:
{
"resources": [
"serviceWorkersView.css",
"serviceWorkerUpdateCycleView.css"
]
}
Diese CSS-Dateien würden dann eine globale Objektkarte namens Root.Runtime.cachedResources
als Zuordnung von einem Pfad zu ihrem Inhalt füllen. Wenn Sie Stile in den DevTools hinzufügen möchten, müssen Sie registerRequiredCSS
mit dem genauen Pfad zur Datei aufrufen, die Sie laden möchten.
Beispiel für einen registerRequiredCSS
Anruf:
constructor() {
…
this.registerRequiredCSS('ui/legacy/components/quick_open/filteredListWidget.css');
…
}
Dadurch wird der Inhalt der CSS-Datei abgerufen und mithilfe der Funktion appendStyle
als <style>
-Element in die Seite eingefügt:
appendStyle
-Funktion, die CSS mit einem Inline-Style-Element hinzufügt:
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);
Als wir moderne Webkomponenten (mit benutzerdefinierten Elementen) einführten, haben wir uns anfangs dafür entschieden, CSS über Inline-<style>
-Tags in den Komponentendateien selbst zu verwenden. Das stellte uns vor neue Herausforderungen:
- Keine Unterstützung für Syntaxhervorhebung Plugins, die Syntaxhervorhebung für Inline-CSS bieten, sind in der Regel nicht so gut wie die Syntaxhervorhebung und die automatische Vervollständigung für CSS, das in
.css
-Dateien geschrieben wurde. - Leistungsoverhead verursachen. Inline-CSS bedeutete auch, dass zwei Durchläufe für das Linting erforderlich waren: einer für CSS-Dateien und einer für Inline-CSS. Dies war ein Leistungsoverhead, den wir entfernen konnten, wenn das gesamte CSS in eigenständigen CSS-Dateien geschrieben wurde.
- Herausforderung bei der Minimierung Inline-CSS konnte nicht einfach minimiert werden, daher wurde kein CSS minimiert. Die Dateigröße des Release-Builds von DevTools wurde auch durch das duplizierte CSS erhöht, das durch mehrere Instanzen derselben Webanwendung eingeführt wurde.
Ziel meines Praktikumsprojekts war es, eine Lösung für die CSS-Infrastruktur zu finden, die sowohl mit der alten Infrastruktur als auch mit den neuen Webkomponenten funktioniert, die in DevTools verwendet werden.
Mögliche Lösungen recherchieren
Das Problem lässt sich in zwei Teile unterteilen:
- Herausfinden, wie das Build-System mit CSS-Dateien umgeht.
- Herausfinden, wie die CSS-Dateien von DevTools importiert und verwendet werden.
Wir haben uns verschiedene potenzielle Lösungen für jeden Teil angesehen. Diese werden unten beschrieben.
CSS-Dateien importieren
Ziel des Imports und der Verwendung von CSS in den TypeScript-Dateien war es, die Webstandards so genau wie möglich einzuhalten, für Einheitlichkeit in den DevTools zu sorgen und doppelte CSS-Dateien in unserer HTML-Datei zu vermeiden. Außerdem wollten wir eine Lösung auswählen, mit der sich unsere Änderungen zu neuen Webplattformstandards wie CSS-Modulscripts migrieren lassen.
Aus diesen Gründen eigneten sich die @import-Anweisungen und -Tags nicht für die Entwicklertools. Sie würden nicht mit den Importen im Rest von DevTools übereinstimmen und zu einem Flash of Unstyled Content (FOUC) führen. Die Migration zu CSS-Modulscripts wäre schwieriger, da die Importe explizit hinzugefügt und anders behandelt werden müssten als bei <link>
-Tags.
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>`
Mögliche Lösungen mit @import
oder <link>
Stattdessen haben wir nach einer Möglichkeit gesucht, die CSS-Datei als CSSStyleSheet
-Objekt zu importieren, damit wir sie über die Property adoptedStyleSheets
dem Shadow DOM hinzufügen können (in den DevTools wird seit einigen Jahren Shadow DOM verwendet).
Optionen für den Bündelungsdienst
Wir brauchten eine Möglichkeit, CSS-Dateien in ein CSSStyleSheet
-Objekt umzuwandeln, damit wir sie in der TypeScript-Datei einfach bearbeiten konnten. Wir haben sowohl Rollup als auch webpack als potenzielle Bundler für diese Transformation in Betracht gezogen. In DevTools wird bereits Rollup im Produktionsbuild verwendet. Wenn jedoch einer der beiden Bundler dem Produktionsbuild hinzugefügt wird, kann es bei der Verwendung unseres aktuellen Build-Systems zu Leistungsproblemen kommen. Die Integration in das GN-Buildsystem von Chromium erschwert das Bündeln. Daher lassen sich Bündelprogramme in der Regel nicht gut in das aktuelle Chromium-Buildsystem einbinden.
Stattdessen haben wir die Möglichkeit untersucht, diese Transformation mit dem aktuellen GN-Buildsystem durchzuführen.
Die neue Infrastruktur für die Verwendung von CSS in den Entwicklertools
Bei der neuen Lösung werden mit adoptedStyleSheets
Stile für ein bestimmtes Shadow DOM hinzugefügt, während mit dem GN-Build-System CSSStyleSheet-Objekte generiert werden, die von einem document
oder ShadowRoot
übernommen werden können.
// 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];
}
}
Die Verwendung von adoptedStyleSheets
bietet mehrere Vorteile:
- Es ist in der Entwicklung zu einem modernen Webstandard.
- Verhindert doppelte Preisvergleichsportale
- Stile werden nur auf ein Shadow DOM angewendet. Dadurch werden Probleme vermieden, die durch doppelte Klassennamen oder ID-Selektoren in CSS-Dateien verursacht werden.
- Einfache Migration zu zukünftigen Webstandards wie CSS-Modulscripts und Importaussagen
Der einzige Nachteil der Lösung war, dass die import
-Anweisungen die Importierung der .css.js
-Datei erforderten. Damit GN während des Builds eine CSS-Datei generieren kann, haben wir das Script generate_css_js_files.js
geschrieben. Das Build-System verarbeitet jetzt jede CSS-Datei und wandelt sie in eine JavaScript-Datei um, die standardmäßig ein CSSStyleSheet
-Objekt exportiert. Das ist großartig, da wir die CSS-Datei importieren und einfach anpassen können. Außerdem können wir den Produktions-Build jetzt ganz einfach minimieren und so die Dateigröße reduzieren:
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;
Beispiel für ein vom Script generiertes iconButton.css.js
Legacy-Code mit ESLint-Regeln migrieren
Während die Webkomponenten einfach manuell migriert werden konnten, war die Migration der bisherigen Verwendungen von registerRequiredCSS
aufwendiger. Die beiden Hauptfunktionen, mit denen alte Stile registriert wurden, waren registerRequiredCSS
und createShadowRootWithCoreStyles
. Da die Schritte zur Migration dieser Aufrufe ziemlich mechanisch waren, entschieden wir uns, ESLint-Regeln zu verwenden, um Fehler zu beheben und Altcode automatisch zu migrieren. In DevTools werden bereits eine Reihe von benutzerdefinierten Regeln verwendet, die speziell für die DevTools-Codebasis gelten. Das war hilfreich, da ESLint den Code bereits in einen abstrakten Syntaxbaum(AST, AST) und wir konnten die bestimmten Aufrufknoten abfragen, die Aufrufe zur Registrierung von Preisvergleichsportalen waren.
Die größte Herausforderung beim Erstellen der ESLint-Regeln für die Migration bestand darin, Grenzfälle zu berücksichtigen. Wir wollten das richtige Gleichgewicht zwischen den Grenzfällen finden, die es wert waren, erfasst zu werden, und denen, die manuell migriert werden sollten. Außerdem wollten wir Nutzern mitteilen können, wenn eine importierte .css.js
-Datei nicht automatisch vom Build-System generiert wird, da dies Laufzeitfehler verhindert.
Ein Nachteil der Verwendung von ESLint-Regeln für die Migration war, dass wir die erforderliche GN-Builddatei im System nicht ändern konnten. Diese Änderungen mussten vom Nutzer in jedem Verzeichnis manuell vorgenommen werden. Das erforderte zwar mehr Arbeit, war aber eine gute Möglichkeit, zu bestätigen, dass jede importierte .css.js
-Datei tatsächlich vom Build-System generiert wird.
Insgesamt war die Verwendung von ESLint-Regeln für diese Migration sehr hilfreich, da wir den alten Code schnell in die neue Infrastruktur migrieren konnten. Da der AST sofort verfügbar war, konnten wir auch mehrere Grenzfälle in der Regel behandeln und sie mithilfe der Fixer API von ESLint zuverlässig automatisch beheben.
Nächster Schritt
Bisher wurden alle Webkomponenten in den Chromium DevTools auf die neue CSS-Infrastruktur umgestellt, anstatt Inline-Styles zu verwenden. Die meisten bisherigen Verwendungen von registerRequiredCSS
wurden ebenfalls auf das neue System umgestellt. Jetzt müssen Sie nur noch so viele module.json
-Dateien wie möglich entfernen und dann diese aktuelle Infrastruktur migrieren, um in Zukunft CSS-Modulscripts zu implementieren.
Vorschaukanäle herunterladen
Verwenden Sie als Standard-Entwicklungsbrowser Chrome Canary, Chrome Dev oder Chrome Beta. Diese Vorabversionen bieten Ihnen Zugriff auf die neuesten DevTools-Funktionen, ermöglichen es Ihnen, innovative Webplattform-APIs zu testen, und helfen Ihnen, Probleme auf Ihrer Website zu finden, bevor Ihre Nutzer sie bemerken.
Chrome-Entwicklertools-Team kontaktieren
Mit den folgenden Optionen können Sie über neue Funktionen, Updates oder andere Themen im Zusammenhang mit den DevTools sprechen.
- Senden Sie uns Feedback und Funktionsanfragen unter crbug.com.
- Melden Sie ein DevTools-Problem über das Dreipunkt-Menü Weitere Optionen > Hilfe > DevTools-Problem melden.
- Tweeten Sie an @ChromeDevTools.
- Hinterlassen Sie Kommentare unter den YouTube-Videos zu den Neuigkeiten in den DevTools oder den YouTube-Videos mit Tipps zu den DevTools.