병합 요청 차이점 프론트엔드 개요

이 문서는 프론트엔드 차이점 Vue 애플리케이션이 작동하는 방식과 존재하는 다양한 부분에 대한 개요를 제공합니다. 기여자들이:

  • 차이점 Vue 앱이 어떻게 설정되는지 이해합니다.
  • 향상이 필요한 영역을 식별합니다.

이 문서는 계속해서 업데이트됩니다. 차이점 애플리케이션에서 중요한 변경 사항이 있을 때마다 업데이트하십시오.

차이점 Vue 앱

구성 요소

차이점을 렌더링하는 Vue 앱은 여러 가지 다른 Vue 구성 요소를 사용하며, 그 중 일부는 GitLab 앱의 다른 영역과 공유됩니다. 아래 차트는 렌더링되는 구성 요소의 방향을 보여줍니다.

이 차트에는 다음과 같은 유형의 항목이 있습니다:

범례 항목 해석
xxx~~, ee-xxx~~ 줄인 디렉터리 경로 이름입니다. [ee]/app/assets/javascripts에서 찾을 수 있으며 0..n개의 중첩된 폴더를 생략합니다.
직사각형 노드 파일
타원형 노드 보다 심층적인 개념을 설명하는 평문
이중 직사각형 노드 단순화된 코드 브랜치
다이아몬드 및 원형 노드 2개(다이아몬드), 3개 이상(원형)의 옵션이 있는 브랜치
팬던트/배너 노드 (왼쪽 홈, 오른쪽 사각형) 중첩된 경로를 줄이기 위한 상위 디렉토리
./ 가장 가까운 상위 디렉토리 팬던트 노드와 관련된 상대적인 경로. 상위 팬던트 노드 아래에 중첩된 비상대적인 경로는 해당 디렉토리에 없습니다.
flowchart TB classDef code font-family: monospace; A["diffs~~app.vue"] descVirtualScroller(["가상 스크롤러"]) codeForFiles[["v-for(diffFiles)"]] B["diffs~~diff_file.vue"] C["diffs~~diff_file_header.vue"] D["diffs~~diff_stats.vue"] E["diffs~~diff_content.vue"] boolFileIsText{텍스트 파일인가?} boolOnlyWhitespace{공백만 있는가?} boolNotDiffable{비교할 수 없는 파일인가?} boolNoPreview{미리보기가 없는가?} descShowChanges(["'변경 사항 표시' 버튼을 보여줌"]) %% 텍스트 변경 사항이 없을 때 dirDiffViewer>"vue_shared~~diff_viewer"] F["./viewers/not_diffable.vue"] G["./viewers/no_preview.vue"] H["./diff_viewer.vue"] I["diffs~~diff_view.vue"] boolIsRenamed{이름이 바뀐 파일인가?} boolIsModeChanged{모드가 변경된 파일인가?} boolFileHasNoPath{새 경로가 있는 파일인가?} boolIsImage{이미지 파일인가?} J["./viewers/renamed.vue"] K["./viewers/mode_changed.vue"] descNoViewer(["뷰어가 렌더링되지 않음"]) L["./viewers/image_diff_viewer.vue"] M["./viewers/download.vue"] N["vue_shared~~download_diff_viewer.vue"] boolImageIsReplaced{교체된 이미지인가?} O["vue_shared~~image_viewer.vue"] switchImageMode((이미지 차이 뷰어 모드)) P["./viewers/image_diff/onion_skin_viewer.vue"] Q["./viewers/image_diff/swipe_viewer.vue"] R["./viewers/image_diff/two_up_viewer.vue"] S["diffs~~image_diff_overlay.vue"] codeForImageDiscussions[["v-for(discussions)"]] T["vue_shared~~design_note_pin.vue"] U["vue_shared~~user_avatar_link.vue"] V["diffs~~diff_discussions.vue"] W["batch_comments~~diff_file_drafts.vue"] codeForTwoUpDiscussions[["v-for(discussions)"]] codeForTwoUpDrafts[["v-for(drafts)"]] X["notes~~notable_discussion.vue"] %% 텍스트 파일 변경 사항 codeForDiffLines[["v-for(diffLines)"]] Y["diffs~~diff_expansion_cell.vue"] Z["diffs~~diff_row.vue"] AA["diffs~~diff_line.vue"] AB["batch_comments~~draft_note.vue"] AC["diffs~~diff_comment_cell.vue"] AD["diffs~~diff_gutter_avatars.vue"] AE["ee-diffs~~inline_findings_gutter_icon_dropdown.vue"] AF["notes~~noteable_note.vue"] AG["notes~~note_actions.vue"] AH["notes~~note_body.vue"] AI["notes~~note_header.vue"] AJ["notes~~reply_button.vue"] AK["notes~~note_awards_list.vue"] AL["notes~~note_edited_text.vue"] AM["notes~~note_form.vue"] AN["vue_shared~~awards_list.vue"] AO["emoji~~picker.vue"] AP["emoji~~emoji_list.vue"] descEmojiVirtualScroll(["가상 스크롤러"]) AQ["emoji~~category.vue"] AR["emoji~emoji_category.vue"] AS["vue_shared~~markdown_editor.vue"] class codeForFiles,codeForImageDiscussions code; class codeForTwoUpDiscussions,codeForTwoUpDrafts code; class codeForDiffLines code; %% 이전과 동일하게 코드 스타일을 적용 class switchImageMode code; %% 이진 노드에 대해서도 코드 스타일을 적용 class boolFileIsText,boolOnlyWhitespace,boolNotDiffable,boolNoPreview code; class boolIsRenamed,boolIsModeChanged,boolFileHasNoPath,boolIsImage code; class boolImageIsReplaced code; A --> descVirtualScroller A -->|"가상 스크롤러는 '페이지에서 찾기' 검색 (Cmd/Ctrl+f)을 사용할 때 비활성화됩니다."|codeForFiles descVirtualScroller --> codeForFiles codeForFiles --> B --> C --> D B --> E %% 파일 보기 플래그 게이트 E --> boolFileIsText boolFileIsText --> |yes| I boolFileIsText --> |no| boolOnlyWhitespace boolOnlyWhitespace --> |yes| descShowChanges boolOnlyWhitespace --> |no| dirDiffViewer dirDiffViewer --> H H --> boolNotDiffable boolNotDiffable --> |yes| F boolNotDiffable --> |no| boolNoPreview boolNoPreview --> |yes| G boolNoPreview --> |no| boolIsRenamed boolIsRenamed --> |yes| J boolIsRenamed --> |no| boolIsModeChanged boolIsModeChanged --> |yes| K boolIsModeChanged --> |no| boolFileHasNoPath boolFileHasNoPath --> |yes| boolIsImage boolFileHasNoPath --> |no| descNoViewer boolIsImage --> |yes| L boolIsImage --> |no| M M --> N %% 이미지 차이 뷰어 L --> boolImageIsReplaced boolImageIsReplaced --> |yes| switchImageMode boolImageIsReplaced --> |no| O switchImageMode -->|"'twoup' (기본값)"| R switchImageMode -->|'onion'| P switchImageMode -->|'swipe'| Q P & Q --> S S --> codeForImageDiscussions S --> AM R-->|"노트 컨테이너 div에 렌더링됨"|U & W & V %% 위의 "P & Q --> S" 문은 조합하지 말 것 %% 노드 관계의 순서가 그래프의 레이아웃을 정의하며 정확한 순서가 필요합니다. R --> S V --> codeForTwoUpDiscussions W --> codeForTwoUpDrafts %% 이 보이지 않는 링크는 `noteable_discussion`이 `design_note_pin`보다 먼저 렌더링되도록 합니다. X ~~~ T codeForTwoUpDrafts --> AB codeForImageDiscussions & codeForTwoUpDiscussions & codeForTwoUpDrafts --> T codeForTwoUpDiscussions --> X %% 텍스트 파일 차이 뷰어 I --> codeForDiffLines codeForDiffLines --> Z codeForDiffLines -->|"isMatchLine?"| Y codeForDiffLines -->|"hasCodeQuality?"| AA codeForDiffLines -->|"hasDraftNote(s)?"| AB Z -->|"hasCodeQuality?"| AE Z -->|"hasDiscussions?"| AD AA --> AC %% 임시 노트 AB --> AF AF --> AG & AH & AI AG --> AJ AH --> AK & AL & AM AK --> AN --> AO --> AP --> descEmojiVirtualScroll --> AQ --> AR AM --> AS

