初期ページ読み込み時にJavaScriptを遅延させ、一時的なコンテンツを表示する

JavaScript の遅延読み込みについて

可能な限り、すべての JavaScript に defer 属性を追加します。JavaScript の読み込みと実行を遅延させることで、ブラウザは HTML の解析、レンダリング、ペイントを開始できます。

これにより、Discourse の起動プロセス中またはその前に、静的な一時コンテンツが表示される可能性があります。これは、初回読み込み時のユーザー体感速度を向上させるはずです。

静的な一時コンテンツのアイデア:

  • ロゴとローディングスピナー付きのスプラッシュスクリーン
  • バックエンドからの投稿を含むトピックビュー

POC と PR

最新の概念実証と PR については、こちらの投稿を参照してください


現在、ベンダー JavaScript およびそれ以前のすべての JavaScript は遅延読み込みされていません。
@参照: https://github.com/rr-it/discourse/commit/328efd5c055f5f2a4d93b5e52268cfe92913faf7

この問題の解決策に関するアイデアを歓迎します。


JavaScript の async、defer、none

defer を含む JavaScript の読み込みオプションの詳細については、Efficiently load JavaScript with defer and async を参照してください。
(これは、実際の Discourse ブートの高速化に関するものではありません。)


Fastboot/再水和

この記事を読みました:
結論として、Fastboot/再水和の実装のようです。
これにはいつ頃の予定がありますか?

「いいね!」 4

それはEmberJSが起動して再レンダリングされた後もLCPを引き起こすことになり、Googleの新しいランキングに関する主な問題に対処することにはなりません。

それがDiscourseにおけるLCPに対処するための現在の中期計画です。

「いいね!」 2

Chrome 88以降では、幸いなことにこれはもはや真実ではありません!:rocket:
私もついさっきまで知りませんでした。:))

「この変更の前は、要素が削除されると、LCPの候補として考慮されなくなっていました。[…] この変更の後、削除された要素はLCPの候補として引き続き考慮されます。」

「後でDOMから削除されるコンテンツを最大のコンテンツ描画要素として含めるように変更することで、同じサイズの画像([*Discourseの場合:テキスト要素])が複数回挿入されるサイトで、最大のコンテンツ描画要素の時間が改善されます。これは、カルーセルでよく見られるパターンですが、サーバーサイドレンダリングを行う一部のJavaScriptフレームワークでも同様です。」


LCP変更履歴

将来的にはさらに良い変更があるかもしれません:

「いいね!」 1

POCが実装されたトピックページのシミュレーション統計を以下に示します。

Lighthouse: 「値は推定値であり、変動する可能性があります。」

WebPageTest

webpagetest.org

Moto4Gシミュレーション


注:私たちは一番上の黒い矢印です。


注:

  • 0秒~2秒 - 白画面:
    WebPageTestはJavaScriptのdeferを無視し、最初のペイントを行う前にすべてのJavaScriptをダウンロードします。これは実際のデバイスでは正しく機能します。
  • 2.5秒 - LCP:サーバーレンダリングからの静的コンテンツ
  • 3.5秒 - ビジュアル変更:ロゴが読み込まれました
  • 6.5秒 - ビジュアル変更:EmberJsレンダリングからのコンテンツ
  • 7秒 - ビジュアル完了

PageSpeed Insights

Largest Contentful Paint要素

PageSpeedは、サーバーレンダリングからの静的テキストノードをFCP LCP要素として正しく識別します:
div.row > div.topic-body > div.post > p

EmberJsによってレンダリングされたテキストノード:
div.row > div.topic-body > div.regular.contents > div.cooked > p

しかし、PageSpeedはシミュレーション結果に正しく識別された静的テキストノードを使用していないようです。シミュレーションされたFCPとLCPが大きすぎます。

実世界のユーザーデータ

POCが実装された「実際の」データを取得するために、さらに14~28日間待ちましょう。Chrome UX Reportからのデータです。

テストされたトピックページでPOCが実装されていない場合の統計:
(データは単一のトピックURLのものであり、オリジン全体のものではありません。)

「いいね!」 4

おお、それは非常に興味深い発見ですね!素晴らしい仕事です!

この拡張機能 https://chrome.google.com/webstore/detail/web-vitals/ahfhijdlegdabablpippeagghigmibma? では、どのような結果が得られますか?

「いいね!」 3

Web Vitals Chrome 拡張機能経由

  • デスクトップで
  • Chromium バージョン 90.0.4430.212
  • 新しいシークレットウィンドウでの初回読み込み


初回入力遅延に関する注記: ページが完全に読み込まれるまで待ってから、背景をクリックしました。EmberJs のレンダリングが完了した後です。


初回入力遅延に関する注記: ここでは、静的コンテンツが最初に表示されたときにすぐに背景をクリックしました。この FID に私の反応時間を追加してください :sloth:

これらのグラフのバーの下にある パーセンタイル に関する追加注記:
パーセンタイルは、測定された値と元の値を比較するだけなので、それほど重要ではありません。元は、サブフォルダに Discourse がインストールされている TYPO3 のウェブページです。

「いいね!」 2

素晴らしいアイデアです!@rrit

Discourseが非常に遅く、JavaScriptが多いWebアプリケーションであることに完全に同意します。CSS/JSファイルを遅延させることができれば、LCP、FCP、FID、CLSの速度が大幅に向上します。

これが実現するのを見るのは本当に助かります。私たちや他の多くの人々がこの問題に直面しています。すべてのDiscourseサイトがCore Web Vitalsで失敗しています。最初にユーザーに高速な静的HTMLページを提供したり、最初の初期ロードでJS/CSSロジックをすべて遅延させたりすれば、すべてのページの速度が上がり、CWVスコアを通過できます!コアDiscourseアップデートでこれがライブになるのを見るのが楽しみです。

すべてのDiscourseサイトは、サイトがCore Web Vitalsを通過しないためにGoogleのランキングが低下しています。

「いいね!」 2

コアでの実験も検討しています。「フラッシュ」で異なるスタイルのコンテンツが表示されるのは少し落ち着かないので、まずはデフォルトで無効になっている「実験的」サイト設定の背後に配置したいと思います。そうすれば、サイト管理者が希望する場合に有効にすることができます。

rritさん、PRにサイト設定を追加していただけますか?設定が有効/無効の場合の動作を確認するために、RSpecテストを追加することも良いでしょう。

「いいね!」 5

これは、サーバーによってレンダリングされたページにフルスクリーンスピナー(幅100%、高さ100%)を配置し、Emberアプリが最終的に起動したときにそれを置き換えることで、非常に低いLCPを取得できることを意味しませんか?

このスピナーをDiscourse UIを模倣したSVGにすることで、トランジションをよりスムーズにし、FOUC(Flash of Unstyled Content)のような現象を軽減できる可能性があります。

「いいね!」 2

LCPの「候補」という部分が重要だと思います。

実際にレンダリングされるものと同じくらい大きい(少なくとも同じサイズ)場合にのみ、最大のコンテンツペイントと見なされるのでしょうか?

したがって、クローラービューを使用すると、コンテンツ(つまりテキスト)がほぼ同じであるため、うまく機能するということでしょうか?

(上記のスクリーンショットに基づいた推測がほとんどです。フルスクリーンスピナーは試していません)

「いいね!」 1

フィーチャーフラグは実装されました。

私はまったくRuby開発者ではありません。この件については、間違いなく助けが必要です。

POCをmainのPRの前に、discourse/discourseリポジトリの新しいブランチにプッシュしますか?

このフィーチャーに関する私のPRはこちらです:

@david これらの変更に対するRspecテストの開発について、少し頭を貸していただけますか?

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

ここでは実現可能な単体テストが見当たりません。統合テストでのみテスト可能と思われます。
app/models/theme.rb
app/models/theme_field.rb

QUnitテストランナーのためにdeferタグを無効にする必要がありました:app/views/qunit/index.html.erb
以前はフィーチャーフラグ "javascript defer" = false でもQUnitテストは実行されていました。そして今、テストは "javascript defer" = true でも実行されます。

「いいね!」 2

これはおそらく、Chrome Speed - Largest Contentful Paint Bug Fixes in M88 で既にブロックされているでしょう。

ビューポート全体を占める画像は、背景画像と視覚的に同等ですが、最大のコンテンツ描画(LCP)とはみなされなくなりました。


良い点です。Largest Contentful Paint (LCP)  |  Articles  |  web.dev を参照してください。

テキスト要素の場合、テキストノードのサイズのみが考慮されます(すべてのテキストノードを囲む最小の長方形)。

すべての要素について、CSSで適用されたマージン、パディング、またはボーダーは考慮されません。

  • そのため、静的なテキストノードはEmberJsのテキストノードとまったく同じサイズでレンダリングされる必要があります。
  • line-height を増やすことで、さらにわずかに大きくすることもできます。
    たとえば、テキストノードの幅が一致しない場合、さまざまな改行によって導入される多くの幾何学的なケースがあり、静的なテキストノードがEmberJsのものより小さくなる可能性があります。

参照:LCPの例


実際には、トピックページの投稿を noscript でレンダリングしました。CSSクラスは実際のクラスとわずかに一致しているため、見た目は同じです。

参照:app/views/layouts/application.html.erb の変更点

編集:私の間違いです。これは実際にはクローラービューです:app/views/topics/show.html.erb

「いいね!」 2

POCでは2つの機能が組み合わされていますが、これらを2つの実験的フィーチャーフラグに分割しますか?

  • deferタグ付きJavaScript(設定ダッシュボードのフィーチャーフラグ)
    (コンテナの再構築またはテーマキャッシュのフラッシュが必要なため、非表示のフィーチャーフラグ)修正:キャッシュによるホットスイッチ
  • トピックビューでの静的コンテンツの表示(設定ダッシュボードのフィーチャーフラグ)

