Defer javascript und anzeigen von zwischeninhalten beim ersten laden der seite

Wie wäre es mit: Verzögern von Discourse-JavaScripts

Fügen Sie nach Möglichkeit defer-Attribute zu allen JavaScripts hinzu. Das Verzögern des Ladens und Ausführens von JavaScript ermöglicht es dem Browser, mit der HTML-Analyse, dem Rendern und dem Malen zu beginnen.

So können einige statische Zwischeninhalte ziemlich früh im (oder sogar vor dem) Discourse-Bootprozess angezeigt werden. Dies sollte für eine schnellere wahrgenommene Seitenladezeit bei der ersten Seitenladung ausreichen.

Ideen für statische Zwischeninhalte:

  • Startbildschirm mit Logo und Ladeanzeige
  • Themenansicht mit Beiträgen aus dem Backend

POC und PR

Für den neuesten Proof of Concept und PR - schauen Sie sich diesen Beitrag an.


Die Vendor-JavaScript und alle vorherigen JavaScripts werden derzeit nicht verzögert.
@siehe: https://github.com/rr-it/discourse/commit/328efd5c055f5f2a4d93b5e52268cfe92913faf7

Ideen zur Lösung dieses Problems sind sehr willkommen.


JavaScript async vs. defer vs. none

Mehr über JavaScript-Ladeoptionen - einschließlich defer: Efficiently load JavaScript with defer and async
(Hierbei geht es nicht darum, den eigentlichen Discourse-Boot zu beschleunigen.)


Fastboot/Rehydrierung

Ich habe diesen Artikel gelesen:
Die Schlussfolgerung dort scheint eine Implementierung von Fastboot/Rehydrierung zu sein.
Gibt es dafür einen Zeitplan?

4 „Gefällt mir“

Das würde dazu führen, dass LCP immer noch nach dem Booten und erneuten Rendern von EmberJS stattfindet und nicht das Hauptproblem bezüglich neuer Google-Rankings löst.

Das ist unser aktueller mittelfristiger Plan, um LCP in Discourse zu lösen.

2 „Gefällt mir“

Seit Chrome 88 ist das zum Glück nicht mehr der Fall! :rocket:
Wusste das bis jetzt auch nicht. :))

“Vor dieser Änderung wurde ein Element, das entfernt wurde, nicht mehr als gültiger LCP-Kandidat betrachtet. […] Nach dieser Änderung wird ein Element, das entfernt wurde, immer noch als gültiger LCP-Kandidat betrachtet.”

“Die Änderung, Inhalte einzubeziehen, die später aus dem DOM entfernt werden, als mögliche Largest Contentful Paints, wird die Largest Contentful Paint-Zeiten auf Websites verbessern, die Bilder [für Discourse: Text-Elemente] gleicher Größe mehrmals einfügen. Dies ist ein gängiges Muster für Karussells sowie für einige JavaScript-Frameworks, die serverseitiges Rendering durchführen.”


LCP Changelog

Es könnten in Zukunft noch weitere gute Änderungen kommen:

1 „Gefällt mir“

Hier sind einige simulierte Statistiken für eine Themen-Seite mit implementiertem POC.

Lighthouse: „Werte sind Schätzungen und können variieren.“

WebPageTest

webpagetest.org

Moto4G-Simulation


Hinweis: Wir sind der schwarze Pfeil oben.


Hinweise:

  • 0s-2s - schwarzer Bildschirm:
    WebPageTest ignoriert defer für JavaScript und lädt alle JavaScripts herunter, bevor es ein erstes Paint durchführt – dies funktioniert auf einem echten Gerät korrekt.
  • 2,5s - LCP: statische Inhalte vom Server-Rendering
  • 3,5s - Visuelle Änderung: Logo geladen
  • 6,5s - Visuelle Änderung: Inhalte vom EmberJs-Rendering
  • 7s - Visuell fertig

PageSpeed Insights

Largest Contentful Paint-Element

PageSpeed identifiziert den statischen Textknoten vom Server-Rendering korrekt als FCP LCP-Element:
div.row > div.topic-body > div.post > p

EmberJs-gerenderter Textknoten:
div.row > div.topic-body > div.regular.contents > div.cooked > p

Aber es scheint, dass PageSpeed den korrekt identifizierten statischen Textknoten nicht für sein simuliertes Ergebnis verwendet: simulierte FCP und LCP sind zu groß.

Reale Benutzerdaten