일부 구성 요소는 다른 구성 요소보다 더 자주 렌더링되지만, 주요 구성 요소는 diff_row.vue입니다. 이 구성 요소는 차이점 파일의 모든 차이점 라인을 렌더링합니다. 성능상의 이유로 이 구성 요소는 기능적인 구성 요소입니다. 그러나 Vue 3로 업그레이드할 때는 더 이상 필요하지 않습니다.

주요 차이점 앱 구성 요소는 차이점 앱의 주요 진입점입니다. 이 구성 요소 중 가장 중요한 부분 중 하나는 차이점 라인에 토론을 할당하는 작업을 디스패치하는 것입니다. 이 작업은 메타데이터 요청이 완료된 후, 일괄 차이점 요청이 완료된 후에 디스패치됩니다. 또한 차이점 파일 배열과 노트 배열의 변경을 감시하는 워쳐가 설정되어 있습니다. 여기에서 변경이 발생할 때마다 토론 설정 작업이 디스패치됩니다.

DiffRow 구성 요소는 차이점 라인 데이터를 하나의 형식으로 저장할 수 있도록 구성되어 있습니다. 이전에는 인라인 및 나란히 보기를 위해 두 가지 다른 형식을 요청해야 했습니다. 그러면 DiffRow 구성 요소가 이 표준 형식을 사용하여 차이점 라인 데이터를 렌더링합니다. 이 표준 형식을 사용하면 사용자가 데이터를 다시 가져오지 않고 인라인 및 나란히 보기를 전환할 수 있습니다.

