기술 블로그

[개발 스토리] lexical.js — Make KaraokeNode!

daglo 팀 · 2022년 9월 2일

[개발 스토리] lexical.js — Make KaraokeNode!

# What is Lexical?

안녕하세요👋 액션파워 플랫폼그룹 프론트엔드 개발팀입니다. 저희 프론트엔드 개발팀에서는 다글로 서비스를 개발하고 있는데요. 다글로는 인공지능 STT 기술을 이용해 사용자가 요청한 음성을 받아쓰기하고, 받아쓰기한 내용을 조회 및 편집할 수 있는 편집기를 제공하고 있습니다.

Quill로 작성된 다글로 편집기

현재 다글로는 Quill 기반으로 제작했는데요. 오랜 시간 동안 유지 관리하며 비대해진 코드 베이스로 인해 유지 보수가 힘들어졌고, 오랜 고민과 토론 끝에 리뉴얼을 앞두고 있습니다.

다글로는 리액트 기반으로 제작된 웹 애플리케이션입니다. 그래서 차기에 선정될 편집기는 리액트 친화적이고, 유지 보수하기 쉬운 구조의 라이브러리를 사용할 수 있기를 원했습니다. 여러 편집기 라이브러리를 살펴보던 중 Meta (구 Facebook) 에서 공개한 Lexical 이라는 라이브러리를 알게 되었습니다.

Lexical은 버전 ‘0.3.11’ 의 초기 단계의 라이브러리이지만, Meta에서 draft.js를 대체하는 강력한 기능과 성능을 가진 라이브러리로 나아가고자 활발히 개발 중에 있습니다.

오늘 이 글에서는 Lexical을 이용해 다글로에서 제공하는 노래방 기능을 만드는 방법을 소개합니다. 노래방 기능이란, 음성ㆍ영상 재생 시 다글로가 받아 쓰기한 내용을 음절에 맞게 색이 변하는 기능을 말합니다. 마치 노래방에서 가사를 띄워주는 것과 비슷해서, 이 글에서는 편의상 ‘노래방 기능’ 이라고 부르도록 하겠습니다.

initilize Lexical Playground

lexical/packages/lexical-playground at main · facebook/lexical Lexical is an extensible text editor framework that provides excellent reliability, accessibility and performance. … github.com

  • lexical의 repo를 clone 합니다.
  • lexical의 playground 예제는 https://github.com/facebook/lexical/tree/main/packages/lexical-playground 에 있습니다.
  • /packages/lexical-playground 경로에서 yarn install 을 합니다.
  • 사용하시는 컴퓨터가 M1 인 경우 The chromium binary is not available for arm64. 이라는 메시지를 맞이하게 됩니다. 그 경우는 아래의 링크를 참조해서 chromium을 설치해주시면 됩니다.
  • TL;DR;
    brew install chromium
    Go to your System Preferences > Security & Privacy > General screen, and select Open Anyway.

How to fix M1 Mac Puppeteer chromium arm64 bug I recently got the M1 Mac mini computer, and ran yarn or npm to install a project that contained Puppeteer in the… linguinecode.com

  • 이후 yarn install을 다시 해서 yarn dev 까지 실행하면 Lexical Playground 를 실행시킬 수 있습니다.

Overview

Lexical Playground의 폴더 구조부터 살펴봅시다.

여기서 주목해야 할 것은 nodes 폴더와 plugins 입니다.

  • nodes : 편집기를 구성하는 가장 작은 요소라고 생각하시면 됩니다. 노션의 ‘블록' 과 같은 역할이라고 볼 수 있습니다. 
    ▶ 예: 이모지, 멘션, 이미지, 투표 등
    /src/nodes/PlaygroundNodes.ts 에 커스터마이징 한 노드를 등록할 수 있습니다. 
    ▶ TextNode, DecoratorNode, DecoratorBlockNode 등의 종류가 있습니다. 
     ▷ TextNode: display: inline 속성을 가진 노드
     ▷DecoratorBlockNode: display: block 속성을 가진 노드
     ▷DecoratorNode: 이외의 display 속성을 가진 노드. Playground를 보니 조건에 따라 엘리먼트가 변경될 수 있는 노드들이 포함되는 듯 합니다.
  • plugins : 등록된 노드들을 이용해 편집기에 적용가능하도록 플러그인을 만들 수 있습니다.
    ▶ lexical에서 단일 책임 원칙에 의거해 캡슐화하여 코드 관리를 하도록 유도했음을 알 수 있습니다.
    ▶ 아래에 리액트 기반 플러그인 목록을 볼 수 있습니다.