Warten wir weitere 14-28 Tage, um „echte“ Daten vom Chrome UX Report mit implementiertem POC zu erhalten.

Statistiken ohne implementierten POC für die getestete Themen-Seite:
(Die Daten stammen von dieser einzelnen Themen-URL – und nicht vom gesamten Ursprung.)

4 „Gefällt mir“

Das ist ja ein sehr interessanter Fund! Tolle Arbeit!

Was bekommst du mit dieser Erweiterung https://chrome.google.com/webstore/detail/web-vitals/ahfhijdlegdabablpippeagghigmibma?

3 „Gefällt mir“

Über die Web Vitals Chrome Extension

  • auf dem Desktop
  • Chromium Version 90.0.4430.212
  • erster Ladevorgang in einem neuen Inkognito-Fenster


Hinweis zu First Input Delay: Ich wartete, bis die Seite vollständig geladen war, und klickte dann auf den Hintergrund – also nachdem das EmberJs-Rendering abgeschlossen war.


Hinweis zu First Input Delay: Hier klickte ich auf den Hintergrund, sobald der statische Inhalt zuerst sichtbar war. Addiere meine Reaktionszeit :sloth: zu diesem FID.

Zusätzlicher Hinweis zu den Perzentilen unter den Balken in diesen Diagrammen:
Die Perzentile sind nicht sehr relevant, da sie nur die gemessenen Werte mit den Ursprungswerten vergleichen. Der Ursprung ist eine TYPO3-Webseite mit einer Unterordnerinstallation von Discourse.

2 „Gefällt mir“

Tolle Idee! @rrit

Ich stimme vollkommen zu, dass Discourse eine sehr langsame, JS-lastige Web-App ist. Wenn wir CSS/JS-Dateien verzögern können, wird dies die LCP-, FCP-, FID- und CLS-Werte erheblich verbessern.

Es wäre wirklich hilfreich, dies live zu sehen. Wir und viele andere Leute haben dieses Problem. Alle Discourse-Seiten scheitern bei den Core Web Vitals. Wenn wir den Benutzern beim ersten Mal eine schnelle STATISCHE HTML-Seite liefern und/oder die gesamte JS/CSS-Logik beim ersten anfänglichen Laden verzögern, können wir so alle Seiten beschleunigen und die CWV-Werte bestehen! Ich freue mich darauf, dies in einem Core Discourse-Update live zu sehen.

Alle Google-Rankings von Discourse-Seiten sinken, da die Seiten die Core Web Vitals nicht bestehen.

2 „Gefällt mir“

Wir sind offen dafür, dies im Kern zu experimentieren. Der „Blitz“ von unterschiedlich gestalteten Inhalten kann etwas beunruhigend sein, daher möchten wir zunächst mit einer standardmäßig deaktivierten „experimentellen“ Website-Einstellung beginnen. Auf diese Weise können Website-Administratoren wählen, ob sie diese aktivieren möchten.

Können Sie versuchen, eine Website-Einstellung in Ihrem PR @rrit hinzuzufügen? Es wäre auch gut, einige RSpec-Tests hinzuzufügen, um das Verhalten mit aktivierter/deaktivierter Einstellung zu überprüfen.

5 „Gefällt mir“

Bedeutet das nicht, dass wir einfach einen Vollbild-Spinner (der 100 % Breite und 100 % Höhe hat) auf der serverseitig gerenderten Seite platzieren und ihn durch die Ember-App ersetzen können, wenn sie endlich startet, um ein extrem niedriges LCP zu erzielen?

Wir könnten diesen Spinner zu einem SVG machen, das die Discourse-UI nachahmt, damit der Übergang reibungsloser und weniger FOUC-artig ist.

2 „Gefällt mir“

Ich denke, der Schlüssel liegt bei LCP „Kandidat

Er wird nur als Largest Contentful Paint betrachtet, wenn er wirklich der größte (oder zumindest gleich groß) wie das ist, was schließlich gerendert wird?

Die Crawler-Ansicht funktioniert also recht gut, weil der Inhalt (d. h. der Text) weitgehend derselbe ist?

(Ich rate hier hauptsächlich, basierend auf den obigen Screenshots – ich habe keinen Vollbild-Spinner ausprobiert)

1 „Gefällt mir“

Feature-Flag ist implementiert.

Ich bin überhaupt kein Ruby-Entwickler – hier brauche ich definitiv Hilfe.

Vielleicht meinen POC in einen neuen Branch im discourse/discourse-Repo pushen, bevor ich einen PR auf main mache?

