Phase 2 완료 (4개): - 노무관리, 단가관리(건설), 입금, 출금 Phase 3 라우팅 구조 변경 완료 (22개): - 거래처(영업), 팝업관리, 공정관리, 게시판관리, 대손추심, Q&A - 현장관리, 실행내역, 견적관리, 견적(테스트) - 입찰관리, 이슈관리, 현장설명회, 견적서(건설) - 협력업체, 시공관리, 기성관리, 품목관리(건설) - 회계 도메인: 거래처, 매출, 세금계산서, 매입 신규 컴포넌트: - ErrorCard: 에러 페이지 UI 통일 - ServerErrorPage: V2 페이지 에러 처리 필수 - V2 Client 컴포넌트 및 Config 파일들 총 47개 상세 페이지 중 28개 완료, 19개 제외/불필요 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
119 lines
3.6 KiB
Markdown
119 lines
3.6 KiB
Markdown
# Chrome DevTools MCP - 이모지 JSON 직렬화 오류
|
|
|
|
> 작성일: 2025-01-17
|
|
|
|
## 문제 현상
|
|
|
|
Chrome DevTools MCP가 특정 페이지 접근 시 다운되는 현상
|
|
|
|
### 에러 메시지
|
|
```
|
|
API Error: 400 {"type":"error","error":{"type":"invalid_request_error",
|
|
"message":"The request body is not valid JSON: invalid high surrogate in string:
|
|
line 1 column XXXXX (char XXXXX)"},"request_id":"req_XXXXX"}
|
|
```
|
|
|
|
### 발생 조건
|
|
- 페이지에 **이모지**가 많이 포함된 경우
|
|
- `take_snapshot` 또는 다른 MCP 도구 호출 시
|
|
- a11y tree를 JSON으로 직렬화하는 과정에서 발생
|
|
|
|
## 원인
|
|
|
|
### 유니코드 서로게이트 쌍 (Surrogate Pair) 문제
|
|
|
|
이모지는 UTF-16에서 **서로게이트 쌍**으로 인코딩됨:
|
|
- High surrogate: U+D800 ~ U+DBFF
|
|
- Low surrogate: U+DC00 ~ U+DFFF
|
|
|
|
Chrome DevTools MCP가 페이지 스냅샷을 JSON으로 직렬화할 때, 이모지의 서로게이트 쌍이 깨지면서 "invalid high surrogate" 오류 발생.
|
|
|
|
### 문제가 되는 케이스
|
|
1. **DOM에 직접 렌더링된 이모지**: `<span>🏠</span>`
|
|
2. **데이터에 포함된 이모지**: API 응답, 파싱된 데이터
|
|
3. **대량의 이모지**: 수십 개 이상의 이모지가 한 페이지에 존재
|
|
|
|
## 해결 방법
|
|
|
|
### 1. 이모지를 Lucide 아이콘으로 교체 (UI)
|
|
|
|
**Before**
|
|
```tsx
|
|
const iconMap = {
|
|
'기본': '🏠',
|
|
'인사관리': '👥',
|
|
};
|
|
|
|
<span className="text-xl">{category.icon}</span>
|
|
```
|
|
|
|
**After**
|
|
```tsx
|
|
import { Home, Users, type LucideIcon } from 'lucide-react';
|
|
|
|
const iconComponents: Record<string, LucideIcon> = {
|
|
Home,
|
|
Users,
|
|
};
|
|
|
|
function CategoryIcon({ name }: { name: string }) {
|
|
const IconComponent = iconComponents[name] || FileText;
|
|
return <IconComponent className="w-5 h-5" />;
|
|
}
|
|
|
|
<CategoryIcon name={category.icon} />
|
|
```
|
|
|
|
### 2. 데이터 파싱 시 이모지 제거/변환 (Server)
|
|
|
|
```typescript
|
|
function convertEmojiToText(text: string): string {
|
|
// 특정 이모지를 의미있는 텍스트로 변환
|
|
let result = text
|
|
.replace(/✅/g, '[완료]')
|
|
.replace(/⚠️?/g, '[주의]')
|
|
.replace(/🧪/g, '[테스트]')
|
|
.replace(/🆕/g, '[NEW]')
|
|
.replace(/•/g, '-');
|
|
|
|
// 모든 이모지 및 특수 유니코드 문자 제거
|
|
result = result
|
|
.replace(/[\u{1F300}-\u{1F9FF}]/gu, '') // 이모지 범위
|
|
.replace(/[\u{2600}-\u{26FF}]/gu, '') // 기타 기호
|
|
.replace(/[\u{2700}-\u{27BF}]/gu, '') // 딩뱃
|
|
.replace(/[\u{FE00}-\u{FE0F}]/gu, '') // Variation Selectors
|
|
.replace(/[\u{1F000}-\u{1F02F}]/gu, '') // 마작 타일
|
|
.replace(/[\u{1F0A0}-\u{1F0FF}]/gu, '') // 플레잉 카드
|
|
.replace(/[\u200D]/g, '') // Zero Width Joiner
|
|
.trim();
|
|
|
|
return result;
|
|
}
|
|
```
|
|
|
|
## 체크리스트
|
|
|
|
새 페이지 개발 시 Chrome DevTools MCP 호환성 확인:
|
|
|
|
- [ ] 페이지에 이모지 직접 렌더링하지 않음
|
|
- [ ] 아이콘은 Lucide 또는 SVG 사용
|
|
- [ ] 외부 데이터(API, 파일) 파싱 시 이모지 제거 처리
|
|
- [ ] status, label 등에 이모지 대신 텍스트 사용
|
|
|
|
## 관련 파일
|
|
|
|
이 문제로 수정된 파일들:
|
|
|
|
| 파일 | 변경 내용 |
|
|
|------|----------|
|
|
| `dev/test-urls/actions.ts` | iconMap, convertEmojiToText 함수 추가 |
|
|
| `dev/test-urls/TestUrlsClient.tsx` | Lucide 아이콘 동적 렌더링 |
|
|
| `dev/construction-test-urls/actions.ts` | 동일 |
|
|
| `dev/construction-test-urls/ConstructionTestUrlsClient.tsx` | 동일 |
|
|
|
|
## 참고
|
|
|
|
- 이 문제는 Chrome DevTools MCP의 JSON 직렬화 로직에서 발생
|
|
- MCP 자체 버그일 가능성 있으나, 클라이언트에서 이모지 제거로 우회 가능
|
|
- 다른 MCP 도구에서도 비슷한 문제 발생 가능성 있음
|