Lexical Plugins | Lexical React-based plugins are using Lexical editor instance from context: React wrapper for @lexical/plain-text that adds… lexicaljs.com

Create Custom Karaoke Node

노드 설계

이제 노래방 노드를 만들어보도록 합시다. 노래방 기능은 다글로에서 많이들 보셨죠? 노래방 기능을 구현하기에 앞서 노드 설계에 대해서 먼저 말씀드리려고 합니다.

먼저 daglo.ai 에서 기존 노래방 기능 구성을 그대로 차용해오고자 합니다. 다글로 편집기 페이지에서 노래방 노드가 어떻게 구성되어있는지 살펴봅시다.

span 태그 내에 t 라는 애트리뷰트에 값을 전달하죠? 또한 해당 노드는 paragraph 노드가 감싸고 있습니다.

또한 API 요청을 보시죠.

// data/sample.json
{
"googleResult": [
{
"results": [
{
"alternatives": [
{
"confidence": 0,
"transcript": "안녕하세요. 인공지능 음성인식 받아쓰기 서비스 다글로 입니다. 언젠가 다시 들을 거라 생각하고 녹음한 음성파일이 그대로 쌓여 있기만 하진 않으세요? 아마 내용을 다시 확인 하려면 시간도 오래 걸리고 불편하기 때문일 겁니다. 다글로는 음성파일을 자동으로 택스트로 변환해주는 인공지능 서비스입니다. 텍스트로 쉽고 빠르게 내용을 확인할 수 있고 검색이 가능하며 변환된 텍스트를 클릭하면 즉시 해당 부분이 재생 됩니다. 편집기에서는 잘못된 부분을 쉽게 수정할 수 있고 한글뿐 아니라 영어 일본어 중국어 등 외국어도 지원해 드리고 있습니다. 다글로는 높은 정확도를 제공해드리기 위해 최신 딥러닝 기술을 사용해 분야별로 특화된 자체 음성인식 엔진을 제공해드리고 있으며 적용 분야를 점차 확대해 나갈 계획입니다. 더욱 높은 정확도를 위해서는 마이크와 녹음기 간격을 10 ㎝ 이내로 가깝게 유지하여 녹음해야 한다는 점을 꼭 기억해 주시기 바랍니다. 다글로는 고객 여러분의 삶과 업무에 보다 나은 효율과 편리함을 드리고 싶습니다. 끊임없이 발전하는 다글로를 기대해주세요. 감사합니다. ",
"words": [
{
"endTime": {
"nanos": 549999999,
"seconds": "2"
},
"word": "안녕하세요."
},
...
]
}
]
}
]
}
],
"lastEdited": "2019-04-09T09:18:48.334Z",
"wordProcessed": true
}

위 데이터는 이 Hands-on에서의 예를 들기 위해 Google Speech API를 통한 STT 결과물을 이용한 샘플 데이터입니다. 저희는 data.googleResult.results[0].alternatives[0].words 를 이용해서 각 노드를 구성할 예정입니다.

커스텀 노드 만들기

자, 그러면 커스텀 노드를 어떻게 만들까요? Lexcial에서는 이모지 변환 플러그인 구현을 예제로 제시하고 있습니다. 그러나 해당 내용은 업데이트가 되지 않아서 현재 버젼 (0.3.11) 과는 맞지 않는 부분들이 있습니다.

lexical/emoticons.md at main · facebook/lexical In this example, we'll implement a feature that detects conventional textual representations of Emoticons and converts… github.com

편집기에서 노래방 노드가 동작하게 하기 위해서는 커스텀 노드를 제작해야 합니다. 노래방 노드는 위에서 말씀드렸듯이 TextNode, DecoratorNode, DecoratorBlockNode 등의 노드가 있습니다. (lexical playground 기준입니다.)

