소스 편집기

소스 편집기는 GitLab에서의 편집 경험을 제공합니다. 이것은 모나코 편집기를 감싸서 필요한 도우미 및 추상화를 제공하고 모나코를 확장(extension)하여 여러 GitLab 기능에서 사용됩니다.

소스 편집기 사용 시기

사용자가 파일 내용을 편집해야 할 때에만 소스 편집기를 사용하세요. 소스 코드를 표시만 해야 한다면, BlobContent 컴포넌트를 사용하는 것을 고려해보세요.

작업 중인 페이지에서 이미 소스 편집기를 로드하고 있다면, 소스 편집기에서 읽기 전용 콘텐츠를 표시하는 것도 여전히 유효한 옵션입니다.

소스 편집기 사용 방법

소스 편집기는 프레임워크에 구애받지 않으며 Rails 및 Vue를 포함한 모든 애플리케이션에서 사용할 수 있습니다. 통합을 돕기 위해 전용 <source-editor> Vue 컴포넌트가 있지만, 소스 편집기의 통합은 일반적으로 간단합니다.

  1. 소스 편집기를 가져오기(import)하세요:

    import SourceEditor from '~/editor/source_editor';
    
  2. 뷰를 위해 글로벌 편집기를 초기화하세요:

    const editor = new SourceEditor({
      // 편집기 옵션.
      // 전체 허용된 옵션 목록은
      // https://microsoft.github.io/monaco-editor/docs.html에서 찾을 수 있습니다.
    });
    
  3. 편집기 인스턴스를 생성하세요:

    editor.createInstance({
      // 소스 편집기 구성 옵션.
    })
    

소스 편집기의 인스턴스는 다음 구성 옵션을 허용합니다:

옵션 필수 여부 설명
el true HTML 노드: 편집기를 렌더링할 요소.
blobPath false String: 편집기에 렌더링할 파일의 이름으로, 해당 파일에 사용할 올바른 구문 강조 기능을 식별하는 데 사용하거나 다른 파일 유형을 사용합니다. *.js와 같이 실제 파일 이름이나 역할을 하지 않는 경우 와일드카드를 사용할 수 있습니다.
blobContent false String: 편집기에 렌더링할 초기 콘텐츠.
extensions false Array: 이 인스턴스에서 사용할 확장(extension).
blobGlobalId false String: 자동 생성된 속성.
참고: 이 속성은 향후 사라질 수 있습니다. 알고 있는 경우가 아니라면 blobGlobalId를 전달하지 마십시오.
편집기 옵션 false Object(s): 위 목록 외에 모든 속성은 특정 인스턴스 수준의 편집기 옵션으로 처리됩니다. 이 필드를 사용하여 인스턴스 수준에서 전역 편집기 옵션을 재정의하세요. 전체 편집기 옵션의 색인을 참조하세요.

API

편집기는 인스턴스 수준에 추가 기능과 함께 모나코 편집기에서 제공되는 공개 API와 동일한 API를 사용합니다:

함수 인수 설명
updateModelLanguage path: 문자열 인스턴스의 구문 강조 기능을 전달된 path의 확장에 따라 업데이트합니다. 인스턴스 수준에서만 사용 가능합니다.
use 객체 배열 인스턴스에 적용할 확장(extension) 배열. 객체 배열만 수용합니다. 확장의 ES6 모듈은 뷰 또는 컴포넌트에서 use에 전달되기 전에 가져와야 합니다. 인스턴스 및 글로벌 편집기(모든 인스턴스) 수준에서 사용 가능합니다.
모나코 편집기 옵션 문서 참조 기본 모나코 편집기 옵션.

  1. 편집기의 로딩 상태.

    로딩 상태는 소스 편집기에 내장되어 있으므로 스피너와 로더가 거의 필요하지 않습니다. 내장 로딩 상태를 이용하려면, 편집기를 포함해야 할 HTML 요소에 data-editor-loading 속성을 설정하세요. 소스 편집기는 초기화되면 로더를 자동으로 표시합니다.

    소스 편집기: 로딩 상태

  2. 파일 이름이 변경되면 구문 강조 기능을 업데이트하세요.

    // 여기서 fileNameEl은 파일 이름을 포함하는 HTML 입력 요소입니다.
    fileNameEl.addEventListener('change', () => {
      this.editor.updateModelLanguage(fileNameEl.value);
    });
    
  3. 편집기의 콘텐츠 가져오기.

    편집기의 변경마다 청취자(listener)를 설정할 수 있지만, 빠르게 비용이 많이 발생할 수 있습니다. 대신 필요할 때 편집기의 콘텐츠를 가져오세요. 예를 들어, 양식 제출 시:

    form.addEventListener('submit', () => {
      my_content_variable = this.editor.getValue();
    });
    
  4. 성능

    소스 편집기 자체는 매우 가볍지만 추가적인 무게를 추가하는 모나코 편집기에 의존합니다. 뷰에 소스 편집기를 추가할 때마다 자바스크립트 번들의 크기가 크게 증가하여 뷰의 로딩 성능에 영향을 줄 수 있습니다. 뷰가 편집기가 필요한지 확실하지 않은 경우 또는 편집기가 뷰의 부가적 요소인 경우에는 요청 시 편집기를 가져오는 것을 권장합니다.

    요청 시 소스 편집기를 가져오는 것은 다른 모듈을 가져오는 것처럼 다루어집니다:

    someActionFunction() {
      import(/* webpackChunkName: 'SourceEditor' */ '~/editor/source_editor').
        then(({ default: SourceEditor }) => {
          const editor = new SourceEditor();
          ...
        });
      ...
    }
    

