일이 지났습니다. 시의성에 유의하세요
저는 약 6년 동안 Replit에서 일해왔으며, 팀이 성장함에 따라 제품의 IDE(우리는 이를 "작업 공간"이라고 부릅니다) 부분에 집중해왔습니다. 당연히 코드 편집기에 점점 더 집중하게 되었죠. 우리만의 요구사항을 충족하는 코드 편집기를 만들 것을 고려했지만, 코드 편집기 개발의 복잡성, 풍부한 오픈소스 옵션, 그리고 우리 팀의 규모를 고려할 때 이는 예측 불가능한 도전이 될 것 같아서, 우리만의 편집기를 구축하는 데 시간을 할애하지 않기로 했습니다. 저는 운 좋게(그리고 고통스럽게도) Ace, Monaco, CodeMirror 이 세 가지 코드 편집기를 프로덕션 환경에서 사용해본 경험이 있는데, 때로는 동시에 사용하기도 했습니다(자세한 내용은 후술하겠습니다). 이 글에서는 Replit의 역사와 제가 편집기를 사용한 경험, 그리고 이 둘이 어떻게 상호작용했는지 돌아보려 합니다.
이 글을 읽는 목적이 세 코드 편집器的 직접적인 비교라면, 마지막 부분으로 바로 이동해 주세요. 요약과 비교는 그곳에 정리해 두었습니다.
이야기
서곡: Ace
Replit 초기, 약 2011년에는 코드 편집기가 없었습니다. 우리는 단순한 입력창이 있는 콘솔, 순수한 REPL 인터페이스를 사용했습니다. 더 복잡한 프로그램을 만들려면 코드 편집기를 추가하는 것이 시급한 과제였죠. 코드 편집기는 구문 강조, 편집기 단축키, 자동 들여쓰기, 검색 및 교체 등의 기능을 제공했습니다. 당시 Cloud9에서 출시한 Ace는 기능이 풍부하고 성능이 뛰어난 웹 기반 코드 편집기였습니다. 현재까지도 Ace 편집기는 활발히 유지보수되고 있으며, 다국어 지원, 키 바인딩, 브라우저에서의 원활한 실행 등을 지원하는 풍부한 생태계를 자랑합니다.
👇🏻 원래의 Replit 인터페이스와 Ace 코드 편집기 비교. 이 스크린샷은 2011년부터 Replit의 오픈소스 버전을 재호스팅해온 우리 커뮤니티 멤버가 제공했습니다 https://www.repldotit.com.

우리는 2017년경까지 Ace를 사용하다가 Monaco로 전환했습니다. Ace는 여전히 유지보수되고 있지만, 유지보수 담당자는 단 한 명뿐입니다. 아마존이 Cloud9을 인수한 후, 오픈소스 프로젝트의 우선순위를 재조정한 것으로 보입니다. 에디터는 이전처럼 자주 업데이트되지 않았고, Github의 이슈는 쌓이기 시작했으며, 유지보수 담당자도 거의 새로운 기능을 추가하지 않았습니다. 전반적으로 Ace의 API는 개발자들에게 구식이고 투박하게 느껴지기 시작했습니다. 유지보수 담당자는 훌륭하지만, 그가 할 수 있는 것에도 한계가 있었습니다.
인터루드: Monaco
아마도 이미 알고 계시겠지만, VSCode는 Monaco 에디터를 사용합니다. 사실, 마이크로소프트는 Monaco를 기반으로 VSCode를 구축했습니다. 우리가 코드 에디터를 Monaco로 전환한다면, VSCode의 개발 대가들로부터 모든 멋진 업데이트와 기능을 얻을 수 있을 거라 생각했습니다. Monaco는 우리 웹사이트와 잘 어울리는 현대적인 사용자 인터페이스를 제공하며, JavaScript, HTML, CSS에 대한 훌륭한 자동 완성 기능을 가지고 있습니다. 또한 LSP(Language-Server-Protocol)에 대한 언어 클라이언트를 쉽게 작성할 수 있는 API도 있는 것 같습니다. 그들의 API 문서는 훌륭하며, Typescript 정의가 포함되어 있어 개발 관점에서 더 많은 확장 기능을 제공합니다.
👇🏻Monaco 에디터 스크린샷(기본 설정), 깔끔하고 정돈된 UI를 확인하세요.