노래방 노드를 구현하기 위해서는 TextNode를 사용합니다.

코드 예시 보기 (외부 링크)

커스텀 노드를 구성하기 위해서는 KaraokeNode 클래스에서 몇가지 함수를 오버라이딩 해야합니다. 오버라이딩 해야 하는 함수는 아래와 같습니다.

  • getType: 노드의 타입명을 지정합니다.
  • clone: 복제
  • createDOM: 노드 생성 시 해당 노드의 어트리뷰트 설정 및 렌더링 방식을 제어할 수 있습니다.
  • updateDOM: 노드 변경 시 해당 엘리먼트의 어트리뷰트 설정 및 렌더링 방식을 수정할 수 있습니다.
  • importJSON: JSON 파일을 import 시 노드를 어떻게 매칭시킬지를 설정합니다.
  • exportJSON: JSON 파일로 export 시 노드를 어떻게 export 할 지 설정합니다.

또한 클래스 바깥에 선언해야 하는 함수가 있습니다.

$create[custom-name]Node$is[custom-name]Node 입니다. 여기서는 $createKaraokeNode, $isKaraokeNode 가 되겠죠.

코드를 작성해봅시다.

플러그인 만들기

API 로더 플러그인 만들기

Lexical의 플러그인 시스템을 이용하여 로직을 캡슐화할 수 있습니다. 플러그인은 리액트 컴포넌트로 구성됩니다. 우선 편집기를 이용하기 위해선 받아쓰기한 값을 가져오는 게 필요하겠죠? 아래와 같이 코드를 작성합니다.

코드에서는 useQuery를 사용했습니다. 이곳에서 살펴볼 내용은 onSuccess 내의 editor.update 함수입니다. update 함수에서는 등록된 노드들을 이용해 DOM 업데이트를 다룹니다.

플러그인 연결

ApiLoadPlugin을 완성했으니, 플러그인을 적용해봅시다. 플러그인은 src/Editor.tsx 에 위치시킵니다.

노래방 플러그인 만들기

Lexical의 플러그인 시스템을 이용하여 노래방 기능을 설정하는 것과 관련된 모든 로직을 캡슐화할 수 있습니다. 플러그인은 리액트 컴포넌트로 구성됩니다.

모든 플러그인의 기본은 useLexicalComposerContext 으로 인스턴스를 가져오는 것부터 시작합니다.

이후 LexicalComposer 에 노드를 등록 후, Lexical에서 어떻게 노드를 핸들링하는지 봅시다.

노드에 값이 잘 반영되었음을 알 수 있습니다. 위 코드에서는 useEffect 훅 내에서 registerNodeTransform 함수를 이용해서 편집기 내에 있는 KaraokeNode를 콜백 함수로 받아 변환하는 역할을 합니다.

자, 이제 코드를 작성해봅시다.

start, pause, reset 버튼을 추가해 노래방 기능을 구현해봅니다. 해당 내용은 lexcial의 특화 기능이라기보다는, 일반적인 기능 구현이기에 어렵지 않으실 겁니다.

KaraokePlugin을 완성했으니, 이 역시도 src/Editor.tsx 에 위치시켜줍니다.

최종 실행

잘 동작하는 것을 확인하실 수 있습니다. 이렇게 오늘은 Lexical을 이용한 노래방 기능 구현을 알아보았습니다. 편집기 라이브러리 선정에 고민하고 계신 모든 분들, 그리고 Lexical 에디터를 사용하시는 모든 분들께 이 글이 조금이나마 도움이 되었길 바랍니다. 🙂

액션파워 채용 사이트

우리 함께 꿈을 현실로 이뤄볼까요?

액션파워에는 다양한 인재들이 모여 끊임없이 도전하고 스스로의 역량을 확장해 나가고 있습니다. 함께 꿈 같은 기술과 서비스를 만들 동료가 되어주세요! 자세한 내용은 채용 사이트에서 확인해보세요.

액션파워에 대한 더 많은 이야기가 궁금하다면?
More about Action Power

← 블로그로 돌아가기

대화가 일이 되는 곳, daglo.

지금 바로 무료로 시작해보세요