Source Editor
GitLab v19.1Source Editor는 GitLab의 편집 UX를 제공합니다. 사용자가 파일 내용을 편집해야 할 때만 Source Editor를 사용하세요. 작업 중인 페이지에 이미 Source Editor가 로드되어 있다면, Source Editor에서 읽기 전용 콘텐츠를 표시하는 것도 여전히 유효한 방법입니다.
Source Editor는 GitLab의 편집 UX를 제공합니다. Monaco 에디터를 감싼 얇은 래퍼로, 필요한 헬퍼와 추상화를 제공하며 확장 기능을 통해 Monaco를 확장합니다. 다음을 포함한 여러 GitLab 기능에서 사용됩니다:
Source Editor를 사용해야 하는 경우#
사용자가 파일 내용을 편집해야 할 때만 Source Editor를 사용하세요.
소스 코드를 표시만 하면 되는 경우에는 BlobContent 컴포넌트를 사용하는 것을 고려하세요.
작업 중인 페이지에 이미 Source Editor가 로드되어 있다면, Source Editor에서 읽기 전용 콘텐츠를 표시하는 것도 여전히 유효한 방법입니다.
Source Editor 사용 방법#
Source Editor는 프레임워크에 독립적이며 Rails와 Vue를 포함한 모든 애플리케이션에서 사용할 수 있습니다.
통합을 돕기 위해 전용 <source-editor> Vue 컴포넌트를 제공하지만, Source Editor의 통합은 일반적으로 간단합니다:
Source Editor 가져오기:
import SourceEditor from '~/editor/source_editor';
뷰(view)에 대한 전역 에디터 초기화:
const editor = new SourceEditor({
// Editor Options.
// The list of all accepted options can be found at
// https://microsoft.github.io/monaco-editor/docs.html
});
에디터 인스턴스 생성:
editor.createInstance({
// Source Editor configuration options.
})
Source Editor 인스턴스는 다음 설정 옵션을 허용합니다:
| 옵션 | 필수 여부 | 설명 |
|---|---|---|
| el | true | HTML Node: 에디터를 렌더링할 요소. |
| blobPath | false | String: 에디터에 렌더링할 파일 이름. 해당 파일에 사용할 올바른 구문 강조 도구를 식별하거나 다른 파일 유형에 사용됩니다. 실제 파일 이름을 알 수 없거나 역할이 없을 때 *.js 같은 와일드카드를 허용합니다. |
| blobContent | false | String: 에디터에 렌더링할 초기 콘텐츠. |
| extensions | false | Array: 이 인스턴스에서 사용할 확장 기능. |
| blobGlobalId | false | String: 자동 생성된 속성. |
| Editor Options | false | Object(s): 위 목록에 없는 모든 속성은 이 특정 인스턴스의 Editor Option으로 처리됩니다. 이 필드를 사용하여 인스턴스 수준에서 전역 Editor Options를 재정의하세요. Editor Options의 전체 인덱스를 사용할 수 있습니다. |
`blobGlobalId` 속성은 향후 릴리즈에서 제거될 수 있습니다.
blobGlobalId가 필요한 특정 사용 사례가 없다면 표준 blob 속성을 사용하세요.
API#
에디터는 인스턴스 수준의 추가 함수와 함께 Monaco 에디터가 제공하는 것과 동일한 공개 API를 사용합니다:
| 함수 | 인수 | 설명 |
|---|---|---|
| updateModelLanguage | path: String | 전달된 경로의 확장자에 따라 인스턴스의 구문 강조를 업데이트합니다. 인스턴스 수준에서만 사용 가능합니다. |
| use | Array of objects | 인스턴스에 적용할 확장 기능 배열. 객체 배열만 허용합니다. 확장 기능의 ES6 모듈은 use에 전달되기 전에 뷰나 컴포넌트에서 가져와서 확인해야 합니다. 인스턴스 및 전역 에디터(모든 인스턴스) 수준에서 사용 가능합니다. |
| Monaco Editor options | 문서 참조 | 기본 Monaco 에디터 옵션. |
팁#
에디터 로딩 상태.
로딩 상태는 Source Editor에 내장되어 있어, HTML에서 스피너와 로더가 거의 필요하지 않습니다.
내장 로딩 상태를 활용하려면 에디터가 포함될 HTML 요소에 data-editor-loading 속성을 설정하세요.
부트스트래핑 시 Source Editor가 자동으로 로더를 표시합니다.
파일 이름이 변경되면 구문 강조를 업데이트하세요.
// fileNameEl here is the HTML input element that contains the filename
fileNameEl.addEventListener('change', () => {
this.editor.updateModelLanguage(fileNameEl.value);
});
에디터 콘텐츠 가져오기.
매번 변경 시마다 에디터에 리스너를 설정할 수 있지만, 이는 빠르게 비용이 많이 드는 작업이 될 수 있습니다. 대신, 필요할 때 에디터의 콘텐츠를 가져오세요. 예를 들어, 폼 제출 시:
form.addEventListener('submit', () => {
my_content_variable = this.editor.getValue();
});
성능
Source Editor 자체는 매우 슬림하지만 Monaco 에디터에 의존하기 때문에 용량이 추가됩니다. Source Editor를 뷰에 추가할 때마다 JavaScript 번들 크기가 상당히 증가하여 뷰의 로딩 성능에 영향을 미칩니다. 다음 중 하나에 해당하는 경우 에디터를 필요 시에만 가져와야 합니다:
뷰에 에디터가 필요한지 확실하지 않은 경우.
- 에디터가 뷰의 보조 요소인 경우.
Source Editor를 필요 시에 로드하는 것은 다른 모듈을 로드하는 것과 동일하게 처리됩니다:
someActionFunction() {
import(/* webpackChunkName: 'SourceEditor' */ '~/editor/source_editor').
then(({ default: SourceEditor }) => {
const editor = new SourceEditor();
...
});
...
}
확장 기능#
Source Editor는 전체 제품에 범용적이고 확장 가능한 편집 도구를 제공하며, 특정 그룹에 의존하지 않습니다. Source Editor의 코어는 Create::Editor FE Team이 소유하지만, 모든 그룹이 확장 기능(주요 기능 요소)을 소유할 수 있습니다. Source Editor 확장 기능의 목표는 에디터 코어를 슬림하고 안정적으로 유지하는 것입니다. 필요한 기능은 이 코어에 확장 기능으로 추가할 수 있습니다. 모든 그룹이 Source Editor의 변경이 자신들의 기능을 손상시키거나 재정의하는 것을 걱정하지 않고 새로운 편집 기능을 구축하고 소유할 수 있습니다.
확장 기능에서 다른 모듈에 의존할 수 있습니다. 이러한 구성은 필요할 때만 의존성을 가져와서 Source Editor 코어의 크기를 적절히 유지하는 데 도움이 됩니다.
구조적으로 Source Editor의 완전한 구현은 다음 다이어그램으로 나타낼 수 있습니다:
%%{init: { "fontFamily": "GitLab Sans" }}%% graph TD; B[Extension 1]---A[Source Editor] C[Extension 2]---A[Source Editor] D[Extension 3]---A[Source Editor] E[...]---A[Source Editor] F[Extension N]---A[Source Editor] A[Source Editor]---Z[Monaco]
확장 기능은 JavaScript 객체를 내보내는 ES6 모듈입니다:
import { Position } from 'monaco-editor';
export default {
navigateFileStart() {
this.setPosition(new Position(1, 1));
},
};
확장 기능의 함수에서 this는 현재 Source Editor 인스턴스를 참조합니다.
this를 사용하면 이 특정 경우에 setPosition() 메서드와 같은 인스턴스의 완전한 API에 접근할 수 있습니다.
기존 확장 기능 사용#
Source Editor 인스턴스에 확장 기능을 추가하려면 다음 단계가 필요합니다:
import SourceEditor from '~/editor/source_editor';
import MyExtension from '~/my_extension';
const editor = new SourceEditor().createInstance({
...
});
editor.use(MyExtension);
확장 기능 만들기#
첫 번째 Source Editor 확장 기능을 만들어 보겠습니다.
확장 기능은 Source Editor의 기능을 확장하는 데 사용되는 기본 Object를 내보내는 ES6 모듈입니다.
테스트로, 호출될 때 에디터의 콘텐츠를 alert로 출력하는 새 함수로 Source Editor를 확장하는 확장 기능을 만들어 보겠습니다.
~/my_folder/my_fancy_extension.js:
export default {
throwContentAtMe() {
alert(this.getValue());
},
};
코드 예제에서 this는 인스턴스를 참조합니다.
인스턴스를 참조함으로써 getValue()와 같은 함수를 포함하는 완전한 기반 Monaco 에디터 API에 접근할 수 있습니다.
이제 확장 기능을 사용해 보겠습니다:
~/my_folder/component_bundle.js:
import SourceEditor from '~/editor/source_editor';
import MyFancyExtension from './my_fancy_extension';
const editor = new SourceEditor().createInstance({
...
});
editor.use(MyFancyExtension);
...
someButton.addEventListener('click', () => {
editor.throwContentAtMe();
});
먼저 Source Editor와 새 확장 기능을 가져옵니다.
그런 다음 에디터와 인스턴스를 생성합니다.
기본적으로 Source Editor에는 throwContentAtMe 메서드가 없습니다.
하지만 editor.use(MyFancyExtension) 줄이 해당 메서드를 인스턴스에 가져옵니다.
그 후 필요할 때 언제든지 사용할 수 있습니다.
이 경우 이론적인 버튼이 클릭될 때 호출합니다.
이 스크립트는 someButton이 클릭될 때 에디터의 콘텐츠가 담긴 alert를 표시합니다.
팁#
성능
Source Editor 자체처럼, 모든 확장 기능은 뷰의 로딩 성능을 해치지 않도록 필요 시에 로드할 수 있습니다:
const EditorPromise = import(
/* webpackChunkName: 'SourceEditor' */ '~/editor/source_editor'
);
const MarkdownExtensionPromise = import('~/editor/source_editor_markdown_ext');
Promise.all([EditorPromise, MarkdownExtensionPromise])
.then(([{ default: SourceEditor }, { default: MarkdownExtension }]) => {
const editor = new SourceEditor().createInstance({
...
});
editor.use(MarkdownExtension);
});
여러 확장 기능 사용
확장 기능 배열을 use 메서드에 전달하세요:
editor.use([FileTemplateExtension, MyFancyExtension]);