マージリクエスト差分フロントエンドの概要

このドキュメントでは、フロントエンドの diffs Vue アプリケーションがどのように動作するのか、またさまざまな異なる部分が存在するのかについての概要を説明します。貢献者の助けになるはずです:

  • diffs Vueアプリがどのように設定されているかを理解します。
  • 改善が必要な箇所を特定します。

この文書は生きている文書です。diffsアプリケーションに重大な変更があった場合は、いつでも更新してください。

Diffs Vueアプリ

コンポーネント

diffをレンダリングするVueアプリでは様々なVueコンポーネントを使用しており、その一部はGitLabアプリの他のエリアと共有されています。下の Chart は、どのコンポーネントがレンダリングされるかを示しています。

note
コンポーネント図の Mermaid グラフを生成するために、イシュー #388843が開かれています。このダイアグラムの画像バージョンはイシューにあります。

いくつかのコンポーネントは他のコンポーネントよりもレンダリングされますが、主なコンポーネントはdiff_row.vueです。このコンポーネントは、diffファイル内のすべてのdiff行をレンダリングします。パフォーマンス上の理由から、このコンポーネントは機能的なコンポーネントです。しかし、Vue 3 にアップグレードすると、このコンポーネントは不要になります。

メインの diff アプリコンポーネントは、diffs アプリへの主要なエントリポイントです。このコンポーネントの最も重要な部分の1つは、diff行にディスカッションを割り当てるアクションをディスパッチすることです。このアクションは、メタデータのリクエストが完了した後と、 バッチの diff リクエストが完了した後にディスパッチされます。また、diff files 配列と notes 配列の両方の変更を監視するウォッチャーも設定されています。ここで変更が発生するたびに、 set discussion アクションがディスパッチされます。

DiffRow コンポーネントは、diff 行データを 1 つの形式で保存できるように設定されています。以前は、インラインとサイドバイサイドの 2 つの異なる形式を要求する必要がありました。DiffRow コンポーネントでは、この標準フォーマットを使用して差分行データをレンダリングします。この標準フォーマットにより、ユーザーはデータを再取得することなく、インラインとサイドバイサイドを切り替えることができます。

note
このコンポーネントでは、使用およびレンダリングされるデータの多くが、さまざまな条件に基づいてメモ化およびキャッシュされます。各コンポーネントのレンダリング間でデータがキャッシュされることがあります。

Vuexストア

diffsアプリのVuexストアは3つのモジュールで構成されています:

  • 備考
  • 差分
  • 一括コメント

notes モジュールは diff ディスカッションを含むディスカッションを担当します。このモジュールでは、ディスカッションを取得し、新しいディスカッションのポーリングを設定します。このモジュールはイシューアプリとも共有されるので、ここでの変更はイシューとマージリクエストの両方でテストする必要があります。

diffs モジュールは diff に関連するすべてを担当します。これには diff の取得、diff ディスカッションの行への割り当て、diff ディスカッションの作成などが含まれますが、これらに限定されません。

最後に、バッチコメントモジュールは複雑ではなく、草稿コメント機能のみを担当します。しかし、このモジュールは草稿コメントが公開されるたびに、notesモジュールとdiffモジュールのアクションをディスパッチします。

API リクエスト

メタデータ

diffs メタデータエンドポイントは、すべての diff ファイルを取得することなく、diffs アプリが必要とする基本データを迅速に取得するために存在します。これには以下が含まれますが、これらに限定されるものではありません:

  • diff ファイルのメタデータを含む diff ファイル名
  • 行番号の追加と削除
  • ブランチ名
  • 差分バージョン

メタデータレスポンスの中で最も重要な部分は、diff ファイル名です。このデータにより、diffs アプリはすべてのバッチ diffs リクエストが完了するのを待たずに、diffs アプリ内でファイルブラウザをレンダリングすることができます。

メタデータ レスポンスを受信すると、diff ファイル データは、ツリー表示またはリスト表示のいずれかでファイル ブラウザをレンダリングするためにフロントエンドが必要とする正しい構造に処理されます。

このファイル オブジェクトの構造は次のとおりです:

{
  "key": "",
  "path": "",
  "name": "",
  "type": "",
  "tree": [],
  "changed": true,
  "diffLoaded": false,
  "filePaths": {
    "old": file.old_path,
    "new": file.new_path
  },
  "tempFile": false,
  "deleted": false,
  "fileHash": "",
  "addedLines": 1,
  "removedLines": 1,
  "parentPath": "/",
  "submodule": false
}

一括差分

diffs エンドポイントのレスポンスサイズを小さくするために、このレスポンスをさまざまなリクエストに分割しています:

  • 各リクエストのレスポンスサイズを小さくします。
  • diffs アプリが、最初のリクエストが終了するとすぐに diff のレンダリングを開始できるようにします。

最初のリクエストを早くするために、リクエストは少量の diff を要求するように送信されます。その後、要求される diff の数は増加し、1 リクエストあたりの最大 diff 数は 30 になります。

リクエストが終了すると、diffsアプリは受け取ったデータをdiffsアプリがdiffs行をレンダリングしやすい形式にフォーマットします。

graph TD A[fetchDiffFilesBatch] --> B[commit SET_DIFF_DATA_BATCH] --> C[prepareDiffData] --> D[prepareRawDiffFile] --> E[ensureBasicDiffFileLines] --> F[prepareDiffFileLines] --> G[finalizeDiffFile] --> H[deduplicateFilesList]

これが完了すると、diffs アプリは diff 行のレンダリングを開始できます。ただし、レンダリングが行われる前に、diffsアプリはもう1つフォーマットを行います。差分行のデータを取得し、インラインモードとサイドバイサイドモードを簡単に切り替えるためのフォーマットにデータをマッピングします。このフォーマットは、diff_content.vue コンポーネント内部の計算プロパティで行われます。

レンダーキュー

note
これはもう必要_ないかも_しれません。レンダーキューの将来を決めるには、いくつかの調査作業が必要です。私たちが作成した仮想スクロールバーは、おそらくこのアプローチから得られたパフォーマンスの利点を取り除いてしまったでしょう。

diff を迅速にレンダリングするため、ブラウザがアイドル状態の場合にのみ diff をレンダリングできるレンダー キューを用意しました。これにより、一度に大量の diff をレンダリングする際にブラウザがフリーズすることがなくなり、ブロック時間の合計を短縮することができます。

このパイプラインによるファイルのレンダリングは、すべての差分ファイルについて以下の条件がすべて満たされた場合(true )にのみ行われます。これらの条件のいずれかがfalseである場合、このレンダーキューは発生せず、diff は期待通りにレンダリングされます。

  • このファイルの差分はすでにレンダリングされていますか?
  • このdiffにはビューアがありますか?(つまり、ダウンロードではないのですか?)
  • diffは拡張されていますか?

このChartは、発生するパイプラインの概要を示しています:

graph TD A[startRenderDiffsQueue] -->B B[commit RENDER_FILE current file index] -->C C[canRenderNextFile?] C -->|Yes| D[Render file] -->B C -->|No| E[Re-run requestIdleCallback] -->C

行われるチェック

  • アイドル時間の残りは5ミリ秒未満ですか?
  • このファイルをすでに4回レンダリングしようとしましたか?

これらのチェックが行われた後、ファイルは Vuex でrenderable としてマークされ、diffs アプリが diff 行とディスカッションのレンダリングを開始できるようになります。