Files
zellyy-finance/src/utils/logger.ts
hansoo a96f776157 feat: Implement comprehensive Clerk ChunkLoadError recovery system
 Enhanced chunk error detection and automatic fallback to Supabase auth
- Enhanced isClerkChunkError with specific CDN pattern matching (joint-cheetah-86.clerk.accounts.dev)
- Added automatic Clerk disable when chunk loading fails
- Implemented graceful fallback to Supabase authentication without interruption
- Added user-friendly error messages and recovery UI
- Created multi-layered error handling across ErrorBoundary, ClerkProvider, and global handlers
- Added vite.config optimization for chunk loading with retry logic

🔧 Core improvements:
- setupChunkErrorProtection() now activates immediately in main.tsx
- Enhanced ClerkProvider with comprehensive error state handling
- App.tsx ErrorBoundary detects and handles Clerk-specific chunk errors
- Automatic sessionStorage flags for Clerk disable/skip functionality
- URL parameter support for noClerk=true debugging

🚀 User experience:
- Seamless transition from Clerk to Supabase when CDN fails
- No app crashes or white screens during authentication failures
- Automatic page refresh with fallback authentication system
- Clear error messages explaining recovery process

This resolves the ChunkLoadError: Loading chunk 344 failed from Clerk CDN
and ensures the app remains functional with Supabase authentication fallback.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-14 10:36:37 +09:00

111 lines
3.5 KiB
TypeScript

/**
* 환경별 로깅 시스템
*
* 개발 환경에서는 상세한 로그를 출력하고
* 프로덕션 환경에서는 console.log를 제거하여 성능 최적화
*/
// 환경 변수로 로그 레벨 결정
const isDevelopment = import.meta.env.DEV;
const _isProduction = import.meta.env.PROD;
// 메타데이터 타입 정의
type LogMeta = Record<string, unknown> | string | number | boolean | null;
// 로거 인터페이스 정의
interface Logger {
debug: (message: string, meta?: LogMeta) => void;
info: (message: string, meta?: LogMeta) => void;
warn: (message: string, meta?: LogMeta) => void;
error: (message: string, error?: LogMeta) => void;
}
// 메시지 포맷터
const formatMessage = (
level: string,
message: string,
meta?: LogMeta
): string => {
const timestamp = new Date().toISOString();
const metaStr = meta ? ` ${JSON.stringify(meta)}` : "";
return `[${timestamp}] ${level.toUpperCase()}: ${message}${metaStr}`;
};
// 환경별 로거 구현
const createLogger = (): Logger => {
if (isDevelopment) {
// 개발 환경: 모든 로그 레벨 출력
return {
debug: (message: string, meta?: LogMeta) => {
// eslint-disable-next-line no-console
console.debug(formatMessage("debug", message, meta));
},
info: (message: string, meta?: LogMeta) => {
// eslint-disable-next-line no-console
console.info(formatMessage("info", message, meta));
},
warn: (message: string, meta?: LogMeta) => {
console.warn(formatMessage("warn", message, meta));
},
error: (message: string, error?: LogMeta) => {
console.error(formatMessage("error", message, error));
},
};
} else {
// 프로덕션 환경: 에러만 로깅, 나머지는 무시
return {
debug: () => {}, // 프로덕션에서는 무시
info: () => {}, // 프로덕션에서는 무시
warn: () => {}, // 프로덕션에서는 무시
error: (message: string, error?: LogMeta) => {
// 프로덕션에서도 에러는 기록 (향후 Sentry 연동)
console.error(formatMessage("error", message, error));
},
};
}
};
// 전역 로거 인스턴스
export const logger = createLogger();
// 레거시 console.log 대체를 위한 헬퍼 함수들
export const logDebug = (message: string, data?: LogMeta) => {
logger.debug(message, data);
};
export const logInfo = (message: string, data?: LogMeta) => {
logger.info(message, data);
};
export const logWarning = (message: string, data?: LogMeta) => {
logger.warn(message, data);
};
export const logError = (message: string, error?: LogMeta) => {
logger.error(message, error);
};
// 특정 도메인별 로거 팩토리
export const createDomainLogger = (domain: string) => {
return {
debug: (message: string, data?: LogMeta) =>
logger.debug(`[${domain}] ${message}`, data),
info: (message: string, data?: LogMeta) =>
logger.info(`[${domain}] ${message}`, data),
warn: (message: string, data?: LogMeta) =>
logger.warn(`[${domain}] ${message}`, data),
error: (message: string, error?: LogMeta) =>
logger.error(`[${domain}] ${message}`, error),
};
};
// 도메인별 로거 인스턴스들
export const syncLogger = createDomainLogger("SYNC");
export const authLogger = createDomainLogger("AUTH");
export const networkLogger = createDomainLogger("NETWORK");
export const storageLogger = createDomainLogger("STORAGE");
export const supabaseLogger = createDomainLogger("SUPABASE");
export default logger;