mdcore Engine Architecture Decision

“유니버설 엔진”이 되려면 뭘로 만들어야 하는가?

Last updated: 2026-03-23

⚠️ 전략 업데이트 (2026-03-23): 기술 결정(Rust/WASM/comrak)은 전부 유효. 변경된 것은 우선순위: 엔진 표면 확장(npm, CLI, VS Code 등)보다 mdfy.cc 바이럴 루프(뱃지 + Chrome 익스텐션)를 먼저 완성. 컴파일 타겟에 macOS QuickLook (aarch64-apple-darwin)도 추가됨. 상세: updatedDirection.md v5.0 참조.


핵심 결론: Rust

Rust core → 다중 타겟 컴파일이 유일한 정답이다.

TypeScript로는 “제품”을 만들 수 있다. Rust로는 “인프라”를 만든다. mdcore의 비전이 “AI와 사람 사이의 콘텐츠 인프라”라면, 인프라의 언어로 만들어야 한다.


왜 Rust인가: Surface Map × Compilation Target 매핑

# Surface 실행환경 필요한 컴파일 타겟 TypeScript Rust
1 mdfy.cc (웹 제품) Browser WASM / JS ✅ WASM
2 @mdcore/engine (npm) Node.js Native addon / WASM ✅ napi-rs
3 @mdcore/terminal (CLI) OS native 독립 바이너리 ❌ Node 필요 ✅ 단일 바이너리
4 VS Code 확장 Node + Web JS / WASM ✅ 둘 다
5 WASM 모듈 어디서나 wasm32 ❌ 직접 불가 ✅ 네이티브
6 Obsidian 플러그인 Electron JS ✅ WASM
7 Email 렌더러 Server Node / Native
8 GitHub Action Docker/Node 바이너리 / JS
9 Slack App Server API 서버
10 Raycast 확장 Node.js JS ✅ napi-rs
11 Mobile SDK iOS/Android Swift FFI / Kotlin JNI ❌ 브릿지 필요 ✅ UniFFI
12 Cloudflare Workers Edge WASM ❌ 제한적 ✅ WASM
13 Deno Runtime WASM / ESM ⚠️ 호환이슈 ✅ WASM 1st class
14 macOS Quick Look Swift + WebKit WASM (WebKit 내) ❌ 불가 ✅ WASM via WebKit

결론: TypeScript는 11/14 표면에서 “돌아가긴” 하지만, 4개 핵심 표면(CLI, Mobile, Edge, macOS Quick Look)에서 구조적 한계가 있다. Rust는 14/14 모두 네이티브로 커버한다.


실제 선례: “한 언어 → 모든 곳” 패턴

프로젝트 코어 언어 배포 채널 교훈
SWC Rust npm (napi-rs) + WASM + CLI 20x faster than Babel. Next.js 기본 컴파일러
Biome Rust CLI + VS Code (LSP) + WASM (Playground) 하나의 Service Layer → 3개 인터페이스
Typst Rust WASM (웹 에디터) + CLI (네이티브) 과학 문서 조판. Leptos로 웹 렌더링
tree-sitter C/Rust WASM + 네이티브 바인딩 VS Code, Zed, Neovim 전부 사용
Turbopack Rust Next.js 내장 (v16 기본값) 700x faster than Webpack

공통점: 전부 Rust(또는 C) 코어 → WASM + napi-rs + 네이티브 바이너리 패턴.


Rust MD 생태계 현황

파서 후보

라이브러리 CommonMark GFM MDX 확장성 사용처
comrak ✅ 0.31.2 ✅ 전체 커스텀 포매터, 하이라이터 GitLab, crates.io, Reddit
pulldown-cmark ✅ 0.31 ⚠️ 부분 이벤트 기반 Rust 생태계 표준
markdown-rs micromark 아키텍처 Vercel 후원, unified.js 연계
markdown-it-rust ⚠️ 플러그인 시스템 markdown-it 포트

추천 조합

Core Parser: comrak (GFM 완전 지원, 프로덕션 검증) MDX 지원: markdown-rs (Vercel 후원, MDX 네이티브) 하이라이팅: tree-sitter 또는 syntect (Rust 네이티브) 수학: KaTeX WASM 또는 자체 TeX 파서 다이어그램: mermaid-js (WASM 아님, JS로 유지)

아키텍처 설계

레이어 구조

