본문 바로가기
Programming/React

Monaco Editor를 활용해서 React 기반 프로젝트에 코드 에디터 적용하기!

by mingule 2022. 3. 18.

최근 개발하면서 웹상에 SQL 쿼리를 작성하는 에디터를 넣어야하는 일이 생겼다! 

빠르게 만들어야하는 MVP개발이었기때문에, 에디터를 직접 만들기보다는 이미 잘 만들어져있는 에디터들을 골라 그 중 하나를 사용하기로 했다.(뭔가 아쉽.. 호호) 그래서 아래의 내용을 포함한 에디터를 찾아 비교해보고, 가장 나은 에디터가 아니라 내 입맛에 맞추어 쉽고 빠르게 개발할 수 있는 에디터를 찾아 사용하기로 했다! 하핬핬!

1. 라이선스가 무료

2. 키워드 하이라이터 기능

3. 들여쓰기 지원

4. 라인넘버 지원

5. SQL 언어 지원

(+ 자동완성 기능 등)

 

다양한 에디터들을 찾을 수 있었는데, 아무래도 많은 사람들이 사용하고 있어 활발하게 커뮤니티가 유지되면서, 쉽고 빠르게 개발할 수 있는 라이브러리들에 우선순위를 두고 찾아봤다. 그 결과, 두가지 옵션을 찾을 수 있었다.

 

사용하면서 추가한 내용) NextJS 환경에서 모나코 에디터의 문제점이 있다!
확인하실 분들은 맨 아래로 내려서 먼저 해당 내용에 대해 확인하고 적용하시는 것을 추천드립니다..!

 

https://www.npmjs.com/package/codemirror

 

codemirror

Full-featured in-browser code editor. Latest version: 5.65.2, last published: 25 days ago. Start using codemirror in your project by running `npm i codemirror`. There are 2175 other projects in the npm registry using codemirror.

www.npmjs.com

https://www.npmjs.com/package/monaco-editor

 

monaco-editor

A browser based code editor. Latest version: 0.33.0, last published: 7 days ago. Start using monaco-editor in your project by running `npm i monaco-editor`. There are 833 other projects in the npm registry using monaco-editor.

www.npmjs.com

이중에서 나는 VSCode에서 기반으로 사용하고있기도 한 Monaco Editor를 사용해보기로 결정했다. 

예전부터 VSCode가 Javascript(Typescript)로 개발되고 있다고 들은 터라 Monaco Editor에 관심을 좀 가지고 있기도 했고, 개인적으로 UI도 Codemirror보다는 좀 더 예쁘다고 생각했기 때문이다. 호홋.. ㅎㅎ.. (그냥 써보고 싶었다는 뜻) 

 

공식 문서는 아래에 있다.

https://microsoft.github.io/monaco-editor/

 

Monaco Editor

Rich IntelliSense, Validation TypeScript, JavaScript, CSS, LESS, SCSS, JSON, HTML Basic Syntax Colorization XML, PHP, C#, C++, Razor, Markdown, Diff, Java, VB, CoffeeScript, Handlebars, Batch, Pug, F#, Lua, Powershell, Python, Ruby, SASS, R, Objective-C Co

microsoft.github.io

 

나는 요 Monaco Editor를 기반으로 리액트에서 쉽게 사용할 수 있게 만든 @monaco-editor/react를 찾아서, 최종적으로 요 라이브러리를 사용해서 에디터를 적용했다. 우리가 리액트를 기반으로 Monaco Editor를 적용할 때 필요한 설정들을 미리 해주고, 쉽게 사용할 수 있도록 해주기 때문에 굉장히 편리하다고 생각했당. 히히

 

아래 명령어를 통해 프로젝트에 다운받아 사용하면 된다.

npm install @monaco-editor/react 

yarn add @monaco-editor/react

 

정말 놀랍게도 아래와 같이 코드를 작성하면 에디터 적용은 끝난다. 짱 쉽 다 !

import Editor from '@monaco-editor/react'

const SqlQueryEditor = () => {
	return <Editor height='100%' />
}

 

뭐 당연히,, 이렇게만 하지는 않았고, 에디터 옵션을 통해 내가 원하는 에디터의 모양을 만들어줬다.

기본 Monaco Editor는 2가지의 테마를 제공한다. 'light'과 'vs-dark' 테마인데, 우리 사이트의 테마는 보라계열이어서, 좀 아쉬웠다. 그래서 내가 새로운 테마를 만들거나, 이미 멋쟁이들이 만들어놓은 테마를 가져다가 써야했는데, 나는 (당연히) 가져다가 쓰는 방향을 선택했다. 테마를 하나하나 만지고 있을 시간은 없었기 때문에,,, (재미는 있는데 시간이 넘 오래 걸리더라..ㅠ)

 

그래서 멋쟁이들이 만들어놓은 테마들을 찾기 시작했는데, monaco-themes 라는 라이브러리를 찾았다. 다양한 테마가 있어 내가 원하는 테마를 가져다가 편하게 사용할 수 있었기 때문에 고민않고 적용했다. 나는 그 중에서 Tomorrow라는 테마를 적용했다. 연보랏빛 하이라이터가 적용되어있어서, 넘 예뻤다. (사심가득)

 

이런 테마를 적용하려면 먼저 useMonaco Hook을 사용해 monaco 인스턴스를 만들어 사용해야한다. 