참고: 이 구성 요소에서 사용되는 많은 데이터가 다양한 조건에 따라 메모화되고 캐시될 수 있습니다. 때로는 데이터가 각기 다른 구성 요소 렌더링 사이에 캐시될 수 있습니다.

Vuex 저장소

diffs 앱을 위한 Vuex 저장소는 3가지 다른 모듈로 구성되어 있습니다:

  • Notes
  • Diffs
  • Batch comments

notes 모듈은 토론을 담당하며, 여기에는 diff 토론이 포함됩니다. 이 모듈에서는 토론이 가져오고 새로운 토론을 폴링하는 것이 설정됩니다. 또한, 여기서의 변경 사항은 이슈 및 병합 요청에서 모두 테스트되어야 하는 공유 모듈입니다.

diffs 모듈은 diff와 관련된 모든 것을 담당합니다. 이는 diffs 가져오기, diff 토론을 라인에 할당하기, diff 토론 생성 등을 포함합니다.

마지막으로, batch comments 모듈은 복합적이지 않으며, 임시 댓글 기능에만 해당합니다. 그러나 이 모듈은 임시 댓글이 공개될 때마다 notes 및 diff 모듈에서 작업을 수행합니다.

API 요청

메타데이터

diffs 메타데이터 엔드포인트는 모든 diff 파일을 가져오지 않고도 diffs 앱이 빠르게 필요로 하는 기본 데이터를 가져오는 데 사용됩니다. 이에는 다음과 같은 항목이 포함됩니다:

  • Diff 파일 이름 및 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 엔드포인트의 응답 크기를 줄이기 위해, 이 응답을 여러 요청으로 분할하여:

  • 각 요청의 응답 크기를 줄입니다.
  • 첫 번째 요청이 끝나자마자 diffs 앱이 diffs를 빠르게 렌더링할 수 있게 합니다.

첫 번째 요청을 보다 빠르게 만들기 위해, 작은 양의 diffs를 요청하고, 요청하는 diffs의 수가 증가하여 요청당 diffs 수가 최대 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 앱은 이제 diffs 라인을 렌더링할 수 있게 됩니다. 그러나 렌더링을 시작하기 전에 diffs 앱은 한 번 더 형식화를 수행합니다. diff 라인 데이터를 가져와 인라인 보기 및 사이드 바이 사이드 모드 간에 쉽게 전환할 수 있도록 데이터를 매핑합니다. 이 형식화는 diff_content.vue 컴포넌트 내의 computed 속성에서 실행됩니다.

렌더 대기열

참고: 이것은 더 이상 필요하지 않을 수도 있습니다. 이 접근 방식의 미래를 결정하기 위해 일부 조사가 필요할 수 있습니다. 생성한 가상 스크롤 바가 이러한 방식에서 얻은 성능 이점을 제거해 버릴 수도 있습니다.

diff를 빠르게 렌더링하려면, 브라우저가 유휴 상태일 때만 diff를 렌더링할 수 있는 렌더 대기열이 있습니다. 이는 브라우저가 한꺼번에 많은 큰 diff를 렌더링할 때 브라우저가 멈추는 것을 방지하여 총 차단 시간을 줄일 수 있게 합니다.

이 파일 렌더링의 파이프라인은 다음 조건이 모든 diff 파일에 대해 true인 경우에만 발생합니다. 이 중 하나라도 false인 경우에는 이 렌더 대기열이 발생하지 않고 diffs가 기대한 대로 렌더링됩니다.

  • 이 파일의 diffs는 이미 렌더링되었습니까?
  • 이 diff에 뷰어가 있습니까? (즉, 다운로드가 아닌가요?)
  • diff가 확장되어 있습니까?

그림은 발생하는 파이프라인에 대한 간략한 개요를 제공합니다:

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 ms보다 적습니까?
  • 이 파일을 렌더링하려는 시도는 이미 4번이 되었습니까?

이러한 확인이 완료되면 파일은 Vuex에서 렌더링 가능으로 표시되어 diffs 앱이 이제 diff 라인과 토론을 렌더링할 수 있게 합니다.