Das ist mein PR zu diesem Feature:

@david Können Sie mir mit etwas Hilfe bei der Entwicklung von Rspec-Tests für diese Änderungen zur Seite stehen:

app/helpers/application_helper.rb: spec/helpers/application_helper_spec.rb

Ich sehe hier keine praktikablen Unit-Tests. Es scheint nur durch Integrationstests testbar zu sein.
app/models/theme.rb
app/models/theme_field.rb

Ich musste das Defer-Tag für den QUnit Test Runner deaktivieren: app/views/qunit/index.html.erb
Zuvor liefen die QUnit-Tests immer noch mit dem Feature-Flag "javascript defer" = false. Und jetzt laufen die Tests auch mit "javascript defer" = true.

2 „Gefällt mir“

Dies wird wahrscheinlich bereits durch Chrome Speed - Largest Contentful Paint Bug Fixes in M88 blockiert:

Vollbild-Bilder, die visuell mit Hintergrundbildern gleichwertig sind, werden nicht mehr als Largest Contentful Paint betrachtet.


Guter Punkt: siehe Largest Contentful Paint (LCP)  |  Articles  |  web.dev

Bei Textelementen wird nur die Größe ihrer Textknoten berücksichtigt (das kleinste Rechteck, das alle Textknoten umschließt).

Bei allen Elementen werden Ränder, Abstände oder Rahmen, die über CSS angewendet werden, nicht berücksichtigt.

  • Deshalb muss der statische Textknoten exakt die gleiche Größe wie der EmberJs-Textknoten haben.
  • Oder sogar etwas größer, indem die line-height erhöht wird.
    Wenn z. B. die Breite der Textknoten nicht übereinstimmt, gibt es viele geometrische Fälle, die durch unterschiedliche Zeilenumbrüche entstehen, bei denen der statische Textknoten kleiner wird als der EmberJs-Knoten.

Siehe: LCP-Beispiele


Ich habe tatsächlich das noscript-Rendering der Beiträge innerhalb einer Beitragsseite verwendet. Die CSS-Klassen stimmen leicht mit den tatsächlichen überein – das Aussehen ist also gleich.

Siehe: Änderungen an app/views/layouts/application.html.erb

Bearbeiten: Mein Fehler, das ist tatsächlich die Crawler-Ansicht: app/views/topics/show.html.erb

2 „Gefällt mir“

Im POC sind zwei Funktionen kombiniert – sollen wir sie in zwei experimentelle Feature-Flags aufteilen?

  • JavaScript mit defer-Tag (Feature-Flag im Einstellungs-Dashboard)
    (verstecktes Feature-Flag, da ein Container-Neubau oder ein Leeren des Theme-Caches erforderlich ist)Fix: Hot-Switching mit Cache
  • Anzeigen statischer Inhalte in der Topic-Ansicht (Feature-Flag im Einstellungs-Dashboard)

Hier sind sie: Feature-Flags


Natürlich wird die volle Auswirkung auf LCP nur durch die Verwendung beider erreicht: FCP: statischer Inhalt

Es kann Discourse-Instanzen geben, bei denen Plugins oder Theme-Komponenten beim verzögerten Laden von JS fehlschlagen. Durch die Aufteilung dieser Features können sie einen kleinen Gewinn bei statischen Inhalten erzielen, ohne JS zu verzögern: FCP: statischer Inhalt ohne JS-Verzögerung

2 „Gefällt mir“

Erster Eindruck von der Google Search Console mit dem seit dem 30.01.2022 angewendeten POC:

Desktop

Es dauerte eine Weile, bis die Ergebnisse für Desktop angezeigt wurden:


Hinweis: Die alte grüne Grundlinie repräsentiert Nicht-Discourse-Webseiten auf derselben Domain.

Mobil


Hinweis: Die alte grüne Grundlinie repräsentiert Nicht-Discourse-Webseiten auf derselben Domain.

Warten wir weitere 7-14 Tage, um hoffentlich weitere Verbesserungen für mobile Seiten zu sehen, da die Werte über die letzten 28 Tage gemittelt werden – derzeit zählen nur 12 Tage mit dem angewendeten POC.

5 „Gefällt mir“

LCP-Zusammenfassung zum Proof of Concept

Der POC wird seit dem 30.01.2022 angewendet und es dauerte über 4 Wochen, bis sich alle Seiten im Bericht „Core Web Vitals“ der Google Search Console (basierend auf CrUX-Daten) auswirkten.