こちらです:フィーチャーフラグ


もちろん、LCPへの完全な影響は両方を使用することで達成されます:「FCP:静的コンテンツ」

プラグインまたはテーマコンポーネントがJavaScriptの遅延で失敗するDiscourseインスタンスがあるかもしれません。これらの機能を分割することで、JavaScriptを遅延させることなく静的コンテンツでわずかな改善を得ることができます:「FCP:JS遅延なしの静的コンテンツ」

「いいね!」 2

Google Search Console からの最初の印象(2022-01-30 より POC を適用後):

デスクトップ

デスクトップでは、結果が表示されるまでに時間がかかりました。


注:古い緑色のベースラインは、同じドメイン上の Discourse 以外のウェブページを表します。

モバイル


注:古い緑色のベースラインは、同じドメイン上の Discourse 以外のウェブページを表します。

モバイルページでさらなる改善が見られることを期待して、さらに 7 ~ 14 日間待ちましょう。値は過去 28 日間の平均であるため、現在 POC が適用されているのは 12 日間のみです。

「いいね!」 5

PoC に関する LCP の概要

POC は 2022 年 1 月 30 日から適用されており、Google Search Console の「Core Web Vitals」レポート(CrUX データに基づく)の全ページに影響を与えるまでに 4 週間以上かかりました。

すべてのトピック ページは LCP のグリーン ゾーン(CrUX による測定)にあります。

  • デスクトップ: LCP 1.7 秒
  • モバイル: LCP 2.0 秒

LCP データ: Google Search Console/CrUX

2022 年 1 月 30 日から POC を適用した Google Search Console からのインプレッション:

デスクトップ


注: 古い緑のベースラインは、同じドメイン上の Discourse 以外のウェブページを表します。

良好な URL

モバイル


注: 古い緑のベースラインは、同じドメイン上の Discourse 以外のウェブページを表します。

良好な URL

LCP 問題: 2.5 秒以上(モバイル)


注: トピック ページのみが EmberJS コンテンツの前に静的コンテンツを表示します。


機能フラグ付き PR の承認が必要

@sam 承認のために、この PR を誰かに委任していただけますでしょうか。

「いいね!」 3

確かに慎重にレビューいたします。非常に大きな変更ですので、対応に少々お時間をいただく場合がございます。

「いいね!」 5

@rrit サイトのデータ共有ありがとうございます!社内で検討した結果、現時点ではこの機能性をDiscourseコアに追加しないことになりました。

共有いただいたWeb Vitalメトリクスは非常に印象的ですが、「クローラービュー」コンテンツのフラッシュは、ユーザーエクスペリエンスとしてあまり良くありません。行ったスタイリングの変更は確かに役立ちますが、カスタムスタイリングを持つすべてのDiscourseサイトで微調整が必要になります。

長期的な目標は、Ember FastBootのようなものを使用した真のサーバーサイドレンダリングを実装することです。理論的には、測定された統計的改善と同じものを提供し、シームレスなユーザーエクスペリエンスも提供します。私たちはその目標に努力を集中させたいと考えています。


とはいえ、Discourseは非常に拡張性が高いため、Discourseプラグインでアイデアを実装し、ここで#pluginで共有することは完全に可能だと思います。

コアPRで最も大きな変更は、スクリプトタグにdefer属性を追加したことです。プラグインからそれらのすべての場所をオーバーライドするのは非常に困難です。しかし、ミドルウェアベースのアプローチで同じ結果が得られると思います。このブログ記事は同様の問題を説明しています。

このテクニックを使用して、text/htmlレスポンスをチェックし、それらを解析して、必要に応じてdefer属性を追加するミドルウェアを作成できます。

プラグインからミドルウェアを追加するには、次のようなことができます。

# name: my-plugin
# about: My plugin description
# version: 1.0
# url: https://example.org

require_relative "lib/script_defer_middleware"

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

プラグインベースのアプローチで問題が発生した場合は、ここに投稿してください。喜んで方向性を示します。

「いいね!」 10

もしこれに時間を割くことができれば、おそらくプラグインを実装するでしょう。

しかし、今のところ web_only.yml でパッチアプローチで対応しようとしています。

# テストされていない擬似コードです!
hooks:
  after_code:
    - exec:
        cd: $home
        cmd:
          - curl https://patch-diff.githubusercontent.com/raw/discourse/discourse/pull/15858.diff | git apply
「いいね!」 4

Ember FastBootは長期的なアプローチとして完璧に見えます。一方、LCPのトピックは引き続き注目されています。

「いいね!」 2

@rrit さん、ありがとうございます :+1:

良いニュースがあります。Discourse に新しい機能が実装され、この問題がかなり改善されるはずです。

「いいね!」 5