Ace에서 Monaco로 전환하는 데는 대가가 따릅니다. 후자는 Ace의 많은 기능이 부족하지만, 우리는 커뮤니티의 열기와 기여로 인해 곧 Ace를 능가할 것이라고 믿습니다. (Ace에 비해) Monaco의 첫 번째 문제는 많은 언어 지원이 부족하다는 점입니다. VSCode에는 많은 언어 지원이 있지만, 이는 브라우저가 아닌 NodeJS/Electron의 능력에 의존합니다. 따라서 우리는 Monaco가 더 많은 언어를 지원할 수 있도록 코드 기여를 시작했습니다. Scala, Julia, Scheme, Clojure 등 다양한 언어 지원과 Python 같은 언어의 버그 수정을 추가했습니다. 나는 Monaco용 문법 강조 표시기를 작성하여 어댑터를 통해 Ace가 지원하는 모든 언어를 지원할 수 있도록 했습니다. 마지막으로, Monaco가 Ace에 비해 부족한 기능은 Vim과 Emacs의 키 바인딩이지만, 곧 누군가가 NPM에서 이러한 기능을 지원하는 패키지를 릴리스할 것입니다.
Monaco의 또 다른 문제는 빌드 도구입니다. Microsoft가 웹 기술로 Monaco를 구축했지만, 현재의 웹 생태계 및 빌드 도구와 잘 통합되지 않습니다. Monaco를 Webpack Dll로 사전 컴파일하고 많은 Webpack 구성을 추가해야만 정상적으로 작동했습니다. 이러한 추가 작업은 고통스러웠고, 우리의 빌드 시스템 복잡성과 비용을 증가시켰습니다. 몇 달 후, Microsoft는 Monaco용 Webpack 플러그인을 발표했는데, 이는 약간의 개선을 가져왔지만 완벽하지 않았습니다. 특히 우리가 프론트엔드를 Next.js로 옮겼을 때 더욱 그랬습니다. 안타깝게도 Monaco는 코드를 지연 로드하고 분할하는 간단한 방법도 없어서, 코드를 작은 파일로 분할하여 로드 속도를 높이는 것은 불가능했습니다. 이 문제로 인해 우리 프로젝트의 크기가 최대 5M까지 증가했는데, 이는 쉽게 무시할 수 있는 문제가 아닙니다.
Monaco는 모바일에서도 잘 작동하지 않습니다. 우리는 이 부분을 아웃소싱하려고 시도했지만, 아무도 수주하지 않았습니다. 그래서 제가 직접 처리하려고 했을 때, Monaco 코드베이스를 살펴보고 읽기가 매우 어렵다는 것을 깨달았습니다. Monaco 에디터 자체가 VSCode를 먼저 구축한 후 분리된 것처럼, VSCode 코드베이스의 다른 부분과 너무 많이 결합되어 있습니다. VSCode 자체도 코드가 잘 작성되지 않았을 뿐만 아니라, 가장 오래된 Typescript 프로젝트 중 하나일 수 있으며 Microsoft의 대기업 스타일로 작성되었습니다. 우리는 모바일에서 꽤 쓸만한 것을 만들었지만, VSCode에 대한 우리의 수정 사항이 VSCode의 메인 브랜치에 병합되지 않을 것이며, 현재의 모바일 버전은 프로덕션 환경에서 사용할 수 있을 때까지 아직 멀었기 때문에 VSCode 포크를 유지하고 싶지 않았습니다. 따라서 저는 휴대폰에서 계속 Ace 에디터를 사용하는 것이 최선의 해결책이라고 결정했습니다. 완벽하지는 않지만, 괜찮습니다(사용할 수는 있습니다).
따라서 우리는 Replit에서 최종적으로 두 개의 코드 편집기를 갖게 되었습니다: 하나는 PC용이고 다른 하나는 모바일용입니다. PC용의 모든 새로운 기능은 Ace(모바일 버전)로 이식되어야 했습니다. 우리는 Ace를 위해 LSP 기능을 지원하는 언어 클라이언트를 작성해야 했고, 여러 사용자가 동시에 편집할 수 있도록 Ace용 작업 변환 어댑터(역자 주: OT 변환?)도 작성해야 했습니다. 많은 경우에 우리는 기능을 이식할 시간조차 없었습니다. 예를 들어, 우리는 코드 멀티스레딩 기능을 모바일로 이식하지 못했습니다.
뒷이야기: CodeMirror
2018년 말, Marijn은 CodeMirror를 https://web.archive.org/web/20180830201622/https://codemirror.net/6/로 재작성하여 버전 6으로 업데이트할 것을 발표했고, 훌륭한 설계 문서를 함께 공개했습니다. 재작성의 주요 동기 중 하나는 터치 디바이스 지원을 추가하는 것이었습니다. 이 시기에 우리는 모바일(일반적인 의미에서)이 우리 전략의 중요한 부분이라는 것을 깨달았습니다; 다음 10억 명의 소프트웨어 창작자들이 온라인에서 작업할 수 있도록 하려면 모바일에서도 사용 가능해야 했습니다. CodeMirror는 JavaScript/라이브러리 레벨에서 완전히 구현하는 대신(Google Docs의 Google Closure처럼) contenteditable을 통해 네이티브 브라우저의 텍스트 편집 기능을 활용함으로써 모바일 사용성을 실현할 계획이었습니다.
ProseMirror는 CodeMirror 6의 API 디자인에 영감을 주었으며, Marijn의 또 다른 프로젝트입니다. 저는 당시 개발 중이던 WYSIWYG 프로젝트에서 이를 사용해 본 적이 있고 매우 마음에 들었습니다. ProseMirror는 매우 작은 코어를 가지고 있으며, 다른 모든 기능은 플러그인 시스템을 통해 구현됩니다. 편집기 라이브러리로서 모듈화되고, 플러그인 가능하며, 기능적이며, 믿을 수 없을 정도로 권한을 부여받은 느낌을 줍니다. 그래서 저는 회사가 새 버전의 CodeMirror 개발을 후원하도록 결정했고, 심지어 직접 프로젝트에 자금을 지원하기도 했습니다.
작년에 CodeMirror 6의 베타 버전이 출시되었을 때, 저와 팀원들은 매우 흥분되어 Replit에 추가하기 시작했습니다. 우리는 편집기를 사용해 보기 시작했고, 학습 곡선이 다소 가파르긴 하지만 결국 "이해"하게 되면 슈퍼-코드-편집기-개발자가 된 기분이 들었습니다. CodeMirror 6를 프로젝트에 적용하기 위해, 저는 점진적으로 프로젝트에 통합하기 시작했습니다. 먼저 Replit에서 읽기 전용 편집기로 추가한 다음, 웹사이트의 다른 코드 편집 가능한 부분들에 추가하기 시작했습니다.
올해 초, 우리는 ‘믿음의 도약’(역자 주: 어쌔신 크리드에서 유래한 표현)을 시작하며 CodeMirror를 모바일 환경에 통합하기 시작했습니다. 사용자 관점에서 보면 CodeMirror는 객관적으로 모바일에서 사용 가능한 다른 어떤 에디터보다 우수합니다. 아직 우리가 지원하는 모든 언어와 일부 기능을 완전히 지원하지는 않지만, 모바일 통합은 그만한 가치가 있었습니다. 이 통합 이후의 사용자 피드백은 우리 예상을 훨씬 뛰어넘었습니다. CodeMirror를 사용한 사용자 중(역자 주: 소규모 테스트 또는 신/구버전 전환 기능을 통해 에디터 사용 통계를 수집한 것으로 추정) 모바일 사용자 비율이 약 70%에 달했습니다! CodeMirror는 모바일에서 Ace를 사용할 때보다 사용자 유지율이 더 높았습니다. CodeMirror의 플러그 가능성(제공하는 무한한 가능성)을 고려할 때, 이렇게 고무적인 결과는 모바일에서 더 많은 가치를 제공하기 위한 시작에 불과하다는 것이 분명해졌습니다. 우리는 먼저 PC 버전에서 제공되지만 모바일에는 없는 기능들을 모바일 CodeMirror로 이식하는 작업부터 시작할 것입니다.

