728x90
Styled Component 사용 시, 순환 참조로 인한 문제 해결
문제 상황
MUI와 Emotion을 함께 사용할 때 Styled Component가 순환 참조가 있는 경우, 다음과 같은 오류가 발생:
Uncaught TypeError: Cannot read properties of undefined (reading '__emotion_styles')
관련 이슈
- styled-components Issue #1449
- styled-components와 비슷한 문제가 Emotion에서도 발생
- 순환 참조로 인해 스타일 정보가 undefined가 되는 현상 보고
원인 분석
- 순환 참조(Circular Dependency)
- 컴포넌트 간의 상호 참조로 인해 JavaScript의 모듈 로딩 시점에 문제 발생
- index.ts를 통한 재내보내기(re-export) 패턴이 주요 원인
- 동기적으로 처리되는 import 구문에서 순환 참조 시 undefined 발생
- 주요 발생 패턴
// components/index.ts
export * from './styled';
export * from './ComponentA';
// components/ComponentA.tsx
import { StyledComponent } from '../components';
해결 방법
순환 참조 감지 & 프로젝트 개선
# madge 설치
yarn add -D madge
# 순환 참조 검사
npx madge --circular src/index.tsx
- 다음과 같이 순환 참조되어 있는 부분 감지하여 프로젝트 구조 개선
- eslint로도 가능
예방책
- 패키지 구조화
- eslint 적용
- git hook pre-commit에 순환 참조 체크 스크립트 적용
{
"scripts": {
"check-circular": "madge --circular src/index.tsx",
"lint": "yarn check-circular && eslint ."
},
"husky": {
"hooks": {
"pre-commit": "yarn check-circular"
}
}
}
결론
- 순환 참조는 JavaScript 모듈 시스템의 특성상 예상치 못한 undefined 문제를 일으킬 수 있음
- madge, eslint 같은 도구로 순환 참조를 사전에 감지하고 제거하는 것이 중요
- 나의 경우 Vite HMR 에서 문제가 발생함 (Production, Next.js에선 오류 인식 불가)
Vite HMR Vs Next.js HMR Vs Build
Vite vs Next.js HMR
1. Vite HMR
- ESM(ES Modules) 기반으로 동작
- 브라우저 네이티브 ESM을 활용
- 모듈 단위로 교체
- 개발 서버에서 번들링 없이 바로 소스 코드를 제공
// 각 모듈이 독립적으로 로드됨
import { Component } from './Component'
2. Next.js HMR
- Webpack 기반으로 동작
- 번들 기반 접근
- 변경된 모듈과 그 의존성을 포함한 청크 단위로 교체
- 웹팩이 모듈을 번들링
- HMR이 번들 레벨에서 작동
3. 순환 참조 처리의 차이
Vite
- ESM의 순환 참조 처리 방식을 따름
- 모듈 초기화 순서가 더 엄격
- HMR 시 순환 참조 문제가 더 잘 드러날 수 있음
Next.js
- Webpack의 모듈 시스템을 사용
- 번들링 과정에서 순환 참조 처리
- 상대적으로 순환 참조에 더 관대
빌드 Vs Vite HMR
빌드 버전에서 문제가 없었던 이유
- 빌드 시에는 전체 코드가 번들링되고 최적화됨
- 순환 참조가 있더라도 번들러가 처리
- 모든 모듈이 평가된 후 실행
Vite HMR에서 문제가 발생한 이유
- 실시간으로 모듈을 교체하는 과정에서 초기화 순서 문제 발생
- Vite의 ESM 기반 HMR이 순환 참조에 더 민감
결론
- Vite의 개발 서버에서는 순환 참조 문제가 더 쉽게 드러남
- 빌드 버전에서는 번들링 과정에서 이런 문제가 감춰질 수 있음
- Next.js는 Webpack 기반이라 순환 참조를 더 잘 처리할 수 있음
- Vite의 HMR에서 발생한 문제는 실제로 코드의 잠재적인 문제를 더 일찍 발견하게 해주는 장점이 될 수 있음