Alle Themenseiten befinden sich in der LCP-Grünzone (gemessen von CrUX):

  • Desktop: LCP 1,7 Sek.
  • Mobil: LCP 2,0 Sek.

LCP-Daten: Google Search Console/CrUX

Eindruck aus der Google Search Console mit dem seit dem 30.01.2022 angewendeten POC:

Desktop


Hinweis: Die alte grüne Basislinie repräsentiert Nicht-Discourse-Webseiten auf derselben Domain.

Gute URLs

Mobil


Hinweis: Die alte grüne Basislinie repräsentiert Nicht-Discourse-Webseiten auf derselben Domain.

Gute URLs

LCP-Problem: länger als 2,5s (mobil)


Hinweis: Nur Themenseiten zeigen statische Inhalte vor EmberJS-Inhalten


Genehmigung von PR mit Feature-Flags erforderlich

@sam Können Sie diesen PR bitte an jemanden delegieren, der ihn zur Genehmigung prüft.

3 „Gefällt mir“

Wir werden ihn auf jeden Fall sorgfältig prüfen, es ist eine sehr große Änderung, es könnte etwas dauern, bis wir dazu kommen.

5 „Gefällt mir“

@rrit danke für das Teilen der Daten von deiner Seite! Wir haben das intern besprochen und befürchten, dass wir diese Funktionalität im Moment nicht in den Discourse-Kern aufnehmen werden.

Obwohl die von dir geteilten Web-Vital-Metriken sehr beeindruckend sind, sorgt der “Crawler-View”-Inhalt für ein schlechtes Benutzererlebnis. Die von dir vorgenommenen Stiländerungen helfen zwar, müssen aber für jede Discourse-Seite mit benutzerdefinierten Stilen angepasst werden.

Unser langfristiges Ziel ist die Implementierung von echtem serverseitigem Rendering mit etwas wie Ember FastBoot. Theoretisch würde dies die gleichen statistischen Verbesserungen bieten, die du gemessen hast, und gleichzeitig ein nahtloses Benutzererlebnis ermöglichen. Wir möchten unsere Bemühungen auf dieses Ziel konzentrieren.


Nichtsdestotrotz ist Discourse sehr erweiterbar, daher denke ich, dass es durchaus möglich ist, deine Idee in einem Discourse-Plugin zu implementieren und es dann hier unter Plugin zu teilen.

Die größte Änderung, die du im Kern-PR vorgenommen hast, ist das Hinzufügen des defer-Attributs zu Skript-Tags. Das Überschreiben all dieser Stellen von einem Plugin aus wäre sehr schwierig. Ich denke jedoch, dass dasselbe Ergebnis mit einem Middleware-basierten Ansatz erzielt werden könnte. Ich habe diesen Blogbeitrag gefunden, der ein ähnliches Problem beschreibt:

Mit dieser Technik könntest du eine Middleware schreiben, die auf text/html-Antworten prüft, diese parst und dann defer-Attribute hinzufügt, wo nötig.

Das Hinzufügen von Middleware von einem Plugin aus kann ungefähr so erfolgen:

# name: my-plugin
# about: Meine Plugin-Beschreibung
# version: 1.0
# url: https://example.org

require_relative "lib/script_defer_middleware"

on(:after_initializers) do
  Rails.configuration.middleware.use(ScriptDeferMiddleware)
end

Wenn du bei einem Plugin-basierten Ansatz auf Hindernisse stößt, kannst du hier gerne posten und wir werden versuchen, dir in die richtige Richtung zu weisen.

10 „Gefällt mir“

Wenn ich Zeit dafür finde, werde ich wahrscheinlich ein Plugin implementieren.

Aber im Moment versuche ich, mit einem Patching-Ansatz in web_only.yml zurechtzukommen:

# nicht getesteter Pseudocode!
hooks:
  after_code:
    - exec:
        cd: $home
        cmd:
          - curl https://patch-diff.githubusercontent.com/raw/discourse/discourse/pull/15858.diff | git apply
4 „Gefällt mir“

Ember FastBoot sieht wie ein perfekter langfristiger Ansatz aus. In der Zwischenzeit bleibt das LCP-Thema aktuell:

2 „Gefällt mir“

Vielen Dank für die Arbeit daran, @rrit :+1:

Ich habe gute Nachrichten: Wir haben eine neue Funktion in Discourse implementiert, die hier ziemlich helfen sollte.

5 „Gefällt mir“