


Erstellen Sie ein Node.js -Tool, um Google Lighthouse -Berichte aufzuzeichnen und zu vergleichen
In diesem Tutorial zeige ich Ihnen Schritt für Schritt, wie Sie ein einfaches Tool in node.js erstellen, um Google Lighthouse -Audits über die Befehlszeile auszuführen, die Berichte zu speichern, die sie im JSON -Format erstellen, und diese dann zu vergleichen, damit die Webleistung beobachtet werden kann, wenn die Website wächst und sich entwickelt.
Ich hoffe, dass dies als gute Einführung für jeden Entwickler dienen kann, der daran interessiert ist, dass er programmatisch mit Google Lighthouse zusammenarbeitet.
Aber zuerst für die Uneingeweihten…
Was ist Google Lighthouse?
Google Lighthouse ist eines der am besten automatischen Tools, die auf dem Utility-Gürtel eines Webentwicklers verfügbar sind. Sie können eine Website in einer Reihe von Schlüsselbereichen schnell prüfen, die zusammen ein Maß für die Gesamtqualität bilden können. Diese sind:
- Leistung
- Zugänglichkeit
- Best Practices
- SEO
- Progressive Web -App
Sobald das Audit abgeschlossen ist, wird ein Bericht auf dem generiert, was Ihre Website gut macht… und nicht so gut, wobei letztere als Indikator für die nächsten Schritte dienen sollen, um die Seite zu verbessern.
So sieht ein vollständiger Bericht aus.
Zusammen mit anderen allgemeinen Diagnostik- und Web-Leistungsmetriken besteht eine wirklich nützliche Funktion des Berichts darin, dass jeder der Schlüsselbereiche in farbcodierte Bewertungen zwischen 0 und 100 aggregiert wird.
Dies ermöglicht es den Entwicklern nicht nur, die Qualität einer Website ohne weitere Analysen schnell zu messen, sondern ermöglicht es auch nicht technische Leute wie Stakeholder oder Kunden, zu verstehen.
Dies bedeutet beispielsweise, dass es viel einfacher ist, den Sieg mit Heather aus dem Marketing zu teilen, nachdem sie Zeit damit verbracht hat, die Zugänglichkeit der Website zu verbessern, da sie die Anstrengungen mehr zu schätzen wissen, nachdem sie den Lighthouse -Barrierefreiheitswert um 50 Punkte in das Grün stieg.
Aber ebenso wie Simon, der Projektmanager, versteht möglicherweise nicht, welchen Speed -Index oder der erste inhaltliche Farbe bedeutet, aber wenn er den Lighthouse -Bericht zeigt, der die Website -Performance -Punktzahl tief im Rot zeigt, weiß er, dass Sie noch Arbeit zu tun haben.
Wenn Sie sich in Chrome oder der neuesten Version von Edge befinden, können Sie sich jetzt mit Devtools ein Lighthouse -Audit ausführen. So wie: wie:
Sie können auch ein Lighthouse -Audit online über PageSpeed -Erkenntnisse oder über beliebte Leistungstools wie WebPagetest durchführen.
Heute interessieren wir uns jedoch nur für Lighthouse als Knotenmodul, da wir das Tool programmgesteuert verwenden können, um Web -Leistungsmetriken zu prüfen, aufzunehmen und zu vergleichen.
Lassen Sie uns herausfinden, wie.
Aufstellen
Wenn Sie es noch nicht haben, brauchen Sie Node.js. Es gibt eine Million verschiedene Möglichkeiten, es zu installieren. Ich benutze den Homebrew -Paket -Manager, aber Sie können auch einen Installateur direkt von der Node.js -Website herunterladen, wenn Sie es vorziehen. Dieses Tutorial wurde mit node.js v10.17.0 geschrieben, wird jedoch sehr wahrscheinlich bei den meisten in den letzten Jahren veröffentlichten Versionen gut funktionieren.
Sie werden auch Chrome installiert benötigen, da wir so die Leuchtturmprüfungen ausführen werden.
Erstellen Sie als nächstes ein neues Verzeichnis für das Projekt und dann in der Konsole ein CD. Führen Sie dann NPM Init aus, um eine Package.json -Datei zu erstellen. Zu diesem Zeitpunkt würde ich empfehlen, die Eingabetaste immer wieder zu verprügeln, um so viel wie möglich davon zu überspringen, bis die Datei erstellt wurde.
Lassen Sie uns nun eine neue Datei im Projektverzeichnis erstellen. Ich habe meine Lh.js angerufen, aber ich zögern Sie nicht, es so zu nennen, was Sie wollen. Dies enthält das gesamte JavaScript für das Tool. Öffnen Sie es in Ihrem Texteditor Ihrer Wahl und schreiben Sie vorerst eine Konsole.log -Anweisung.
console.log ('Hallo Welt');
Stellen Sie dann in der Konsole sicher, dass Ihr CWD (aktuelles Arbeitsverzeichnis) Ihr Projektverzeichnis ist, und führen Sie den Knoten Lh.js aus und ersetzen Sie meinen Dateinamen für alles, was Sie verwendet haben.
Sie sollten sehen:
$ node lh.js Hallo Welt
Wenn nicht, überprüfen Sie, ob Ihre Knoteninstallation funktioniert, und Sie befinden sich definitiv im richtigen Projektverzeichnis.
Nun, das ist nicht im Weg, wir können das Werkzeug selbst entwickeln.
Chrom mit node.js öffnen
Installieren wir die erste Abhängigkeit unseres Projekts: Leuchtturm selbst.
NPM Installieren Sie Leuchtturm-Save-dev
Dadurch wird ein NODE_MODULES -Verzeichnis erstellt, das alle Dateien des Pakets enthält. Wenn Sie Git verwenden, sollten Sie es nur mit dieser. Gitignore -Datei hinzufügen.
In Lh.js möchten Sie als nächstes die Testkonsole (log () löschen und das Lighthouse -Modul importieren, damit Sie sie in Ihrem Code verwenden können. Like SO:
Const Lighthouse = Request ('Lighthouse');
Darunter müssen Sie auch ein Modul namens Chrome-Leiter importieren, bei dem es sich um eine der Abhängigkeiten des Leuchtturms handelt und es den Knoten ermöglicht, Chrome für sich selbst zu starten, damit das Audit ausgeführt werden kann.
Const Lighthouse = Request ('Lighthouse'); const chromelauncher = require ('Chrom-Launcher');
Jetzt, da wir Zugriff auf diese beiden Module haben, erstellen wir ein einfaches Skript, das nur Chrome öffnet, ein Lighthouse -Audit ausführt und dann den Bericht an die Konsole druckt.
Erstellen Sie eine neue Funktion, die eine URL als Parameter akzeptiert. Da wir dies mit node.js ausführen, können wir die ES6 -Syntax sicher verwenden, da wir uns keine Sorgen um diese lästigen Internet -Explorer -Benutzer machen müssen.
const stirpchrome = (url) => { }
Innerhalb der Funktion müssen wir als erstes das Chrom mit dem von uns importierten Chrom-Launcher-Modul öffnen und an das Argument senden, das durch den URL-Parameter weitergeleitet wird.
Wir können dies mit der Start () -Methode und der Starturl -Option tun.
const stirpchrome = url => { chromelauncher.launch ({{ Starturl: URL }); };
Wenn Sie die Funktion unten aufrufen und eine URL Ihrer Auswahl übergeben, wird das Chrome bei der URL geöffnet, wenn das Knotenskript ausgeführt wird.
LaunchCrome ('https://www.lukeharrison.dev');
Die Startfunktion gibt tatsächlich ein Versprechen zurück, mit dem wir auf ein Objekt zugreifen können, das einige nützliche Methoden und Eigenschaften enthält.
Beispielsweise können wir mit dem folgenden Code Chrom öffnen, das Objekt in die Konsole drucken und Chrom drei Sekunden später mit seiner Kill () -Methode schließen.
const stirpchrome = url => { Chromelauncher .Start({ Starturl: URL }) .then (Chrome => { console.log (chrome); setTimeout (() => Chrome.kill (), 3000); }); }; LaunchCrome ("https://www.lukeharrison.dev");
Nachdem wir Chrome herausgefunden haben, gehen wir zum Leuchtturm.
Leuchtturm programmatisch ausführen
Lassen Sie uns zunächst unsere Funktion "startChrome () in etwas mehr reflektierender seiner endgültigen Funktionalität umbenennen: Startchromeandrunlighthouse (). Mit dem schwierigen Teil können wir jetzt das Lighthouse -Modul verwenden, das wir zuvor im Tutorial importiert haben.
In der damaligen Funktion des Chrome Launcher, die nur sobald der Browser geöffnet ist, werden wir das URL -Argument der Funktion über den Leuchtturm übergeben und eine Prüfung dieser Website auslösen.
const stirpchromeandrunlighthouse = url => { Chromelauncher .Start({ Starturl: URL }) .then (Chrome => { const opts = { Port: Chrome.port }; Leuchtturm (URL, Opts); }); }; LaunchCromeandrunLightHouse ("https://www.lukeharrison.dev");
Um die Lighthouse -Instanz mit unserem Chrom -Browserfenster zu verknüpfen, müssen wir zusammen mit der URL seinen Port übergeben.
Wenn Sie dieses Skript jetzt ausführen, werden Sie in der Konsole auf einen Fehler drücken:
(Knoten: 47714) UnbeschlossenesPromiserjektionSWARNING: Fehler: Sie haben wahrscheinlich mehrere Registerkarten für denselben Ursprung geöffnet.
Um dies zu beheben, müssen wir nur die Starturl -Option von Chrome Launcher entfernen und die URL -Navigation von Lighthouse von hier aus verarbeiten lassen.
const stirpchromeandrunlighthouse = url => { chromelauncher.launch (). Dann (Chrome => { const opts = { Port: Chrome.port }; Leuchtturm (URL, Opts); }); };
Wenn Sie diesen Code ausführen, werden Sie feststellen, dass etwas definitiv zu passieren scheint. Wir erhalten einfach kein Feedback in der Konsole, um zu bestätigen, dass das Lighthouse -Audit definitiv ausgeführt wurde, und die Chrome -Instanz schließt sich auch nicht wie zuvor.
Zum Glück gibt die Lighthouse () -Funktion ein Versprechen zurück, mit dem wir auf die Prüfungsergebnisse zugreifen können.
Lassen Sie uns Chrome abtöten und diese Ergebnisse dann über die Berichtseigenschaft des Ergebnisobjekts an das Terminal im JSON -Format drucken.
const stirpchromeandrunlighthouse = url => { chromelauncher.launch (). Dann (Chrome => { const opts = { Port: Chrome.port }; Leuchtturm (URL, Opts) .then (Ergebnisse => { chrome.kill (); console.log (results.Report); }); }); };
Obwohl die Konsole nicht der beste Weg ist, um diese Ergebnisse anzuzeigen, wird das Einfügen hier den Bericht in ihrem gesamten Ruhm angezeigt, wenn Sie sie in Ihre Zwischenablage kopieren und den Lighthouse Report Viewer besuchen.
Zu diesem Zeitpunkt ist es wichtig, den Code ein wenig aufzuräumen, um die Funktion der LaunchCromeandrunlighthouse () zu erstellen, die den Bericht zurückgibt, sobald er ausgeführt wird. Dies ermöglicht es uns, den Bericht später zu verarbeiten, ohne zu einer unordentlichen Pyramide von JavaScript zu führen.
Const Lighthouse = Request ("Lighthouse"); const chromelauncher = require ("Chrom-Leiter"); const stirpchromeandrunlighthouse = url => { return Chromelauncher.launch (). Dann (Chrome => { const opts = { Port: Chrome.port }; Return Lighthouse (URL, Opts) .then (Ergebnisse => { return Chrome.kill (). Dann (() => results.Report); }); }); }; LaunchCromeandrunLightHouse ("https://www.lukeharrison.dev") .then (resultation => { console.log (Ergebnisse); });
Eine Sache, die Sie vielleicht bemerkt haben, ist, dass unser Tool im Moment nur eine einzige Website prüfen kann. Ändern wir dies, damit Sie die URL als Argument über die Befehlszeile übergeben können.
Um die Schmerzen bei der Arbeit mit Befehlszeilenargumenten zu nehmen, werden wir sie mit einem Paket namens Yargs behandeln.
NPM Install-Save-dev Yargs
Importieren Sie es dann zusammen mit Chrome Launcher und Lighthouse ganz oben in Ihrem Skript. Wir brauchen hier nur seine Argv -Funktion.
Const Lighthouse = Request ('Lighthouse'); const chromelauncher = require ('Chrom-Launcher'); const argv = fordert ('yargs'). argv;
Dies bedeutet, wenn Sie ein Befehlszeilenargument wie SO übergeben:
Node lh.js --url https://www.google.co.uk
… Sie können auf das Argument im Skript wie SO zugreifen:
const url = argv.url // https://www.google.co.uk
Bearbeiten wir unser Skript, um das URL -Argument der Befehlszeile an den URL -Parameter der Funktion zu übergeben. Es ist wichtig, ein wenig Sicherheitsnetz über die IF -Anweisung und Fehlermeldung hinzuzufügen, falls kein Argument übergeben wird.
if (argv.url) { LaunchCromeandrunLightHouse (argv.url) .then (resultation => { console.log (Ergebnisse); }); } anders { Wirf "Du hast keine URL an den Leuchtturm übergeben"; }
Tada! Wir haben ein Tool, das Chrome startet und programmatisch ein Leuchtturm -Audit ausführt, bevor der Bericht im JSON -Format an das Terminal gedruckt wird.
Sparen von Leuchtturmberichten
Wenn der Bericht an die Konsole gedruckt wird, ist dies nicht sehr nützlich, da Sie seine Inhalte nicht einfach lesen und nicht für die zukünftige Verwendung gespeichert sind. In diesem Abschnitt des Tutorials ändern wir dieses Verhalten, sodass jeder Bericht in eine eigene JSON -Datei gespeichert wird.
Um Berichte von verschiedenen Websites zu verhindern, die sich verwechseln, organisieren wir sie wie so:
- lukeharrison.dev
- 2020-01-31t18: 18: 12.648z.json
- 2020-01-31t19: 10: 24.110z.json
- cnn.com
- 2020-01-14T22: 15: 10.396z.json
- lh.js
Wir werden die Berichte mit einem Zeitstempel benennen, der angibt, wann das Datum/die Uhrzeit des Berichts erstellt wurde. Dies bedeutet, dass keine zwei Berichtsdateinamen jemals gleich sein werden, und es hilft uns, zwischen Berichten leicht zu unterscheiden.
Es gibt ein Problem mit Windows, das unsere Aufmerksamkeit erfordert: The Colon (:) ist ein illegaler Zeichen für Dateinamen. Um dieses Problem zu mildern, werden wir Colons durch Unterstriche (_) ersetzen, sodass ein typischer Berichts -Dateiname so aussieht:
- 2020-01-31T18_18_12.648z.json
Erstellen des Verzeichnisses
Zunächst müssen wir das URL -Argument der Befehlszeilen manipulieren, damit wir es für den Verzeichnisnamen verwenden können.
Dies beinhaltet mehr als nur das Entfernen des WWW, da die auf Webseiten ausgeführten Audits berücksichtigt werden muss, die nicht am Root sitzen (z. B. www.foo.com/bar), da die Schrägstriche ungültige Zeichen für Verzeichnisnamen sind.
Für diese URLs ersetzen wir die ungültigen Zeichen erneut durch Unterstriche. Wenn Sie ein Audit unter https://www.foo.com/bar ausführen, lautet der resultierende Verzeichnisname, der den Bericht enthält, foo.com_bar.
Um den Umgang mit URLs zu erleichtern, verwenden wir ein nationales Node.js -Modul namens URL. Dies kann wie jedes andere Paket importiert werden und ohne es thepackage.json hinzufügen und über NPM ziehen müssen.
Const Lighthouse = Request ('Lighthouse'); const chromelauncher = require ('Chrom-Launcher'); const argv = fordert ('yargs'). argv; const url = erfordern ('url');
Lassen Sie es uns als nächstes verwenden, um ein neues URL -Objekt zu instanziieren.
if (argv.url) { const urlobj = neue URL (argv.url); LaunchCromeandrunLightHouse (argv.url) .then (resultation => { console.log (Ergebnisse); }); }
Wenn Sie Urlobj in die Konsole drucken würden, sehen Sie viele nützliche URL -Daten, die wir verwenden können.
$ node lh.js --url https://www.foo.com/bar URL { href: 'https://www.foo.com/bar', Ursprung: 'https://www.foo.com', Protokoll: 'Https:', Benutzername: '', Passwort: '', Host: 'www.foo.com', Hostname: 'www.foo.com', Hafen: '', Pfadname: '/Bar', suchen: '', SearchParams: urlSearchParams {}, Hash: '' }
Erstellen Sie eine neue Variable namens DirName und verwenden Sie die String ersetzt () -Methode auf der Hosteigenschaft unserer URL, um das WWW zusätzlich zum HTTPS -Protokoll zu entfernen:
const urlobj = neue URL (argv.url); lass DirName = urlobj.host.replace ('www.', '');
Wir haben hier Let Let verwendet, was im Gegensatz zu const neu zugewiesen werden kann, da wir die Referenz aktualisieren müssen, wenn die URL einen Pfadnamen hat, um Schrägstriche durch Unterstriche zu ersetzen. Dies kann mit einem regulären Ausdrucksmuster erfolgen und sieht so aus:
const urlobj = neue URL (argv.url); lass DirName = urlobj.host.replace ("www.", ""); if (urlobj.PathName! == "/") { DIRNAME = DIRNAME URLOBJ.PATHNAME.REPLACE (/\ // g, "_"); }
Jetzt können wir das Verzeichnis selbst erstellen. Dies kann durch die Verwendung eines anderen nativen Node.js -Moduls mit dem Namen FS (kurz für "Dateisystem") erfolgen.
Const Lighthouse = Request ('Lighthouse'); const chromelauncher = require ('Chrom-Launcher'); const argv = fordert ('yargs'). argv; const url = erfordern ('url'); const fs = erfordern ('fs');
Wir können seine mkdir () -Methode verwenden, um ein Verzeichnis zu erstellen, müssen jedoch zunächst ihre existsync () -Methode verwenden, um zu überprüfen, ob das Verzeichnis bereits vorhanden ist, da Node.js sonst einen Fehler werfen würde:
const urlobj = neue URL (argv.url); lass DirName = urlobj.host.replace ("www.", ""); if (urlobj.PathName! == "/") { DIRNAME = DIRNAME URLOBJ.PATHNAME.REPLACE (/\ // g, "_"); } if (! fs.existsSync (DirName)) { fs.mkdirsync (DirName); }
Das Testen des Skripts an dem Punkt sollte dazu führen, dass ein neues Verzeichnis erstellt wird. Übergabe https://www.bbc.co.uk/news als URL -Argument würde zu einem Verzeichnis namens BBC.co.uk_News führen.
Speichern des Berichts
In der damaligen Funktion für LaunchCromeandrunlighthouse () möchten wir die vorhandene Konsole durch Logik ersetzen, um den Bericht an die Festplatte zu schreiben. Dies kann mit der WriteFile () -Methode des FS -Moduls durchgeführt werden.
LaunchCromeandrunLightHouse (argv.url) .then (resultation => { fs.writeFile ("report.json", resulting, err => { Wenn (err) erröste; }); });
Der erste Parameter repräsentiert den Dateinamen, der zweite ist der Inhalt der Datei und der dritte ist ein Rückruf, der ein Fehlerobjekt enthält, sollte während des Schreibvorgangs etwas schief gehen. Dies würde eine neue Datei namens Report.json erstellen, die den zurückgekehrten Lighthouse -Bericht JSON -Objekt enthält.
Wir müssen es noch an das richtige Verzeichnis mit einem Zeitstempel als Dateinamen senden. Der erstere ist einfach - wir übergeben die zuvor erstellte DirName -Variable wie so:
LaunchCromeandrunLightHouse (argv.url) .then (resultation => { fs.writeFile (`$ {Dirname}/report.json`, Ergebnisse, err => { Wenn (err) erröste; }); });
Letzteres verlangt jedoch, dass wir einen Zeitstempel des Erstellens des Berichts irgendwie abrufen. Zum Glück erfasst der Bericht selbst dies als Datenpunkt und wird als FetchTime -Eigenschaft gespeichert.
Wir müssen nur daran denken, Colons (:) für Unterstriche (_) auszutauschen, damit es mit dem Windows -Dateisystem gut spielt.
LaunchCromeandrunLightHouse (argv.url) .then (resultation => { fs.writeFile ( `$ {Dirname}/$ {resultes [" fetchTime "]. Ersetzen (/:/g," _ ")}. Json`,, Ergebnisse, err => { Wenn (err) erröste; } ); });
Wenn Sie dies jetzt ausführen würden, anstatt einen Zeitstempel.
UnbeschichtetePromiserjektionWarning: TypeError: Eigentum "Ersetzen" von Undefined kann nicht lesen
Dies geschieht, weil der Leuchtturm derzeit den Bericht im JSON -Format zurückgibt und nicht ein von JavaScript konsumierbares Objekt.
Zum Glück können wir den Leuchtturm nur auffordern, den Bericht als reguläres JavaScript -Objekt zurückzugeben, anstatt den JSON selbst zu analysieren.
Dies erfordert die Bearbeitung der folgenden Zeile von:
return Chrome.kill (). Dann (() => results.Report);
…Zu:
return Chrome.kill (). Dann (() => results.lhr);
Wenn Sie nun das Skript erneut ausführen, wird die Datei korrekt benannt. Wenn es jedoch geöffnet wird, ist es nur Inhalte leider…
[Objektobjekt]
Dies liegt daran, dass wir jetzt wie zuvor das gegenteilige Problem haben. Wir versuchen, ein JavaScript -Objekt zu rendern, ohne es zuerst in ein JSON -Objekt zu streiten.
Die Lösung ist einfach. Um zu vermeiden, dass dieses riesige Objekt Ressourcen zum Analysieren oder Streben von diesem riesigen Objekt verschwenden muss, können wir beide Typen aus dem Leuchtturm zurückgeben:
Return Lighthouse (URL, Opts) .then (Ergebnisse => { return Chrome.kill (). Dann (() => { zurückkehren { JS: results.lhr, JSON: results.Report }; }); });
Anschließend können wir die Writefile -Instanz dazu ändern:
fs.writeFile ( `$ {Dirname}/$ {results.js [" FetchTime "]. Ersetzen (/:/g," _ ")}. Json`,, results.json, err => { Wenn (err) erröste; } );
Sortiert! Nach Abschluss des Lighthouse -Audits sollte unser Tool den Bericht nun in einer Datei mit einem einzigartigen Zeitstempelfilenamen in einem nach der Website -URL benannten Verzeichnis speichern.
Dies bedeutet, dass Berichte jetzt viel effizienter organisiert sind und sich gegenseitig nicht überschreien, egal wie viele Berichte gespeichert sind.
Vergleich von Leuchtturmberichten
Bei der alltäglichen Entwicklung kann ich, wenn ich mich auf die Verbesserung der Leistung konzentriere, die Fähigkeit, Berichte direkt in der Konsole zu vergleichen, sehr schnell zu vergleichen und zu prüfen, ob ich in die richtige Richtung bin, äußerst nützlich sein. In diesem Sinne sollten die Anforderungen dieser Vergleichsfunktionalität sein:
- Wenn ein früherer Bericht bereits für dieselbe Website vorhanden ist, wenn ein Leuchtturm -Audit abgeschlossen ist, führen Sie automatisch einen Vergleich damit durch und zeigen Änderungen der wichtigsten Leistungsmetriken an.
- Ich sollte auch in der Lage sein, wichtige Leistungskennzahlen aus zwei beliebigen Berichten aus zwei beliebigen Websites zu vergleichen, ohne einen neuen Leuchtturmbericht erstellen zu müssen, den ich möglicherweise nicht benötige.
Welche Teile eines Berichts sollten verglichen werden? Dies sind die im Rahmen eines Leuchtturmberichts gesammelten numerischen Schlüsselleistungskennzahlen. Sie geben Einblicke in die objektive und wahrgenommene Leistung einer Website.
Darüber hinaus sammelt Lighthouse auch andere Metriken, die in diesem Teil des Berichts nicht aufgeführt sind, aber noch in einem geeigneten Format sind, um in den Vergleich einbezogen zu werden. Diese sind:
- Zeit zum ersten Byte - Zeit zum ersten Byte identifiziert die Zeit, zu der Ihr Server eine Antwort sendet.
- Gesamtblockierungszeit - Summe aller Zeiträume zwischen FCP und Zeit bis interaktiv, wenn die Aufgabenlänge 50 ms überschritten wurde, ausgedrückt in Millisekunden.
- Geschätzte Eingabelatenz - Die geschätzte Eingabelatenz ist eine Schätzung, wie lange Ihre App in Millisekunden während des geschäftigsten 5S -Fensters des Seitenlasts auf Benutzereingaben reagiert. Wenn Ihre Latenz höher als 50 ms ist, können Benutzer Ihre App als Verzögerung wahrnehmen.
Wie sollte der metrische Vergleich an die Konsole ausgegeben werden? Wir werden einen einfachen prozentualen Vergleich mit den alten und neuen Metriken erstellen, um zu sehen, wie sie sich vom Bericht zu Bericht verändert haben.
Um ein schnelles Scannen zu ermöglichen, werden wir auch individuelle Metriken färben, je nachdem, ob sie schneller, langsamer oder unverändert sind.
Wir werden auf diese Ausgabe streben:
Vergleichen Sie den neuen Bericht mit dem vorherigen Bericht
Erstellen wir mit dem Erstellen einer neuen Funktion namens CompyReReports () direkt unter unserer Funktion startchromeandrunlighthouse (), die die gesamte Vergleichslogik enthält. Wir geben ihm zwei Parameter - von - von bis hin zu den beiden für den Vergleich verwendeten Berichten.
Im Moment drucken wir als Platzhalter nur einige Daten aus jedem Bericht an die Konsole aus, um zu bestätigen, dass sie sie richtig empfangen.
const vergleicheports = (von, bis) => { console.log (aus ["Finalurl"] "von [" FetchTime "]); console.log (an ["Finalurl"] "zu [" FetchTime "]); };
Da dieser Vergleich nach der Erstellung eines neuen Berichts beginnen würde, sollte die Logik zur Ausführung dieser Funktion in der damaligen Funktion für Startchromeandrunlighthouse () sitzen.
Wenn Sie beispielsweise 30 Berichte in einem Verzeichnis haben, müssen wir feststellen, welches der neueste ist und es als vorheriger Bericht festlegen, mit dem der neue verglichen wird. Zum Glück haben wir uns bereits entschlossen, einen Zeitstempel als Dateiname für einen Bericht zu verwenden. Dadurch gibt es uns etwas zum Arbeiten.
Zunächst müssen wir vorhandene Berichte sammeln. Um diesen Vorgang zu vereinfachen, installieren wir eine neue Abhängigkeit namens GLIB, die bei der Suche nach Dateien eine Musteranpassung ermöglicht. Dies ist kritisch, da wir nicht vorhersagen können, wie viele Berichte existieren oder wie sie genannt werden.
Installieren Sie es wie jede andere Abhängigkeit:
NPM Installieren Sie GLIP-Save-dev
Importieren Sie es dann genauso wie gewohnt oben in der Datei:
Const Lighthouse = Request ('Lighthouse'); const chromelauncher = require ('Chrom-Launcher'); const argv = fordert ('yargs'). argv; const url = erfordern ('url'); const fs = erfordern ('fs'); const glob = fordert ('glob');
Wir werden Glob verwenden, um alle Berichte im Verzeichnis zu sammeln, die wir bereits über die DirName -Variable kennen. Es ist wichtig, seine Synchronisierungsoption auf True festzulegen, da die Ausführung von JavaScript nicht weitergeht, bis wir wissen, wie viele andere Berichte vorhanden sind.
LaunchCromeandrunLightHouse (argv.url) .then (resultation => { const prevreports = glob (`$ {dirname}/*. json`, {{ Synchronisation: Richtig }); // et al });
Dieser Prozess gibt eine Reihe von Pfaden zurück. Also, wenn das Berichtsverzeichnis so aussah:
- lukeharrison.dev
- 2020-01-31T10_18_12.648z.json
- 2020-01-31T10_18_24.110z.json
… Dann würde das resultierende Array so aussehen:
[ 'Lukeharrison.dev/2020-01-31t10_18_12.648z.json', 'lukeharrison.dev/2020-01-31t10_18_24.110z.json' ]
Da wir nur einen Vergleich durchführen können, wenn ein früherer Bericht vorhanden ist, verwenden wir dieses Array als Bedingung für die Vergleichslogik:
const prevreports = glob (`$ {dirname}/*. json`, {{ Synchronisation: Richtig }); if (prevreports.length) { }
Wir haben eine Liste von Berichtsdateipfaden und müssen ihre Zeitstempelfilen vergleichen, um festzustellen, welches die neueste ist.
Dies bedeutet, dass wir zunächst eine Liste aller Dateinamen sammeln, irrelevante Daten wie Verzeichnisnamen abschneiden und darauf achten, die Unterstriche (_) durch Colons zurückzuziehen (:), um sie wieder in gültige Daten zu verwandeln. Der einfachste Weg, dies zu tun, besteht darin, den Pfad zu verwenden, ein weiteres natives Node.js -natives Modul.
const path = fordern ('path');
Übergeben des Pfades als Argument an seine Parse -Methode wie SO:
path.parse ('lukeharrison.dev/2020-01-31t10_18_24.110z.json');
Gibt dieses nützliche Objekt zurück:
{ Wurzel: '', Dir: 'Lukeharrison.dev', Basis: '2020-01-31T10_18_24.110z.json', ext: '.json', Name: '2020-01-31T10_18_24.110z' }
Um eine Liste aller Zeitnamen des Zeitstempelfils zu erhalten, können wir dies tun:
if (prevreports.length) { Daten = []; für (Bericht in den Vorbereitungen) { Dates.push ( Neues Datum (Path.Parse (PrevReports [Bericht]). Name.Replace (/_/g, ":")) ); } }
Wie wieder aussah, wenn unser Verzeichnis aussah:
- lukeharrison.dev
- 2020-01-31T10_18_12.648z.json
- 2020-01-31T10_18_24.110z.json
Würde zu:
[ '2020-01-31T10: 18: 12.648z', '2020-01-31T10: 18: 24.110Z' ]
Eine nützliche Sache an Daten ist, dass sie standardmäßig von Natur aus vergleichbar sind:
const alpha = neues Datum ('2020-01-31'); const bravo = neues Datum ('2020-02-15'); console.log (alpha> bravo); // FALSCH console.log (bravo> alpha); // WAHR
Durch die Verwendung einer Reduzierung der Funktion können wir unsere Datumsangaben bis zu den jüngsten Überresten reduzieren:
Daten = []; für (Bericht in den Vorbereitungen) { dates.push (neues Datum (path.parse (prevReports [report]). name.replace (/_/g, ":"))); } const max = dates.Reduce (Funktion (a, b) { return math.max (a, b); });
Wenn Sie den Inhalt von Max in die Konsole ausdrucken würden, würde er einen Unix -Zeitstempel aufwerfen. Jetzt müssen wir nur noch eine weitere Zeile hinzufügen, um unser letztes Datum wieder in das richtige ISO -Format umzuwandeln:
const max = dates.Reduce (Funktion (a, b) { return math.max (a, b); }); const incremeReport = neues Datum (max) .toisString ();
Angenommen, dies sind die Liste von Berichten:
- 2020-01-31T23_24_41.786z.json
- 2020-01-31T23_25_36.827z.json
- 2020-01-31T23_37_56.856z.json
- 2020-01-31T23_39_20.459z.json
- 2020-01-31T23_56_50.959z.json
Der Wert des kürzlich erschienenen Bereichs wäre 2020-01-31T23: 56: 50,959Z.
Nachdem wir den neuesten Bericht kennen, müssen wir als nächstes seinen Inhalt extrahieren. Erstellen Sie eine neue Variable namens neuere Berichte unter der jüngsten Reportvariablen und weisen Sie ihr eine leere Funktion zu.
Da wir wissen, dass diese Funktion immer ausführen muss, anstatt sie manuell aufzurufen, ist es sinnvoll, sie in ein IFFE zu machen (sofort auf den Funktionsausdruck aufgerufen), der von selbst ausgeführt wird, wenn der JavaScript -Parser sie erreicht. Dies bedeutet durch die zusätzliche Klammern:
const in LineportContents = (() => { }) ();
In dieser Funktion können wir den Inhalt des neuesten Berichts mit der ReadFileSync () -Methode des nativen FS -Moduls zurückgeben. Da dies im JSON -Format sein wird, ist es wichtig, es in ein reguläres JavaScript -Objekt zu analysieren.
const in LineportContents = (() => { const output = fs.readFilesync ( DirName "/" letztesReport.Replace (/:/g, "_") ".json", "UTF8", (Err, Ergebnisse) => { Rückgabeergebnisse; } ); return json.parse (output); }) ();
Und dann geht es darum, die Funktion vergleicheports () zu bezeichnen und sowohl den aktuellen Bericht als auch den jüngsten Bericht als Argumente zu übergeben.
vergleicheports (neuere Reportkontents, results.js);
Im Moment drucken Sie nur ein paar Details in die Konsole aus, damit wir die Berichtsdaten durch OK testen können:
https://www.lukeharrison.dev/ 2020-02-01t00: 25: 06.918Z https://www.lukeharrison.dev/ 2020-02-01t00: 25: 42.169z
Wenn Sie zu diesem Zeitpunkt Fehler erhalten, löschen Sie einen Bericht über Bericht oder Berichte ohne gültige Inhalte aus früherer Tutorial.
Vergleichen Sie zwei beliebige Berichte
Die verbleibende wichtige Anforderung war die Möglichkeit, zwei Berichte von zwei beliebigen Websites zu vergleichen. Der einfachste Weg, dies zu implementieren, besteht darin, dass der Benutzer die vollständigen Berichtsdateipfade als Befehlszeilenargumente übergeben, die wir dann an die Funktion vergleicheports () senden werden.
In der Befehlszeile würde dies so aussehen:
Node Lh.js--From lukeharrison
Um dies zu erreichen, müssen die bedingte IF -Anweisung bearbeitet werden, die nach dem Vorhandensein eines Arguments der URL -Befehlszeile prüft. Wir fügen eine zusätzliche Überprüfung hinzu, um festzustellen, ob der Benutzer gerade einen von und zum Pfad bestanden hat. Andernfalls prüfen Sie nach der URL wie zuvor. Auf diese Weise verhindern wir ein neues Leuchtturm -Audit.
if (argv.from && argv.to) { } else if (argv.url) { // et al }
Lassen Sie uns den Inhalt dieser JSON -Dateien extrahieren, sie in JavaScript -Objekte analysieren und anschließend an die Funktion vergleiche.
Wir haben JSON bereits vor dem Abrufen des neuesten Berichts an JSON analysiert. Wir können diese Funktionalität einfach in eine eigene Helferfunktion extrapolieren und an beiden Stellen verwenden.
Erstellen Sie eine neue Funktion namens GetContents (), die einen Dateipfad als Argument akzeptiert. Stellen Sie sicher, dass dies nur eine reguläre Funktion ist und nicht eine IFFE, da wir nicht möchten, dass sie ausführt, sobald der JavaScript -Parser es findet.
const getContents = pathstr => { const output = fs.ReadFilesync (Pathstr, "Utf8", (ers, Ergebnisse) => { Rückgabeergebnisse; }); return json.parse (output); }; const vergleicheports = (von, bis) => { console.log (aus ["Finalurl"] "von [" FetchTime "]); console.log (an ["Finalurl"] "zu [" FetchTime "]); };
Aktualisieren Sie dann die Funktion der letzten reportContents (), um diese extrapolierte Helferfunktion stattdessen zu verwenden:
const luddemaReportContents = getContents (DirName '/' letztemreport.replace (/:/g, '_') '.json');
In unserer neuen Bedingung müssen wir den Inhalt der Vergleichsberichte an die Funktion vergleiche () übergeben.
if (argv.from && argv.to) { Vergleiche ( GetContents (argv.from ".json"), GetContents (argv.to ".json") ); }
Wie zuvor sollte dies einige grundlegende Informationen zu den Berichten in der Konsole ausdrucken, um uns mitzuteilen, dass alles einwandfrei funktioniert.
Node lh.js--from lukeharrison
Würde zu:
https://www.lukeharrison.dev/ 2020-01-31t23_24_41.786z https://www.lukeharrison.dev/ 2020-02-01t11_16_25.221z
Vergleichslogik
Dieser Teil der Entwicklung beinhaltet die Erstellung der Vergleichslogik, um die beiden Berichte zu vergleichen, die von der Funktion "vergleicheports () empfangen werden.
Innerhalb des Objekts, das Leuchtturm zurückgibt, gibt es eine Eigenschaft namens Audits, die ein weiteres Objekt -Auflistungsmetriken, -chancen und Informationen enthält. Hier gibt es viele Informationen, von denen wir uns nicht für die Zwecke dieses Tools interessieren.
Hier ist der Eintrag für die erste inhaltliche Farbe, eine der neun Leistungsmetriken, die wir vergleichen möchten:
"Erstkonsumierter Paint": { "ID": "Erstverpackter Paint", ",", ",", "Titel": "Erste inhaltliche Farbe", "Beschreibung": "Erster inhaltlicher Farbe markiert die Zeit, zu der der erste Text oder das erste Bild gemalt wird. "Punktzahl": 1,, "ScorePlayMode": "Numeric", "numericValue": 1081.661, "DisplayValue": "1.1 s" }
Erstellen Sie ein Array, das die Schlüssel dieser neun Leistungsmetriken auflistet. Wir können dies verwenden, um das Prüfungsobjekt zu filtern:
const vergleicheports = (von, bis) => { const metricfilter = [ "Erstes in der Paint", ",", "Erstmesser-Paint", "Speed-Index", "Geschätzte Eingangs-Latenz", "Total-Blocking-Zeit", "Max-Potential-Fid", "Zeit bis zum ersten Mal", "First-CPU-Idle", "Interaktiv" ]; };
Dann werden wir eines der Prüfungsobjekte des Berichts durchlaufen und dann seinen Namen gegen unsere Filterliste verweisen. (Es spielt keine Rolle, welches Prüfungsobjekt, da beide die gleiche Inhaltsstruktur haben.)
Wenn es dort ist, dann wollen wir es nutzen.
const metricfilter = [ "Erstes in der Paint", ",", "Erstmesser-Paint", "Speed-Index", "Geschätzte Eingangs-Latenz", "Total-Blocking-Zeit", "Max-Potential-Fid", "Zeit bis zum ersten Mal", "First-CPU-Idle", "Interaktiv" ]; für (let auditObj in ["audits"]) { if (metricfilter.includes (auditObj)) { console.log (auditObj); } }
Diese Konsole.log () würde die folgenden Schlüssel in die Konsole ausdrucken:
Erstkonsum Erstmessung Speed-Index Geschätzte Eingangs-Latenz Total-Blocking-Zeit max-potential-fid Zeit bis zuerst First-CPU-Idle interaktiv
Dies bedeutet, dass wir von ['Audits'] [AuditObj] .NumericValue und an ['Audits'] [AuditObj] .NumericValue in dieser Schleife verwenden würden, um auf die Metriken selbst zuzugreifen.
Wenn wir diese mit dem Schlüssel in die Konsole drucken würden, würde dies zu einer solchen Ausgabe führen:
Erster in den ersten Instrengungen 1081.661 890.774 Erstmessungsträger 1081.661 954.774 Speed-Index 15576.70313351777 1098.622294504341 Geschätzte Eingangs-Latenz 12.8 12.8 Total-Blocking-Zeit 59 31,5 Max-Potential-Fid 153 102 Zeit bis zum ersten Mal 16.85999999999985 16.096000000000004 First-CPU-Idle 1704.8490000000002 1918.774 Interaktiv 2266.2835 2374.3615
Wir haben alle Daten, die wir jetzt brauchen. Wir müssen nur die prozentuale Differenz zwischen diesen beiden Werten berechnen und dann mit dem zuvor beschriebenen farbcodierten Format an der Konsole protokollieren.
Wissen Sie, wie Sie die prozentuale Änderung zwischen zwei Werten berechnen können? Ich auch nicht. Zum Glück kam die Lieblings -Monolith -Suchmaschine aller Rettung.
Die Formel lautet:
((Von - nach) / von) x 100
Nehmen wir also an, wir haben einen Geschwindigkeitsindex von 5,7s für den ersten Bericht (von) und dann einen Wert von 2,1 Sekunden für den zweiten (bis). Die Berechnung wäre:
5.7 - 2,1 = 3.6 3,6 / 5,7 = 0,63157895 0,63157895 * 100 = 63,157895
Die Abrunden auf zwei Dezimalstellen würde zu einem Rückgang des Geschwindigkeitsindex von 63,16%führen.
Lassen Sie uns dies in eine Helferfunktion in der Funktion vergleicheports () unterhalb des Metricfilter -Arrays einfügen.
const calcpercentagediff = (von, bis) => { const per = ((bis - von) / von) * 100; return Math.round(per * 100) / 100; };
Back in our auditObj conditional, we can begin to put together the final report comparison output.
First off, use the helper function to generate the percentage difference for each metric.
for (let auditObj in from["audits"]) { if (metricFilter.includes(auditObj)) { const percentageDiff = calcPercentageDiff( from["audits"][auditObj].numericValue, to["audits"][auditObj].numericValue ); } }
Next, we need to output values in this format to the console:
This requires adding color to the console output. In Node.js, this can be done by passing a color code as an argument to the console.log() function like so:
console.log('\x1b[36m', 'hello') // Would print 'hello' in cyan
You can get a full reference of color codes in this Stackoverflow question. We need green and red, so that's \x1b[32m and \x1b[31m respectively. For metrics where the value remains unchanged, we'll just use white. This would be \x1b[37m.
Depending on if the percentage increase is a positive or negative number, the following things need to happen:
- Log color needs to change (Green for negative, red for positive, white for unchanged)
- Log text contents change.
- '[Name] is X% slower for positive numbers
- '[Name] is X% faster' for negative numbers
- '[Name] is unchanged' for numbers with no percentage difference.
- If the number is negative, we want to remove the minus/negative symbol, as otherwise, you'd have a sentence like 'Speed Index is -92.95% faster' which doesn't make sense.
There are many ways this could be done. Here, we'll use theMath.sign() function, which returns 1 if its argument is positive, 0 if well… 0, and -1 if the number is negative. That'll do.
for (let auditObj in from["audits"]) { if (metricFilter.includes(auditObj)) { const percentageDiff = calcPercentageDiff( from["audits"][auditObj].numericValue, to["audits"][auditObj].numericValue ); let logColor = "\x1b[37m"; const log = (() => { if (Math.sign(percentageDiff) === 1) { logColor = "\x1b[31m"; return `${percentageDiff "%"} slower`; } else if (Math.sign(percentageDiff) === 0) { return "unchanged"; } anders { logColor = "\x1b[32m"; return `${percentageDiff "%"} faster`; } }) (); console.log(logColor, `${from["audits"][auditObj].title} is ${log}`); } }
So, there we have it.
You can create new Lighthouse reports, and if a previous one exists, a comparison is made.
And you can also compare any two reports from any two sites.
Complete source code
Here's the completed source code for the tool, which you can also view in a Gist via the link below.
const lighthouse = require("lighthouse"); const chromeLauncher = require("chrome-launcher"); const argv = require("yargs").argv; const url = require("url"); const fs = require("fs"); const glob = require("glob"); const path = require("path"); const launchChromeAndRunLighthouse = url => { return chromeLauncher.launch().then(chrome => { const opts = { port: chrome.port }; return lighthouse(url, opts).then(results => { return chrome.kill().then(() => { zurückkehren { js: results.lhr, json: results.report }; }); }); }); }; const getContents = pathStr => { const output = fs.readFileSync(pathStr, "utf8", (err, results) => { return results; }); return JSON.parse(output); }; const compareReports = (from, to) => { const metricFilter = [ "first-contentful-paint", "first-meaningful-paint", "speed-index", "estimated-input-latency", "total-blocking-time", "max-potential-fid", "time-to-first-byte", "first-cpu-idle", "interactive" ]; const calcPercentageDiff = (from, to) => { const per = ((to - from) / from) * 100; return Math.round(per * 100) / 100; }; for (let auditObj in from["audits"]) { if (metricFilter.includes(auditObj)) { const percentageDiff = calcPercentageDiff( from["audits"][auditObj].numericValue, to["audits"][auditObj].numericValue ); let logColor = "\x1b[37m"; const log = (() => { if (Math.sign(percentageDiff) === 1) { logColor = "\x1b[31m"; return `${percentageDiff.toString().replace("-", "") "%"} slower`; } else if (Math.sign(percentageDiff) === 0) { return "unchanged"; } anders { logColor = "\x1b[32m"; return `${percentageDiff.toString().replace("-", "") "%"} faster`; } }) (); console.log(logColor, `${from["audits"][auditObj].title} is ${log}`); } } }; if (argv.from && argv.to) { compareReports( getContents(argv.from ".json"), getContents(argv.to ".json") ); } else if (argv.url) { const urlObj = new URL(argv.url); let dirName = urlObj.host.replace("www.", ""); if (urlObj.pathname !== "/") { dirName = dirName urlObj.pathname.replace(/\//g, "_"); } if (!fs.existsSync(dirName)) { fs.mkdirSync(dirName); } launchChromeAndRunLighthouse(argv.url).then(results => { const prevReports = glob(`${dirName}/*.json`, { sync: true }); if (prevReports.length) { dates = []; for (report in prevReports) { dates.push( new Date(path.parse(prevReports[report]).name.replace(/_/g, ":")) ); } const max = dates.reduce(function(a, b) { return Math.max(a, b); }); const recentReport = new Date(max).toISOString(); const recentReportContents = getContents( dirName "/" recentReport.replace(/:/g, "_") ".json" ); compareReports(recentReportContents, results.js); } fs.writeFile( `${dirName}/${results.js["fetchTime"].replace(/:/g, "_")}.json`, results.json, err => { Wenn (err) erröste; } ); }); } anders { throw "You haven't passed a URL to Lighthouse"; }
View Gist
Nächste Schritte
With the completion of this basic Google Lighthouse tool, there's plenty of ways to develop it further. Zum Beispiel:
- Some kind of simple online dashboard that allows non-technical users to run Lighthouse audits and view metrics develop over time. Getting stakeholders behind web performance can be challenging, so something tangible they can interest with themselves could pique their interest.
- Build support for performance budgets, so if a report is generated and performance metrics are slower than they should be, then the tool outputs useful advice on how to improve them (or calls you names).
Viel Glück!
Das obige ist der detaillierte Inhalt vonErstellen Sie ein Node.js -Tool, um Google Lighthouse -Berichte aufzuzeichnen und zu vergleichen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Hey, ist keine ziemlich neue CSS -Funktion, die mit Scroll -Regionen funktioniert? Oh ja, das scrollgetriebene Animationen. Sollten wir das bedeuten, dass wir eine Animation auslösen können, während wir in einem CSS -Karussell durch die Gegenstände scrollen können?

TheBestMethodforincludingCSSDependsonProjectSizeandComplexität: 1) ForlargerProjects, UsexternalcssforbetterTainability undPerformance.2) ForsMallerProjects, InternalcsSSuStoVoidextrahttprequests.AldalwaysConsidaNanceSrahtTprequest.

Wie es aussieht, eines dieser unmöglichen Probleme zu beheben, die sich als etwas ganz anderes herausstellen, an das Sie nie gedacht haben.

@KeyFramesandcsStransitionSdifferinComplexity:@keyFramesAllowsfordetailedanimationsequenzen, whilecsStransitionShandleSmplestatechanges.USecsStransitionsForHovereffectSlikeButtonColorchanges sowie@keyframesforintricateanimationslikerotierungen.

Ich weiß, ich weiß: Es gibt eine Menge von Content -Management -Systemoptionen, und während ich mehrere getestet habe, war keiner wirklich derjenige, den Sie wirklich wissen? Seltsame Preismodelle, schwierige Anpassungen, einige werden sogar ein Ganzes &

Das Verknüpfen von CSS -Dateien mit HTML kann durch die Verwendung von Elementen in einem HTML erreicht werden. 1) Verwenden Sie Tags, um lokale CSS -Dateien zu verknüpfen. 2) Mehrere CSS -Dateien können durch Hinzufügen mehrerer Tags implementiert werden. 3) Externe CSS -Dateien verwenden absolute URL -Links wie z. 4) Stellen Sie die korrekte Verwendung von Dateipfaden und CSS -Dateiladeauftrag sicher und optimieren Sie die Leistung können mit CSS -Präprozessor zusammengeführt werden, um Dateien zu verschmelzen.

Die Auswahl von Flexbox oder Grid hängt von den Layoutanforderungen ab: 1) Flexbox ist für eindimensionale Layouts wie die Navigationsleiste geeignet. 2) Das Gitter eignet sich für zweidimensionale Layouts wie Zeitschriftenlayouts. Die beiden können im Projekt verwendet werden, um den Layout -Effekt zu verbessern.

Der beste Weg, um CSS -Dateien einzubeziehen, besteht darin, Tags zu verwenden, um externe CSS -Dateien in den HTML -Teil einzuführen. 1. Verwenden Sie Tags, um externe CSS -Dateien einzuführen, wie z. 2. Für kleine Anpassungen können Inline -CSS verwendet werden, sollten jedoch mit Vorsicht verwendet werden. 3. Große Projekte können CSS -Präprozessoren wie SASS oder weniger verwenden, um andere CSS -Dateien über @import zu importieren. 4. Für die Leistung sollten CSS -Dateien zusammengeführt und CDN verwendet und mit Tools wie CSSNano komprimiert werden.


Heiße KI -Werkzeuge

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool
Ausziehbilder kostenlos

Clothoff.io
KI-Kleiderentferner

Video Face Swap
Tauschen Sie Gesichter in jedem Video mühelos mit unserem völlig kostenlosen KI-Gesichtstausch-Tool aus!

Heißer Artikel

Heiße Werkzeuge

WebStorm-Mac-Version
Nützliche JavaScript-Entwicklungstools

SublimeText3 Linux neue Version
SublimeText3 Linux neueste Version

MinGW – Minimalistisches GNU für Windows
Dieses Projekt wird derzeit auf osdn.net/projects/mingw migriert. Sie können uns dort weiterhin folgen. MinGW: Eine native Windows-Portierung der GNU Compiler Collection (GCC), frei verteilbare Importbibliotheken und Header-Dateien zum Erstellen nativer Windows-Anwendungen, einschließlich Erweiterungen der MSVC-Laufzeit zur Unterstützung der C99-Funktionalität. Die gesamte MinGW-Software kann auf 64-Bit-Windows-Plattformen ausgeführt werden.

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

SublimeText3 Mac-Version
Codebearbeitungssoftware auf Gottesniveau (SublimeText3)