확장 기능

소스 편집기는 전체 제품에 대한 범용적이고 확장 가능한 편집 도구를 제공하며 특정 그룹에 의존하지 않습니다. 소스 편집기의 핵심은 Create::Editor FE Team에서 소유하고 있지만, 어떤 그룹이든지 확장 기능, 즉 주요 기능 요소를 소유할 수 있습니다. 소스 편집기 확장의 목표는 편집기 핵심을 가볍고 안정적으로 유지하는 것입니다. 필요한 기능은 해당 핵심에 확장으로 추가할 수 있습니다. 소스 편집기의 변경으로 인해 새로운 편집 기능을 구축하고 소유하는 어떤 그룹도 불편함 없이 적용할 수 있습니다.

확장 기능에서 다른 모듈에 의존할 수 있습니다. 이러한 구성은 필요할 때만 종속성을 가져와 소스 편집기의 핵심 크기를 유지하는 데 도움이 됩니다.

구조적으로, 소스 편집기의 완전한 구현은 다음과 같이 나타낼 수 있습니다:

graph TD; B[확장 1]---A[소스 편집기] C[확장 2]---A[소스 편집기] D[확장 3]---A[소스 편집기] E[...]---A[소스 편집기] F[확장 N]---A[소스 편집기] A[소스 편집기]---Z[모나코]

확장은 JavaScript 객체를 내보내는 ES6 모듈입니다.

import { Position } from 'monaco-editor';

export default {
  navigateFileStart() {
    this.setPosition(new Position(1, 1));
  },
};

확장의 함수에서 this는 현재 소스 편집기 인스턴스를 가리킵니다. this를 사용하여 이러한 특정 경우의 setPosition() 메서드와 같은 완전한 인스턴스 API에 액세스할 수 있습니다.

기존 확장 기능 사용

소스 편집기 인스턴스에 확장을 추가하려면 다음 단계를 수행하면 됩니다:

import SourceEditor from '~/editor/source_editor';
import MyExtension from '~/my_extension';

const editor = new SourceEditor().createInstance({
  ...
});
editor.use(MyExtension);

확장 기능 생성

첫 번째 소스 편집기 확장을 만들어 봅시다. 확장은 Source Editor의 기능을 확장하는 데 사용되는 기본 Object를 내보내는 ES6 모듈입니다. 테스트를 위해 호출될 때 에디터 내용을 alert로 출력하는 새로운 함수로 Source Editor를 확장하는 확장을 만들어 봅시다.

~/my_folder/my_fancy_extension.js:

export default {
  throwContentAtMe() {
    alert(this.getValue());
  },
};

위의 코드 예제에서 this는 인스턴스를 가리킵니다. 인스턴스를 참조함으로써 우리는 전체 기본 Monaco 편집기 API에 액세스하여 getValue()와 같은 함수에 액세스할 수 있습니다.

이제 우리의 확장을 사용해 봅시다:

~/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 편집기와 새로운 확장을 가져옵니다. 그런 다음 편집기와 해당 인스턴스를 생성합니다. 기본적으로 소스 편집기에는 throwContentAtMe 메서드가 없지만 editor.use(MyFancyExtension) 줄은 해당 메서드를 인스턴스에 가져옵니다. 그 후에는 필요할 때 언제든지 사용할 수 있습니다. 이 경우에는 가상의 버튼이 클릭되었을 때 호출됩니다.

이 스크립트는 someButton이 클릭될 때 에디터의 내용을 포함한 alert를 결과로 표시합니다.

Source 편집기 새로운 확장의 결과

  1. 성능

    소스 편집기 자체와 마찬가지로 어떤 확장도 보기의 로딩 성능에 해를 끼치지 않도록 필요할 때에만 로드될 수 있습니다:

     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);
       });
    
  2. 복수의 확장 사용

    use 메서드에 확장 배열을 전달하기만 하면 됩니다:

     editor.use([FileTemplateExtension, MyFancyExtension]);