본문 바로가기
TroubleShooting

__emotion_styles undefined 문제 해결

by 왕큰새 2024. 11. 22.
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가 되는 현상 보고

원인 분석

  1. 순환 참조(Circular Dependency)
    • 컴포넌트 간의 상호 참조로 인해 JavaScript의 모듈 로딩 시점에 문제 발생
    • index.ts를 통한 재내보내기(re-export) 패턴이 주요 원인
    • 동기적으로 처리되는 import 구문에서 순환 참조 시 undefined 발생
  2. 주요 발생 패턴
// 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로도 가능

예방책

  1. 패키지 구조화
  2. eslint 적용
  3. 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 기반으로 동작
  • 번들 기반 접근
  • 변경된 모듈과 그 의존성을 포함한 청크 단위로 교체
    1. 웹팩이 모듈을 번들링
    2. HMR이 번들 레벨에서 작동

3. 순환 참조 처리의 차이

Vite

  • ESM의 순환 참조 처리 방식을 따름
  • 모듈 초기화 순서가 더 엄격
  • HMR 시 순환 참조 문제가 더 잘 드러날 수 있음

Next.js

  • Webpack의 모듈 시스템을 사용
  • 번들링 과정에서 순환 참조 처리
  • 상대적으로 순환 참조에 더 관대

빌드 Vs Vite HMR

빌드 버전에서 문제가 없었던 이유

  • 빌드 시에는 전체 코드가 번들링되고 최적화됨
  • 순환 참조가 있더라도 번들러가 처리
  • 모든 모듈이 평가된 후 실행

Vite HMR에서 문제가 발생한 이유

  • 실시간으로 모듈을 교체하는 과정에서 초기화 순서 문제 발생
  • Vite의 ESM 기반 HMR이 순환 참조에 더 민감

결론

  • Vite의 개발 서버에서는 순환 참조 문제가 더 쉽게 드러남
  • 빌드 버전에서는 번들링 과정에서 이런 문제가 감춰질 수 있음
  • Next.js는 Webpack 기반이라 순환 참조를 더 잘 처리할 수 있음
  • Vite의 HMR에서 발생한 문제는 실제로 코드의 잠재적인 문제를 더 일찍 발견하게 해주는 장점이 될 수 있음