
Rich Editor Note: 노션 에디터 유사 메모 앱
📅기간🎯종류
2025-04 ~ 2025-07
🔗GitHub⚡기술React NativeSQLiteSupabaseReact개인
개인
소개
노션과 같은 온/오프 환경에서 사용 가능한 메모앱이며, 기본 노트앱과 다르게 Rich Text Editor를 제공합니다.
두 프로젝트를 포함한 모노레포입니다.
app-bible-note: React Native 모바일 앱 (iOS/Android)
web-bible-note: React + Vite 기반 웹 에디터
핵심은 “웹 기반 리치 텍스트 에디터”를 모바일 앱의 WebView로 안정적으로 구동하기 위한 기술 설계입니다.
또한 노션과 같이 오프라인 환경에서도 메모장을 활용할 수 있도록, 정적 서버를 실행시키도록 만들었습니다.
프로젝트 구조
app-bible-note/모바일 앱 소스
web-bible-note/웹 에디터 소스
editor.zip에디터 정적 자원 예시(루트에 위치, 배포/테스트용)
아키텍처 개요
- 웹 에디터(web-bible-note)
- React + TipTap(프로즈미러 기반) + Vite
- 커스텀 노드/입력 규칙으로 성경 구절 블록을 생성Supabase를 통한 노트 저장
- 모바일 앱(app-bible-note)
- React Native 0.79 + Hermes. WebView로 에디터를 로드
- 원격
editor.zip을 내려 받아 기기 내에 압축 해제한 뒤 로컬 정적 서버로 서빙 - 네트워크 상황과 플랫폼 제약에도 일관된 UX 제공
웹 에디터 구현
에디터 코어
- 파일:
web-bible-note/src/features/editor/useMyEditor.ts
- 핵심 포인트:
- TipTap
useEditor기반.StarterKit에 heading 레벨 제한,Placeholder,Focus적용. - 커스텀
CustomBackspaceExtension - 빈 블록에서의 백스페이스 동작을 제어해 heading/리스트/커스텀 노드에서 자연스럽게 단락으로 전환하거나 리스트 리프팅을 수행.
onUpdate에서 디바운스 자동 저장(1초).- 저장은
updateNote(noteId, title, content)로 Supabase에 반영.
const editor = useEditor({ extensions: [ StarterKit.configure({ heading: { levels: [1, 2, 3] } }), BibleVerse, BibleVerseInput, CustomBackspaceExtension, Focus.configure({ className: "has-focus", mode: "all" }), Placeholder.configure({ /* 노드 타입별 placeholder */ }), ], content: initialContent || "<p>@ 명령어를 입력하고 성경 구절을 작성해보세요.</p>", onUpdate: ({ editor }) => { if (editor) debouncedSave(editor.getJSON()); }, immediatelyRender: false, });
성경 구절 기능(커스텀 노드 2종)
- 입력 노드:
BibleVerseInput(@입력 규칙으로 생성) - 파일:
web-bible-note/src/features/editor/extensions/bible-verse/BibleVerseInput.ts @입력 시 블록 삽입 → 엔터 시 현재 입력 텍스트를 구절 레퍼런스로 파싱,fetchBibleVerse(reference)로 컨텐츠를 비동기 조회 → 현재 입력 블록을bibleVerse노드로 치환하고, 필요시 뒤에 단락 자동 생성 및 커서 이동.
addInputRules() { return [ new InputRule({ find: /@ $/, handler: ({ chain, range }) => { chain().deleteRange(range).insertContent({ type: "bibleVerseInput" }).run(); }, }), ]; },
- 표시 노드:
BibleVerse - 파일:
web-bible-note/src/features/editor/extensions/bible-verse/BibleVerse.ts NodeView로 React 컴포넌트를 연결해 리치한 렌더링.reference,content,id속성 보유, 드래그/선택 가능.
export const BibleVerse = Node.create<BibleVerseOptions>({ name: "bibleVerse", group: "block", selectable: true, draggable: true, atom: true, addNodeView() { return ReactNodeViewRenderer(BibleVerseComponent); }, });
모바일 앱 구현(설계 중심)
로딩 전략과 실행 모드
- 파일:
app-bible-note/App.tsx
- 전략:
- 로컬 개발 모드
.env의IS_LOCAL_WEBVIEW가true면LOCAL_SERVER_URL로 바로 접속.- 원격 배포 모드
- 앱이 실행되면서 원격
editor.zip을 다운로드/압축 해제 - 앱 내 로컬 정적 서버(
127.0.0.1:3000)로 서빙 후 WebView가 해당 URL로 접속.
if (IS_LOCAL_WEBVIEW === 'true') { setOrigin(LOCAL_SERVER_URL); setPreparingServer(false); return; } // 원격 모드: FileService 진행 상태 콜백 등록 → 완료 시 ServerService.startServer(rootDir)
정적 자원 준비
- 파일:
app-bible-note/src/services/FileService.ts
- 역할:
- 웹 루트 디렉토리 생성/검증 → 로컬
version읽기 → 원격 버전과 비교(현재 샘플은'1.1'하드코딩; 실제 구현 시 서버에서 조회). downloadFile()로REMOTE_SERVER_URL/editor.zip다운로드(진행도 콜백으로 UI 반영)- → 존재/사이즈 검증 →
unzip()으로 압축 해제 → 필요 시editor/서브폴더 감지 - →
version갱신 → 완료 콜백으로 서버 시작 지점 알림. - 오류/네트워크 이슈 시 Android는 번들 자산(
copyFileAssets('editor', fileDir))로 폴백.
기술 포인트:
- 파일 I/O:
@dr.pogodin/react-native-fs
- 압축 해제:
react-native-zip-archive
- 진행 상황 UI:
DownloadProgress를 상태로 노출 → WebViewScreen에서 스피너/메시지 표시
로컬 정적 서버
- 파일:
app-bible-note/src/services/ServerService.ts
- 역할:
@dr.pogodin/react-native-static-server로fileDir을 루트로 바인딩,127.0.0.1:3000에서 서빙.- 간단한
mod_alias/mod_rewrite설정으로 유연한 경로 처리. - 서버 시작/중지와 상태 변경 콜백(
ServerStatus) 제공.
const server = new Server({ fileDir: rootDir, hostname: '127.0.0.1', port: 3000, /* ... */ }); const res = await server.start(); if (res) { this.updateStatus(res, true); }
WebView 화면 및 키보드 UX
- 파일:
app-bible-note/src/screens/WebViewScreen.tsx
- 역할:
origin이 준비될 때까지 다운로드/압축/서버 준비 상태를 UI로 표시.injectedJavaScript로 입력 폰트/선택 동작 UX 보완, 포커스/블러 이벤트를 React Native로 전달.- 키보드 툴바(
KeyboardToolbar)를 별도 오버레이로 제공, iOS/Android 모두 자연스러운 편집 경험. onShouldStartLoadWithRequest에서 허용된 오리진만 로드- 외부 링크는
Linking.openURL로 브라우저 위임.
정적 패키지 구조와 호환성
editor.zip은 두 가지 구조를 모두 지원합니다.- zip 루트에 빌드 결과물을 직접 포함
- zip 내부 최상위에
editor/폴더를 두고 그 아래에 빌드 결과물 포함
- 압축 해제 후
editor서브폴더 유무를 감지해 서버 루트를 설정합니다.
version파일을 함께 관리하여 업데이트 여부를 판단합니다(Android 폴백 시editor/version번들 자산과 비교).
보안/성능 고려
- WebView는 로컬 정적 서버에서만 자원을 로드하므로, 네트워크 의존도를 낮추고 오프라인 친화적입니다.
- 캐시 정책은 개발 편의와 일관성을 위해
LOAD_NO_CACHE를 사용(필요시 빌드 단계에서 조정 가능)
Next Step
- 원격 버전 조회/서명 검증(무결성 체크) 도입
- 증분 업데이트(전체 zip 재다운로드 대신 diff/etag 기반)
- Supabase 오프라인 큐/재시도(네트워크 복구 시 동기화)
- 딥링크/성경 구절 공유 → 에디터 포커스 이동