┌─────────────────────────────────────────────────────────────────────┐ │ Consumer Layer (JS/TS) │ │ mdfy.cc (React) │ @mdcore/sdk (npm) │ VS Code │ Obsidian │ └──────────┬──────────┴──────────┬──────────┴─────┬─────┴─────┬──────┘ │ │ │ │ ┌─────┴─────────────────────┴────────────────┴───────────┴──────┐ │ Binding Layer │ │ WASM (browser/edge) │ napi-rs (Node) │ UniFFI (mobile) │ └──────────┬─────────────┴──────────┬────────┴──────────┬───────┘ │ │ │ ┌──────────┴────────────────────────┴───────────────────┴───────┐ │ mdcore-engine (Rust) │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │ │ │ Parser │ │ Renderer │ │Converter │ │Flavor Detect │ │ │ │ (comrak) │ │ (custom) │ │ (X↔MD) │ │ (auto) │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────────┘ │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │Highlight │ │ Math │ │ AST │ │ │ │(syntect) │ │ (TeX) │ │ (mdast) │ │ │ └──────────┘ └──────────┘ └──────────┘ │ └────────────────────────────────────────────────────────────────┘

핵심 설계 원칙

  1. Zero-copy AST: Rust 소유권 시스템으로 메모리 복사 최소화
  2. Plugin via Trait: trait MdPlugin { fn transform(&self, ast: &mut MdAst); } — 코어 건드리지 않고 확장
  3. WASM-first 렌더링: 브라우저에서는 항상 WASM, Node에서는 napi-rs (WASM fallback)
  4. Streaming parser: 대용량 문서도 첫 토큰부터 렌더 시작 (pulldown-cmark 이벤트 모델)

컴파일 & 배포 매트릭스

WASMNativeBinary
(.wasm)(.node)(ELF/Mach)

npm 패키지 구조 (SWC 패턴)

@mdcore/engine ← 메인 패키지 (JS wrapper + 타입) @mdcore/engine-linux-x64-gnu ← Linux x64 네이티브 @mdcore/engine-linux-arm64-gnu ← Linux ARM64 @mdcore/engine-darwin-x64 ← macOS Intel @mdcore/engine-darwin-arm64 ← macOS Apple Silicon @mdcore/engine-win32-x64-msvc ← Windows @mdcore/engine-wasm ← WASM fallback (모든 플랫폼)

설치 시 OS/Arch 감지 → 맞는 네이티브 패키지 자동 선택. 없으면 WASM fallback.


TypeScript가 아닌 이유

“TypeScript로 먼저 빠르게 만들고 나중에 Rust로 갈아타자”는 위험하다:

항목 TS 먼저 → Rust 나중에 Rust 처음부터
Phase 1 속도 ⚡ 빠름 (2-3주) 🐢 느림 (4-6주)
Phase 2 전환 비용 💀 전면 재작성 ✅ 없음
API 호환성 ⚠️ 갈아탈 때 breaking change ✅ 처음부터 안정
CLI 배포 Node 런타임 필요 단일 바이너리
외부 기여자 인식 “또 하나의 JS 래퍼” “진짜 인프라”
npm 다운로드 성능 JS 속도 25x 빠름 (Unifast 기준)
경쟁사 모방 난이도 쉬움 어려움 (Rust 모트)

가장 위험한 시나리오: TS로 MVP 만듦 → 유저 모임 → Rust 재작성 필요 → API 호환성 깨짐 → 유저 이탈. SWC가 Babel을 이긴 이유는 “점진적 교체”가 아니라 “처음부터 Rust”였기 때문.


하지만 현실적으로: 솔로 파운더 + Rust

걱정: “Rust 러닝커브가 높지 않나?”

답변: mdcore 엔진의 80%는 이미 존재한다.

직접 만들어야 하는 것: ├── Flavor detection logic (~500줄) ├── Renderer customization layer (~1000줄) ├── X→MD converter wrappers (~800줄) ├── WASM binding glue (~200줄) └── napi-rs binding glue (~200줄) 이미 존재하는 것 (가져다 쓰는 것): ├── comrak → 파싱 + GFM 전체 ├── syntect → 코드 하이라이팅 ├── pulldown-cmark → 스트리밍 파서 (대용량용) ├── wasm-bindgen → WASM 컴파일 ├── napi-rs → Node 바인딩 └── serde → JSON 직렬화

실질적으로 작성해야 하는 Rust 코드는 ~2,700줄 정도. 나머지는 설정과 glue code.


Phase별 실행 계획

Phase 1 (Week 1-4): Core Engine + WASM

