다크 모드
소개
@platform/vue-debugger는 개발/검증 환경 전용 인페이지 Vue 디버거입니다. 브라우저 확장이나 별도 devtools 없이, 디버깅 도구 전체가 여러분의 페이지 안에서 동작합니다. 앱을 띄우면 우측 하단에 톱니(⚙) 모양 FAB 버튼이 뜨고, 그것을 누르거나 Alt+Shift+D를 입력하면 11개 패널을 가진 디버거가 열립니다.
이 페이지는 디버거가 무엇이고 왜 이렇게 만들어졌는지를 먼저 설명합니다. 바로 붙여 보고 싶다면 빠른 시작으로 건너뛰어도 됩니다.
무엇인가
별도 Vue 앱 인스턴스로 동작하는 인페이지 디버거입니다. 컴포넌트 트리·상태·네트워크·라우팅·콘솔·에러 등 디버깅에 필요한 정보를 호스트 앱 위에 떠 있는 패널 하나로 모아 보여줍니다. 진입점은 단 하나입니다.
ts
const { attachDebugger } = await import('@platform/vue-debugger')
attachDebugger(app)attachDebugger(app, options)는 { version, open(), close(), toggle(), destroy() } 핸들을 반환하고(비브라우저 환경에서는 null), window.__VUE_DEBUGGER__로도 접근할 수 있습니다. 패널을 여는 단축키, 추적할 네트워크 제외 패턴, 모바일 브리지 같은 세부 동작은 옵션 레퍼런스에서 다룹니다.
왜 인페이지인가
대부분의 Vue 디버깅은 Vue Devtools 브라우저 확장으로 합니다. 하지만 두 가지 현실에서는 그 확장을 쓸 수 없습니다. 이 디버거는 바로 그 빈틈을 메우기 위해 태어났습니다.
- 브라우저 확장을 설치할 수 없는 환경. 사내 보안정책상 확장 설치가 막힌 폐쇄망에서는 devtools를 깔 수 없습니다. 그래서 모든 기능을 확장 없이 페이지 안에서 돌아가도록 만들었습니다.
- devtools가 아예 없는 모바일/WebView. 모바일 브라우저와 네이티브 앱의 WebView에는 붙일 수 있는 devtools가 없습니다. 이 환경에서는 인페이지 디버거가 유일한 디버깅 수단입니다. 그래서 이 도구는 모바일 퍼스트로 설계되었습니다 — 터치 타깃 확대, 세로 스택 레이아웃(≤640px), 화면을 드래그로 훑는 인스펙션, 전체화면 토글, safe-area 대응까지 들어 있습니다.
모바일 콘솔의 부재
WebView에는 콘솔조차 없는 경우가 많습니다. 컴포넌트 패널의 식 평가(선택한 스코프에서 items.length 같은 표현식을 바로 실행)가 그 콘솔을 대체합니다.
누구를 위한 것
- 사내 폐쇄망에서 일하는 Vue 3 개발자 — 확장을 못 깔지만 디버깅은 필요한 분.
- 모바일/WebView를 검증하는 개발자 — 실기기에서 상태·네트워크·네이티브 브리지 호출을 들여다봐야 하는 분.
적용 가능 여부는 단순합니다. Vue 3.4 이상 + 빌드 도구가 있는 앱이면 어디서나 동작합니다.
| 항목 | 요구 사항 |
|---|---|
| Vue | 3.4 이상 (peerDependency) |
| 번들러 | Vite 권장, webpack/Vue CLI도 가능 |
| 상태/라우터 | pinia·vue-router는 있으면 자동 연동, 없어도 동작 |
| 환경 | 브라우저(모바일 WebView 포함). SSR 서버 측에서는 자동 비활성 |
선행 조건의 상세 점검은 사전 준비를 보세요.
핵심 보장 3가지
다른 사람의 앱에 디버깅 도구를 심는 일에는 마땅한 의심이 따릅니다. 이 디버거는 다음 세 가지를 설계로 보장합니다.
1. Shadow DOM 격리 — 호스트 앱을 오염시키지 않습니다
디버거는 별도 Vue 앱 인스턴스로 떠서 Shadow DOM(:host { all: initial }) 안에서 렌더링됩니다. 호스트 앱의 CSS·DOM 트리와 완전히 분리되므로, 여러분의 스타일을 깨지 않고 여러분의 스타일에 깨지지도 않습니다.
CSS import가 필요 없습니다
스타일은 Shadow DOM 안에 자동 주입됩니다. 별도의 CSS 파일을 import할 필요가 없고, 호스트 CSS와 충돌하지도 않습니다.
2. 런타임 의존성 0 — 폐쇄망 반입은 tgz 하나로 끝
런타임 의존성이 하나도 없습니다. vue(^3.4.0)만 peerDependency이고, 그것마저 소비 앱의 vue를 그대로 씁니다. pinia·vue-router·axios는 import하지 않고 런타임에 구조적으로 발견합니다(없어도 동작하며, 해당 패널이 빈 상태로 표시될 뿐입니다).
그 결과 폐쇄망 반입이 단순해집니다 — 하위 의존성 tgz 없이 *.tgz 하나면 충분합니다. 절차는 에어갭 반입에서 다룹니다.
3. 프로덕션 0 — 진짜 프로덕션 빌드엔 코드가 들어가지 않습니다
디버거는 정적으로 평가되는 분기 안에서만 동적 import됩니다.
ts
if (import.meta.env.DEV || (import.meta.env.MODE === 'staging' && import.meta.env.VITE_DEBUGGER === 'on')) {
const { attachDebugger } = await import('@platform/vue-debugger')
attachDebugger(app)
}production 빌드에서는 두 조건이 모두 정적 false로 치환되어, Vite/Rollup이 이 블록과 그 안의 동적 import()를 dead-code로 통째 제거합니다. 디버거 코드는 프로덕션 번들에 아예 들어가지 않습니다.
동적 키 접근은 금지입니다
반드시 import.meta.env.VITE_DEBUGGER처럼 정적 치환 대상을 쓰세요. const f = 'VITE_DEBUGGER'; import.meta.env[f]처럼 동적으로 접근하면 정적 제거가 일어나지 않아 디버거가 프로덕션에 그대로 남습니다. 자세한 분기 로직과 누출 검사는 환경별 설정을 보세요.
한눈에 보는 11개 패널
디버거는 11개 패널로 구성됩니다. 각 패널의 세부 동작은 패널 레퍼런스에서 다룹니다.
| 패널 | 한 줄 요약 |
|---|---|
| 컴포넌트 | 트리 탐색(검색/접기/가상화) + 인스펙션 모드 · 값 출처 칩 · 변경 히스토리 · 식 평가 |
| 네트워크 | XHR/fetch 바닥 캡처 + 헤더(401·CORS·쿠키)·cURL 복사·직전 인과 맥락(breadcrumb) |
| Pinia | 상태 트리(인라인 편집) · 액션/뮤테이션 로그 · 타임트래블 |
| 스토리지 | local/session/cookie 보기·편집 + 쓴 코드의 호출 스택 |
| 🔗 연쇄 | watch 사이드이펙트를 시간 인과로 묶은 계단식 트리 |
| 에러 | errorHandler·window error·unhandledrejection 수집 + 원본 위치 복원 + 직전 맥락(breadcrumb) |
| 콘솔 | console.* 캡처 — 인자 직렬화 보존, warn/error에 호출 스택 |
| Router | 현재 라우트 · 네비게이션 타임라인 · 어느 가드가 막았나 귀속 |
| 📱 브리지 | WebView↔네이티브 호출 기록 + 수동 호출 + 환경 지문 |
| 🐞 리포트 | 현재 상황을 JSON으로 캡처 → 공유 · 같은 디버거로 다시 열람 |
| 정보 | 환경 진단 · 통합 타임라인 · UX 신호 · '알려진 한계' 고지 |
탭은 고정하고, 패널은 도크할 수 있습니다
탭을 길게 눌러 고정하면 자주 쓰는 탭이 앞으로 옵니다. 패널 상단에서는 도크 위치(하단/좌/우)와 전체화면을 바꿀 수 있습니다. 탭 전환은 패널을 캐시(KeepAlive)해 저사양 PC에서도 즉각입니다.
0.13~0.15 사이 추가된 것
소스맵 콜스택(개발자 호출자 최대 5스텝 강조·호출 위치 → 배지) · 인과 맥락 breadcrumb(콜스택이 비동기로 끊겨도 직전 행위로 보완) · 네트워크 헤더·cURL 복사 · 컴포넌트 트리 검색/접기/가상화 · 탭 전환 즉각화. 한눈에 보려면 변경 이력, 운영 누출 차단 강화는 보안·누출 차단을 보세요.
다음 단계
개념은 여기까지입니다. 이제 실제로 붙여 봅시다.