summaryrefslogtreecommitdiff
path: root/doc/development/merge_request_concepts/diffs/frontend.md
diff options
context:
space:
mode:
Diffstat (limited to 'doc/development/merge_request_concepts/diffs/frontend.md')
-rw-r--r--doc/development/merge_request_concepts/diffs/frontend.md208
1 files changed, 208 insertions, 0 deletions
diff --git a/doc/development/merge_request_concepts/diffs/frontend.md b/doc/development/merge_request_concepts/diffs/frontend.md
new file mode 100644
index 00000000000..6bd6d80af94
--- /dev/null
+++ b/doc/development/merge_request_concepts/diffs/frontend.md
@@ -0,0 +1,208 @@
+---
+stage: Create
+group: Code Review
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Merge request diffs frontend overview
+
+This document provides an overview on how the frontend diffs Vue application works, and
+the various different parts that exist. It should help contributors:
+
+- Understand how the diffs Vue app is set up.
+- Identify any areas that need improvement.
+
+This document is a living document. Update it whenever anything significant changes in
+the diffs application.
+
+## Diffs Vue app
+
+### Components
+
+The Vue app for rendering diffs uses many different Vue components, some of which get shared
+with other areas of the GitLab app. The below chart shows the direction for which components
+get rendered.
+
+NOTE:
+[Issue #388843](https://gitlab.com/gitlab-org/gitlab/-/issues/388843) is open to
+generate a Mermaid graph of the components diagram. An image version of the
+diagram is available in the issue.
+
+Some of the components are rendered more than others, but the main component is `diff_row.vue`.
+This component renders every diff line in a diff file. For performance reasons, this
+component is a functional component. However, when we upgrade to Vue 3, this is no longer
+required.
+
+The main diff app component is the main entry point to the diffs app. One of the most important parts
+of this component is to dispatch the action that assigns discussions to diff lines. This action
+gets dispatched after the metadata request is completed, and after the batch diffs requests are
+finished. There is also a watcher set up to watches for changes in both the diff files array and the notes
+array. Whenever a change happens here, the set discussion action gets dispatched.
+
+The DiffRow component is set up in a way that allows for us to store the diff line data in one format.
+Previously, we had to request two different formats for inline and side-by-side. The DiffRow component
+then uses this standard format to render the diff line data. With this standard format, the user
+can then switch between inline and side-by-side without the need to re-fetch any data.
+
+NOTE:
+For this component, a lot of the data used and rendered gets memoized and cached, based on
+various conditions. It is possible that data sometimes gets cached between each different
+component render.
+
+### Vuex store
+
+The Vuex store for the diffs app consists of 3 different modules:
+
+- Notes
+- Diffs
+- Batch comments
+
+The notes module is responsible for the discussions, including diff discussions. In this module,
+the discussions get fetched, and the polling for new discussions is setup. This module gets shared
+with the issue app as well, so changes here need to be tested in both issues and merge requests.
+
+The diffs module is responsible for the everything related to diffs. This includes, but is not limited
+to, fetching diffs, assigning diff discussions to lines, and creating diff discussions.
+
+Finally, the batch comments module is not complex, and is responsible only for the draft comments feature.
+However, this module does dispatch actions in the notes and diff modules whenever draft comments
+are published.
+
+### API Requests
+
+#### Metadata
+
+The diffs metadata endpoint exists to fetch the base data the diffs app requires quickly, without
+the need to fetch all the diff files. This includes, but is not limited to:
+
+- Diff file names, including some extra meta data for diff files
+- Added and removed line numbers
+- Branch names
+- Diff versions
+
+The most important part of the metadata response is the diff file names. This data allows the diffs
+app to render the file browser inside of the diffs app, without waiting for all batch diffs
+requests to complete.
+
+When the metadata response is received, the diff file data gets sent to a web worker. The web worker
+exists to allow for this data, which for larger merge requests could be huge, to be processed off
+the main thread. Processing this data involves getting the data into the correct structure
+that the frontend requires to render the file browser in either tree view or list view.
+
+```mermaid
+graph TD
+ A[fetchDiffFilesMeta]
+ B[Create web worker]
+ C[Fetch data]
+ D[SET_DIFF_METADATA]
+ E[Post worker data]
+ F[Worker message event listener]
+ K[SET_TREE_DATA]
+
+ G[TreeWorker]
+ H[onMessage]
+ I[generateTreeList]
+ J[postMessage sortTree]
+
+ A -->B
+ E -->F
+ B -->C
+ C -->D
+ D -->E
+
+ G -->H
+ H -->I
+ I -->J
+ J -->F
+
+ F -->K
+```
+
+The structure for this file object is:
+
+```javascript
+{
+ "key": "",
+ "path": "",
+ "name": "",
+ "type": "",
+ "tree": [],
+ "changed": true,
+ "tempFile": false,
+ "deleted": false,
+ "fileHash": "",
+ "addedLines": 1,
+ "removedLines": 1,
+ "parentPath": "/",
+ "submodule": false
+}
+```
+
+#### Batch diffs
+
+To reduce the response size for the diffs endpoint, we are splitting this response up into different
+requests, to:
+
+- Reduces the response size of each request.
+- Allows the diffs app to start rendering diffs as quickly as the first request finishes.
+
+To make the first request quicker, the request gets sent asking for a small amount of
+diffs. The number of diffs requested then increases, until the maximum number of diffs per request is 30.
+
+When the request finishes, the diffs app formats the data received into a format that makes
+it easier for the diffs app to render the diffs lines.
+
+```mermaid
+graph TD
+ A[fetchDiffFilesBatch] -->
+ B[commit SET_DIFF_DATA_BATCH] -->
+ C[prepareDiffData] -->
+ D[prepareRawDiffFile] -->
+ E[ensureBasicDiffFileLines] -->
+ F[prepareDiffFileLines] -->
+ G[finalizeDiffFile] -->
+ H[deduplicateFilesList]
+```
+
+After this has been completed, the diffs app can now begin to render the diff lines. However, before
+anything can be rendered the diffs app does one more format. It takes the diff line data, and maps
+the data into a format for easier switching between inline and side-by-side modes. This
+formatting happens in a computed property inside the `diff_content.vue` component.
+
+### Render queue
+
+NOTE:
+This _might_ not be required any more. Some investigation work is required to decide
+the future of the render queue. The virtual scroll bar we created has probably removed
+any performance benefit we got from this approach.
+
+To render diffs quickly, we have a render queue that allows the diffs to render only if the
+browser is idle. This saves the browser getting frozen when rendering a lot of large diffs at once,
+and allows us to reduce the total blocking time.
+
+This pipeline of rendering files happens only if all the below conditions are `true` for every
+diff file. If any of these are `false`, then this render queue does not happen and the diffs get
+rendered as expected.
+
+- Are the diffs in this file already rendered?
+- Does this diff have a viewer? (Meaning, is it not a download?)
+- Is the diff expanded?
+
+This chart gives a brief overview of the pipeline that happens:
+
+```mermaid
+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
+```
+
+The checks that happen:
+
+- Is the idle time remaining less than 5 ms?
+- Have we already tried to render this file 4 times?
+
+After these checks happen, the file is marked in Vuex as `renderable`, which allows the diffs
+app to start rendering the diff lines and discussions.