CodeMirror 6의 커뮤니티는 아직 초기 단계에 있기 때문에, 우리는 많은 부분을 직접 구현하거나 특정 기능을 위해 후원금을 지불하고 Marijn과 함께 버그를 해결해야 했습니다. 우리는 우리의 기여가 CodeMirror 커뮤니티를 이끌고 보답하는 데 도움이 되기를 바랍니다. 여기서 우리가 적극적으로 개발 중인 기능 목록을 소개하겠습니다: Vim 모드, Emacs 모드, LSP 클라이언트, 들여쓰기 표시, CSS 색상 선택기, 언어 파서, 그리고 앞으로 데스크톱 버전의 CodeMirror를 출시할 때 게시물에서 발표할 많은 다른 기능들입니다. 저는 사람들이 새로운 CodeMirror에 대해 흥분하고 있으며, 앞으로 1~2년 안에 커뮤니티와 생태계 사용자 수가 급증할 것이라고 생각합니다. 많은 사람들이 프로덕션 환경에서 사용하기를 간절히 원하고 있습니다.
우리는 CodeMirror에 점점 더 많은 기능을 구축하고, 코드 접근성을 높이는 과정에서 필수적인 부분으로 만들 수 있어 매우 기쁩니다. 우리는 항상 사용자 경험을 우리가 원하는 방식으로 구축하기 위해 결국에는 자신만의 에디터를 개발해야 한다고 말해왔습니다. 그럼에도 불구하고, 우리는 CodeMirror로 할 수 있는 일에 대해 매우 만족하고 있습니다.
Battle 섹션
여러분이 적합한 코드 에디터를 찾는 데 도움이 되도록 요약해 보겠습니다. 다시 말하지만, 이는 제 개인적인 경험일 뿐이며 여러분의 경험과 다를 수 있습니다.
각 섹션에서 저는 에디터에 1점에서 3점까지 점수를 매길 것입니다. 3점이 가장 높은 점수입니다.
안정성
| 에디터 | 점수 | 설명 |
|---|
| Ace | ⭐️⭐️⭐️ | 매우 안정적이고 신뢰할 수 있습니다. 이 편집기는 역사적 검증을 거쳤으며, 10년 이상 다양한 도구를 지원해 왔습니다. 제가 사용한 모든 기간 동안 단 한 번도 break change를 경험한 적이 없습니다. 일부 버전에서 작은 버그가 도입되기도 했지만, 빠르게 수정되었습니다. |
| Monaco | ⭐️⭐️ | Monaco는 안정적인 편집 경험을 제공합니다; 물론 몇 가지 버그도 있지만, VSCode의 릴리스와 함께 빠르게 수정되며, 유지 관리자들은 지속적으로 새로운 버전을 출시하는 데 능숙합니다. 1점을 깎은 이유는 API가 가장 안정적이지 않고 자주 작은 변화가 있어 성가시기 때문입니다. Microsoft는 아직 Monaco의 1.0 버전을 출시하지 않았습니다. |
| CodeMirror 6 | ⭐️ | CodeMirror는 아직 베타 단계에 있으며, 이 프로젝트에는 많은 사소한 버그가 있습니다. 하지만 Marijn은 빠르게 대응하고 수정합니다. 비록 프로젝트가 여전히 베타 단계이지만, Marijn이 현재의 API에 만족하고 있어 큰 break change는 없을 것이라고 생각합니다. CodeMirror 6는 이미 많은 기능에 채택되기 시작했으며, Chrome의 개발자 도구도 내년부터 코드 편집기로 사용할 계획일 수 있습니다. |
즉시 사용 가능한 경험
| 에디터 | 평점 | 설명 |
|---|---|---|
| Ace | ⭐️⭐️ | 뛰어난 즉시 사용 경험을 제공하며, 많은 기능과 언어를 지원합니다. 기본적인 JavaScript Lint 기능(JSHint 사용)과 자동 완성 기능도 포함되어 있습니다. 다만 사용자 인터페이스가 약간 구식이라 때로는 다소 혼란스러울 수 있습니다. |
| Monaco | ⭐️⭐️⭐️ | 매우 정교한 사용자 인터페이스를 가지고 있습니다. 이 에디터는 HTML, CSS, JavaScript에 대한 코드 힌트 지원을 기본적으로 제공하는 등 많은 기능이 내장되어 있습니다. |
| CodeMirror 6 | ⭐️⭐️ | 에디터가 정상적으로 작동하려면 약간의 설정이 필요합니다. 이는 프로젝트의 모듈화 특성과의 균형을 맞추는 과정입니다. basic-setup 패키지가 있으며, 이는 여러 모듈을 결합하고 코어 모듈을 다시 내보냅니다. 사용자 인터페이스는 훌륭합니다. |
모듈화, 빌드 도구 및 발전 궤적
| 에디터 | 평점 | 설명 |
|---|---|---|
| Ace | ⭐️⭐️ | Ace 자체는 매우 작고 모듈화도 지원합니다. 다른 모듈을 지연 로딩(lazy loading)으로 로드할 수 있습니다. 그러나 Ace는 비교적 오래된 프로젝트이며 자체 모듈 관리 시스템을 갖추고 있어 프로그램에서 작동시키려면 약간의 설정이 필요합니다. |
| Monaco | ⭐️ | Monaco 에디터는 번들 크기가 매우 큽니다. 약 5MB 정도입니다. 또한 제가 아는 한, 지연 로딩은 불가능합니다. Monaco는 빌드 시스템에 몇 가지 특별한 설정이 필요하며, 이는 기존 시스템과 통합하기 어렵게 만듭니다. |
| CodeMirror 6 | ⭐️⭐️ | CodeMirror는 현대적인 기술로 구축되었습니다. 번들러를 사용하지 않고도 ES6 모듈로 가져올 수 있습니다. 지연 로딩 기능은 매우 간단합니다. ES6의 동적 임포트 기능만 있으면 됩니다. 이 프로젝트는 매우 모듈화되어 있으며 에디터 코어는 매우 작습니다. |
확장성 및 고급 기능
| 에디터 | 점수 | 설명 |
| Ace | ⭐️⭐️ | Ace는 많은 구성 옵션을 제공하며 효과적이고 확장 포인트도 훌륭합니다. 비록 매우 범용적이지는 않지만, 많은 고급 기능을 구현할 수 있게 해줍니다. API는 약간 구식으로 느껴지지만 확실히 안정적입니다. 프로젝트를 빠르게 실험해 볼 필요가 있을 때, Ace를 쉽게 선택하는 이유는 코드가 읽기 쉽고 핵심 코드가 거의 10년 동안 변경되지 않았기 때문입니다. |
| Monaco | ⭐️⭐️ | Monaco는 다양한 구성 옵션을 제공하며 편집기의 동작과 기본 기능을 수정할 수 있는 API를 제공합니다. 그럼에도 불구하고 확장 가능한 부분은 제한적이고 지나치게 구체적입니다. 종종 편집기와 머리를 맞대고 해킹 패치를 적용해야 하는데, 이는 매우 위험하고 수렴하기 어려운 작업입니다. 코드베이스가 쉽게 읽히지 않고 내부 코드가 지속적으로 변경되기 때문입니다. 결국, 우리는 Monaco 업그레이드를 중단했는데, 앞으로도 우리가 필요로 하는 일부 기능을 지원할 가능성이 없기 때문입니다. |
| CodeMirror 6 | ⭐️⭐️⭐️ | CodeMirror 6는 처음부터 확장성을 염두에 두고 설계되었으며, 이는 주요 설계 원칙 중 하나입니다. 이러한 확장성 덕분에 CodeMirror는 모듈화가 가능합니다. 실제로 코어 자체(@codemirror/view 및 @codemirror/state)는 본질적으로 확장 가능한 textarea입니다. 모든 ‘코드’ 기능은 확장으로 구현됩니다. 구문 강조 및 줄 번호와 같은 기본 요소도 확장 및 패키지로 구현됩니다. 자신만의 확장을 만들 때 이러한 공식 패키지는 훌륭한 예시 자료가 됩니다. CodeMirror를 사용하여 화려한 플러그인을 구축하는 것은 식은 죽 먹기이며, 플러그인 개발자로서 믿기 힘들 정도로 강력한 지원을 제공합니다! 확장 포인트는 매우 유연하므로, 여러분은 프로그램 세계의 신이 되어 원하는 모든 기능을 자유롭게 구현하고 그 결과를 책임질 수 있습니다. |
커뮤니티와 문서
| 에디터 | 평점 | 설명 |
|---|---|---|
| Ace | ⭐️⭐️ | 수년 동안 Ace는 풍부한 생태계와 Ace 사용에 관한 수많은 글과 블로그를 축적해왔습니다. 모든 언어의 하이라이트 기능을 지원하며 커뮤니티에서 제공하는 다양한 툴킷을 보유하고 있습니다. API 문서가 가장 뛰어나지는 않지만 대부분의 사용 시나리오에는 충분합니다. 구조화된(약간 오래된) 코드베이스는 훌륭한 (문서) 보완 자료입니다. 온라인에는 입문 가이드도 있습니다. |
| Monaco | ⭐️⭐️ | Monaco은 2018년경부터 본격적으로 발전하기 시작했지만, 커뮤니티가 빠르게 쇠퇴하는 것을 느낄 수 있습니다. NPM에서 커뮤니티에서 유지 관리하는 다양한 패키지를 찾을 수 있습니다. Monaco의 API 문서 자체는 이미 꽤 좋은 수준이지만, 공식 가이드가 없어 초보자들이 시작하기 어렵게 느낄 수 있습니다. 프로젝트 구조가 복잡하기 때문에 코드를 읽는 것이 API 문서를 보완하는 자료로 사용하기 어렵습니다. |
| CodeMirror 6 | ⭐️⭐️⭐️ | CodeMirror 6에 대한 개발 동력이 커뮤니티에서 많이 느껴집니다. 우리는 CodeMirror 6에 꼭 필요하다고 생각하는 몇 가지 패키지로 커뮤니티 발전을 돕기 위해 노력하고 있으니 기대해주세요! 문서는 훌륭하며 시간이 지남에 따라 더 나아질 것이라 기대합니다. 문서 시스템에는 훌륭한 입문 글과 많은 예제가 있으며 상세한 설명이 함께 제공됩니다. 위에서 확장성에 대해 언급했듯이, 대부분의 기능은 확장을 통해 구현되며, 이러한 기능 패키지는 원하는 기능을 구현할 때 '최고의 동료’가 될 것입니다. |
성능
면책 조항: 성능 평가에는 명확한 벤치마크 데이터가 없습니다.
| 에디터 | 평점 | 설명 |
|---|---|---|
| Ace | ⭐️⭐️⭐️ | Ace는 브라우저와 머신이 지금만큼 강력하지 않았던 시절에 태어났기 때문에, 현재의 성능은 매우 인상적입니다. |
| Monaco | ⭐️⭐️ | Monaco에는 많은 성능 최적화가 있지만 다소 무거울 수 있습니다. Replit에는 저전력 머신을 사용하는 많은 사용자가 있으며, 그들은 Monaco가 전력을 많이 소모한다고 느끼고 있습니다. |
| CodeMirror 6 | ⭐️⭐️⭐️ | CodeMirror는 지금까지 성능이 우수한데, 이는 작성자가 많은 시간을 성능 최적화에 투자했기 때문입니다. |
모바일 지원
여기서는 평점을 매기지 않겠습니다. 모바일을 지원하는 코드 에디터를 원한다면 사용 가능한 유일한 선택지는 CodeMirror 6입니다. Ace의 모바일 지원이 나쁘지는 않지만 프로덕션 환경에서 사용하기에는 적합하지 않으며, Monaco는 모바일에서 사용할 수 없습니다.
나는 CodeMirror가 Webview 컴포넌트를 사용하는 네이티브 애플리케이션에서도 적용될 수 있다고 말할 수 있습니다. CodeMirror의 대부분 내용은 직렬화 가능하므로, 네이티브 코드에서 Webview와 상호작용할 수 있습니다.
감사합니다!
이 부분은 저자의 광고 시간으로, 일단 번역하지 않겠습니다.
저는 인생의 중요한 선택의 기로에 섰을 때, 누군가 최선의 방법을 알려주어 소중한 시간을 헛되이 보내지 않기를 바라곤 합니다. 그런 마음으로 저는 자주 블로그를 쓰며, 광활한 인터넷의 이 작은 구석에 제게는 단 한 번뿐인 인생 경험을 기록하여 도움이 필요한 분들에게 도움이 되기를 바랍니다.