パフォーマンス

ベストプラクティス

リアルタイムコンポーネント

リアルタイム機能のコードを書くときには、いくつかのことを念頭に置かなければなりません:

  1. リクエストでサーバーに負荷をかけないようにしてください。
  2. リアルタイムに感じられるはずです。

したがって、リクエストの送信とリアルタイムの感覚のバランスをとらなければなりません。 リアルタイムのソリューションを作成するときは、以下のルールを使用してください。

  1. サーバーは、ヘッダーにPoll-Interval 。これをポーリング間隔として使用します。こうすることで、システム管理者がポーリングレートを簡単に変更できるようになります。Poll-Interval: -1 。これはポーリングを無効にすることを意味し、これを実装する必要があります。
  2. HTTPステータスが2XXと異なる応答は、ポーリングも無効にする必要があります。
  3. ポーリングには共通のライブラリを使用します。
  4. アクティブなタブにのみ投票します。Visibilityを使用してください。
  5. 定期的なポーリング間隔を使用し、バックオフポーリングやジッターは使用しないでください。
  6. バックエンドのコードは、おそらくetagsを使用しているはずです。304 Not Modified。ブラウザがそれを変換してくれます。

画像の遅延読み込み

最初のレンダリングにかかる時間を改善するために、画像の遅延読み込みを使用しています。 これは、data-src 属性に data-src実際の画像ソースを設定することで機能しますdata-src 。 HTMLがレンダリングされ、JavaScriptが読み込まれた後、 data-src画像が現在のビューポート内にある場合、src に自動的に移動します。

  • src 属性の名前をdata-src に変更し、lazyクラスを追加することで、HTML 内の画像を遅延ロード用に準備します。
  • Railsimage_tag ヘルパーを使用している場合、lazy: false を指定しない限り、デフォルトですべての画像が遅延ロードされます。

遅延画像を含むコンテンツを非同期に追加する場合は、gl.lazyLoader.searchLazyImages() 関数を呼び出す必要があります。 関数は、遅延画像を検索し、必要であれば読み込みます。しかし、一般的には、遅延読み込み関数のMutationObserver を使って自動的に処理されるべきです。

アニメーション

opacitytransform のプ ロ パテ ィ ーのみをア ニ メ ー ト し ます。 その他のプ ロ パテ ィ (topleftmarginpaddingなど) はすべて、 レ イ ア ウ ト の再計算を引 き 起 こ し ますので、 よ り 高 コ ス ト にな り ます。 こ れに関す る 詳 し い説明は、 「ハイパフ ォーマ ン ス ・ アニ メ ーシ ョ ン」 の 「レ イ ア ウ ト に影響す る ス タ イ ル」 を参照 し て く だ さ い。

レイアウトを変更する必要が_ある_場合(たとえば、サイドバーがメインコンテンツを押しのけるなど)、FLIPを使用して高価なプロパティを一度変更し、実際のアニメーションはtransformsで処理します。

資産フットプリントの削減

ユニバーサルコード

main.jscommons/index.js に含まれるコードは、_すべての_ページで読み込まれ、実行されます。 本当に_どこでも_必要でない限り、これらのファイルに何も追加しないでください。 これらのバンドルには、vueaxiosjQueryのようなユビキタスライブラリや、メインナビゲーションとサイドバーのコードが含まれています。 可能な限り、これらのバンドルからモジュールを削除して、コードのフットプリントを減らすことを目指しましょう。

ページ固有のJavaScript