monaco 인스턴스는 비동기적으로 동작하기 때문에, 처음에는 null이 뜬다. 그래서 에러가 날 수 있으니, monaco 인스턴스가 잘 만들어지고 나서 사용할 수 있도록 조건을 걸어줘야한다. 

 

아래처럼 원하는 테마를 가져와서, 적용할 수 있다. 

import Editor, { useMonaco } from '@monaco-editor/react';
import tomorrowTheme from 'monaco-themes/themes/Tomorrow.json';

const SqlQueryEditor: React.FC<SqlQueryEditorProps> = ({...}) => {
  const monaco = useMonaco();
  // 내가 사용할 모나코 인스턴스를 생성한다.
  
  useEffect(() => {
    if (!monaco) return;
    // 모나코 인스턴스가 null이면 early return을 해준다.
      
    monaco.editor.defineTheme(
      'tomorrow',
      tomorrowTheme as editor.IStandaloneThemeData
    );
    // 내가 원하는 이름으로 테마를 define해준다. 
    // 나는 'tomorrow'라는 이름으로 monaco-themes에서 받아온 Tomorrow라는 테마를 define해 준 것이다.
      
    monaco.editor.setTheme('tomorrow')
    // 내가 사용하는 모나코 에디터에 테마를 적용해준다.
  }, [monaco])
  
  return <Editor theme="tomorrow" />
}

 

자, 이제 테마는 됐는데.. 뭔가 부족하다. 

Monaco Editor는 처음에 미니맵(우측 상단에 내 코드를 작게 다 보여주는 맵)이 활성화되어있다. (아래 사진 참고)

우측 상단을 보면 미니맵이 보이는 것을 알 수 있다. (이건 VSCode를 캡쳐해온것!)

나는 미니맵을 원하지도 않고..

코드랑 에디터가 너무 붙어있어서.. 아래처럼 padding도 좀 주고싶은데.. 하면 Editor에서 제공하는 props를 통해 이런 것들을 해결할 수 있다. 

(좌) padding: 0 / (우) paddingTop: 50 (비교를 위한 극단적인 비교)

나는 아래와 같이 에디터 옵션들을 넣어줬다. 직관적으로 알 수 있겠지만, 폰트사이즈 조절, 미니맵 없애기, 기본으로 vertical/horizontal로 붙어있는 scrollbar auto로 만들어주기 등의 옵션을 줬다. 

readOnly 옵션도 있어서, 상황에 따라 Edit하지 못하도록 만들 수도 있어서 넘 좋았다. 

<Editor 
  height='100%'
  defaultValue='--여기에 SQL문을 작성하시면 됩니다.'
  ...
  language='sql'
  theme='tomorrow'
  options={{
    fontSize: 15,
    minimap: { enabled: false },
    scrollbar: {
      vertical: 'auto',
      horizontal: 'auto'
    }
    ...
  }}
/>

제공하는 옵션은 정말 많지만, 요정도면 정말 편하게 깔끔한 - 에디터를 만들 수 있었다. 프항항 ㅎㅎㅎㅎ

 

모나코 에디터 정말 많이 사용하는 것 같은데, 관련해서 정리된 글이 딱히 없는 것 같아서 (내가 못찾은거겠지..?ㅎ,,,,) 한번 정리했다.

@monaco-editor/react에 되게 자세하게 제공하는 기능들과 그 예시가 나와있어서, 쉽게 개발하고 또 정리할 수 있었던 것 같다. 

알럽잇! 

 

후후.... 재밌었다.... 요즘 바빠서 정리를 잘 못하는데, 틈틈히 까먹지 않게 정리나 회고를 좀 해야겠다. 프항항!!!

- 그럼 이번 포스팅도 끗 - 

 


Next.js환경에서 Monaco Editor 의 문제점

겪은 오류 

- Monaco Editor를 사용한 페이지 → 다른 페이지 → Monaco Editor를 사용한 페이지(다시 돌아옴)

이런 경우, 다시 돌아온 페이지에서 Monaco Editor의 CSS가 사라진다. 

 

원인 파악

1. Monaco Editor 컴포넌트가 Mount되면, Editor 컴포넌트에서 Header 태그에 Monaco Editor의 CSS를 가져오는 Link 태그를 넣는다. (최초 한번)

2. 다른 페이지로 이동을 하면, _document.tsx 파일의 next 컴포넌트가 다시 렌더링되면서, Script를 가져오는 Link 태그가 사라진다.

3. 그런데 Monaco Editor는 우리가 다시 에디터를 적용한 페이지에 접속하면, 이 때에는 이미 CSS를 가져왔다고 판단해 Link 태그를 다시 넣지 않는다. 그래서 CSS가 사라진 상태로 보이는 것!

 

임시로 next HEAD 컴포넌트에 CSS URL을 삽입하는 방법으로 해결을 할 수는 있지만, 말 그대로 임시방편이라, 추후 에디터를 바꾸게 될 것 같다. 또르르.. 

JS, CSS파일을 같이 로드하는 케이스에 대해 Next.js가 지원하지 않는다고 하는데 Monaco Editor에서는 같이 사용하고 있기 때문에, Next.js 환경에서는 사용하기 힘들 것이라고 생각하고 있다. 

 

흠 그래도 방법을 더 찾아보아야겠다..! 아쉽,, 

댓글