Week 1: Rust 프로젝트 셋업 - cargo new mdcore-engine --lib - comrak 통합, 기본 파싱/렌더링 - Flavor detection (GFM, Obsidian, MDX, Pandoc) - 테스트 스위트 (CommonMark spec tests) Week 2: WASM 컴파일 + 웹 통합 - wasm-bindgen 셋업 - parse(md) → HTML 함수 WASM으로 노출 - mdfy.cc (Next.js)에서 WASM import - 렌더링 커스터마이징 (테마, 스타일) Week 3: napi-rs + npm 패키지 - napi-rs 바인딩 - @mdcore/engine npm 패키지 첫 배포 - 플랫폼별 prebuild (linux-x64, darwin-arm64, wasm) - TypeScript 타입 정의 자동 생성 Week 4: mdfy.cc MVP - Next.js + WASM 엔진 통합 - 입력 → 렌더링 → 공유 기본 플로우 - Shiki (하이라이팅), KaTeX (수학), Mermaid (다이어그램)은 JS로 유지 - Vercel 배포

Phase 2 (Week 5-8): 확장 표면

- @mdcore/terminal (CLI) — cargo build로 네이티브 바이너리 - VS Code 확장 — WASM 번들 - X→MD 변환기 — HTML/PDF/DOCX → MD - Interactive editing layer — JS/React (WASM 엔진 위)

Phase 3 (Week 9-12): 생태계

- Obsidian 플러그인 - GitHub Action - Mobile SDK (UniFFI → Swift/Kotlin) - Canvas mode (tldraw + WASM 엔진)

Mermaid: WASM이 아닌 JS로 유지하는 것들

모든 것을 Rust로 만들 필요는 없다. 렌더링의 일부 레이어는 JS가 더 적합:

컴포넌트 언어 이유
MD 파싱 + AST Rust 성능, 유니버설
HTML 렌더링 Rust 코어 기능
Flavor 감지 Rust 코어 기능
X↔MD 변환 Rust 코어 기능
Syntax highlighting JS (highlight.js) syntect는 WASM 불가, Shiki보다 경량
Math (KaTeX) JS 브라우저 DOM 필요
Diagrams (Mermaid) JS SVG 렌더링, DOM 의존
Interactive editing JS/React UI 레이어
Mermaid visual editor JS/React (자체 구현) tldraw 대신 경량 캔버스. 외부 의존성 0
HTML → MD 변환 JS (Turndown) 붙여넣기 자동 감지
테마/스타일 CSS/TailwindCSS 스타일은 코드 아님

원칙: “데이터를 다루는 것은 Rust, 화면을 다루는 것은 JS”


최종 기술 스택

┌─────────────── mdcore tech stack ───────────────────────┐ │ │ │ CORE (Rust) │ │ ├── comrak — MD 파싱 (GFM) │ │ ├── pulldown-cmark — 스트리밍 파싱 (대용량) │ │ ├── syntect — 코드 하이라이팅 (서버/CLI용) │ │ ├── serde — JSON 직렬화 │ │ ├── wasm-bindgen — WASM 바인딩 │ │ └── napi-rs — Node.js 네이티브 바인딩 │ │ │ │ BINDING │ │ ├── @mdcore/engine — npm 메인 패키지 (TS 타입) │ │ ├── @mdcore/wasm — WASM 번들 (브라우저/Edge) │ │ └── uniffi — iOS/Android 바인딩 (Phase 3) │ │ │ │ PRODUCT (TypeScript/React) │ │ ├── Next.js 15 — mdfy.cc 웹앱 │ │ ├── TailwindCSS — 스타일링 │ │ ├── shadcn/ui — UI 컴포넌트 │ │ ├── Shiki — 코드 하이라이팅 (브라우저) │ │ ├── KaTeX — 수학 렌더링 │ │ ├── Mermaid — 다이어그램 │ │ ├── tldraw — Canvas mode (Phase 2) │ │ └── Supabase — Auth, DB, Storage │ │ │ │ INFRA │ │ ├── Vercel — 프론트엔드 배포 │ │ ├── Cloudflare Workers — Edge WASM 실행 │ │ ├── GitHub Actions — CI/CD + 멀티플랫폼 빌드 │ │ └── crates.io — Rust 크레이트 배포 │ │ │ └──────────────────────────────────────────────────────────┘

이것이 만드는 모트(Moat)

  1. 기술 모트: Rust로 작성된 MD 엔진을 JS로 복제하는 것은 수개월~수년. JS 엔진을 Rust로 대체하는 것도 마찬가지. 먼저 Rust로 가는 쪽이 이김.
  2. 배포 모트: 하나의 코어가 13개 표면에 동시 배포. 경쟁자는 각 표면마다 별도 구현 필요.
  3. 성능 모트: WASM 엔진이 JS 대비 3-25x 빠름. 대용량 문서에서 체감 차이 극명.
  4. 인식 모트: “Rust로 만든 인프라”는 개발자 커뮤니티에서 “진짜”로 인식됨. SWC, Biome, Turbopack이 증명.

“Infrastructure should be written in infrastructure languages.”— mdcore의 기술 철학