Webpackは、app/assets/javascripts/pages/*内のファイル構造に基づいてエントリポイントのバンドルを自動生成するように設定されています。pages ディレクトリ内のディレクトリは、Railsのコントローラとアクションに対応しています。 これらの自動生成されたバンドルは、対応するページに自動的にインクルードされます。

たとえば、https://gitlab.com/gitlab-org/gitlab/-/issuesにアクセスした場合、index アクションでapp/controllers/projects/issues_controller.rbコントローラにアクセスすることになります。pages/projects/issues/index/index.jsに対応するファイルが存在する場合、そのファイルは webpack バンドルにコンパイルされ、ページにインクルードされます。

注意:これまでは、手動で生成した webpack バンドルとともに、haml ファイル内でcontent_for :page_specific_javascripts を使用することを推奨していました。 しかし、この新しいシステムでは、webpack.config.js ファイルに手動でエントリポイントを追加する必要はありません。
ヒント:あるページに対応するコントローラとアクションがわからない場合は、GitLab 内のどのページでもブラウザの開発者コンソールでdocument.body.dataset.page を調べればわかります。

重要な考慮事項

  • エントリーポイントはライトに保つ:ページ固有の JavaScript エントリーポイントは、可能な限りライトであるべきです。 これらのファイルはユニットテストの対象外であり、主にエントリーポイントスクリプトの外のモジュールに存在するクラスやメソッドのインスタンス化と依存性注入のために使用されるべきです。 単にインポートし、DOM を読み、インスタンス化するだけで、他には何もしません。

  • エントリーポイントは非同期である可能性があります:エントリーポイントのスクリプトが実行されるときに、DOM が完全に読み込まれ、利用可能になっていることを_仮定しないで_ください。 DOM が読み込まれた後に何らかのコードを実行する必要がある場合は、DOMContentLoadedイベントにイベントハンドラをアタッチする必要があります:

     import initMyWidget from './my_widget';
    
     document.addEventListener('DOMContentLoaded', () => {
       initMyWidget();
     });
    
  • モジュールの配置をサポートします:
    • クラスやモジュールが_特定のルートに固有の_ものである場合、使用されるエントリーポイントの近くに配置するようにしてください。 例えば、my_widget.jspages/widget/show/index.js内でのみインポートされる場合、pages/widget/show/my_widget.js にモジュールを配置し、相対パスでインポートする必要があります (例:import initMyWidget from './my_widget';)。
    • クラスまたはモジュールが_複数のルートで使用さ_れる場合、それをインポートするエントリポイントに最も近い共通の親ディレクトリの共有ディレクトリ内に配置します。 たとえば、my_widget.jspages/widget/show/index.jspages/widget/run/index.jsの両方でインポートされる場合、pages/widget/shared/my_widget.js にモジュールを配置し、可能であれば相対パスでインポートします (例:../shared/my_widget)。
  • Enterprise Edition の注意事項:GitLab Enterprise Edition では、ページ固有のエントリーポイントは Community Edition と同じ名前のものを上書きします。ee/app/assets/javascripts/pages/foo/bar/index.js が存在する場合は、app/assets/javascripts/pages/foo/bar/index.jsよりも優先されます。コードの重複を最小限に抑えたい場合は、一方のエントリーポイントをもう一方のエントリーポイントからインポートすることができます。 これは、機能を柔軟に上書きできるようにするために自動的に行われるわけではありません。

コード分割

ページロード時に即座に実行する必要のないコード (たとえば、モーダル、ドロップダウン、その他の遅延ロード可能なビヘイビア) については、動的なインポート文を使用してモジュールを非同期のチャンクに分割できます。 これらのインポートは、スクリプトがロードされると解決される Promise を返します:

import(/* webpackChunkName: 'emoji' */ '~/emoji')
  .then(/* do something */)
  .catch(/* report error */)

GitLabのバージョンにまたがってブラウザにキャッシュされるチャンクのファイル名を決定論的に提供することができるので、これらの動的インポートを生成するときはwebpackChunkName

詳細はwebpackのコード分割のドキュメントを参照してください。

ページサイズの最小化

ページサイズが小さいということは、ページの読み込みが速く(特にモバイルや接続の悪い環境では重要)、ブラウザによるページの解析が速く、データプランに上限があるユーザーにとってはデータ使用量が少なくて済むということです。

一般的なアドバイス

  • 新しいフォントを追加しないでください。
  • 例えば、WOFFよりもWOFF2、TTFよりもWOFF2の方が優れています。
  • 可能な限りアセットを圧縮し、最小化します(CSS/JSについては、Sprocketsとwebpackがこれを行います)。
  • 余分なライブラリを追加することなく、合理的に実現できる機能があれば、それを避けてください。
  • 特定のページでのみ必要なライブラリを読み込むには、上記のようにページ固有のJavaScriptを使用します。
  • 可能な限りコード分割ダイナミックインポートを使用し、初期に不要なコードを遅延ロードします。
  • 高性能アニメーション

その他のリソース