Lighthouse of FE biginner

[MFA] Micro App의 관심사 공유 본문

[WEB] 프론트엔드

[MFA] Micro App의 관심사 공유

[FE] Lighthouse 2025. 2. 13. 18:04
Micro App 간의 공통 관심사가 있고, 해당 관심사를 서로 공유해 하는 케이스

 

Micro Frontend Architecture에서 Micro App은 느슨하게 결합됩니다.

 

한 개의 Shell(Host) App과 3개의 Remote App이 있습니다. 각각의 Micro App은 특정 App에 의존하지 않고 각각의 포트에서 홀로 구동(Standalone)이 될 수 있습니다.

 

Module Federation으로 통합될 시 구동 중인 Remote App들은 Shell App에 런타임에 통합됩니다. 이때 Remote App은 반드시 Remote App의 역할만 할 수 있는 것은 아닙니다.

 

Remote App은 특정 모듈을 expose 하여 다른 Remote App의 Host App이 될 수 있습니다.

 

위 그림에서 Remote2 App은 Remote App의 Fragment를 Remote로 사용하고 있습니다. 이 경우에 Remote2 App은 모듈을 expose하고 다른 App을 remote로 등록하기도 합니다.

 

 

“공통” 관심사

만약 모든 App에서 공통 관심사(상태)가 있을 경우 어떨까요?

 

각 Remote App은 하나의 플랫폼을 이루기 위해 Shell App에 통합됩니다. 개발하는 입장에선 여러 개의 App을 띄우지만, 사용자의 관점에는 자신이 여러 개의 App에 접근하는 것에 관심이 없듯 하나의 플랫폼만 (통합된 Shell App)만 바라봅니다.

 

사용자가 플랫폼에 로그인하여 사용자 인증을 한 뒤 프론트엔드는 사용자의 정보를 담고 있습니다.

 

모든 App은 사용자 정보에 관심이 있습니다. 이를 공통 관심사(횡단 관점)라고 합니다.

 

예시를 들어봅니다. Shell App에 유저 정보를 위한 Store가 존재하고 로그인 기능이 붙어 있습니다.

 

사용자가 로그인을 하면 서버로부터 유저 정보를 받아 Store에 Set 합니다. Shell App은 Store을 expose 하고, Remote App에서 해당 Store을 remote로 등록해 사용합니다.

 

이런 경우 Host ← → Remote App의 순환 참조가 발생합니다. MFA 아키텍처에서 순환 참조가 발생하면 (Micro App에서 expose, remote) 디버깅이 어려워지고 강 결합이 발생하기 됩니다.

 

느슨한 결합을 유지하며 의존성을 단 방향으로 유지하며 상태를 한 방향으로 흐르게 설계하는 것이 데이터의 흐름을 예측하고 예외 케이스를 디버깅 하기에 좋습니다.

Module Federation의 이론 상 모든 Micro App은 Container가 될 수 있습니다. 이 말은 즉 순환 참조가 가능하다는 것 입니다.

 

Remote App에서 상태를 Expose

순환 참조가 발생하지 않으며 가장 간단하게 상태를 공유하는 방식은 사용자 인증을 담당하는 Micro App에서 Store을 Expose 하는 방식입니다.

 

다른 Micro App에서 해당 Remote App을 remote로 등록한 후 Store을 사용하면 쉽게 상태를 공유할 수 있습니다.

 

하지만 해당 방식은 Store을 사용하기 위해 반드시 Remote App을 구동해야 하는 의존성이 발생하고, 이로 인해 강 결합이 발생합니다.

 

이벤트 방식의 커뮤니케이션

각 Micro App에 User Store을 소유하고 Store의 정보가 바뀔 시 정의한 Custom Event를 Dispatch, 각 Micro App에서는 Event를 Listening 하며 Micro App의 커뮤니케이션 방식으로 상태를 공유할 수 있습니다.

 

하지만 이 방식은 각 App이 중복으로 Store을 관리해야 한다는 점과, Custom Event를 정의하고 커뮤니케이션 하는 방식을 관리해야 한다는 점이 발생합니다.

 

Communication Between Micro Frontends

 

Communication Between Micro Frontends

Having gained much experience with the implementation of various microfrontend-based solutions — I’l...

dev.to

 

Local Storage에 저장

Store을 사용하지 않고 Local Storage를 통해 쉽게 상태를 공유할 수 있습니다.

 

이 경우 상태 공유를 위해 상태 관리 라이브러리를 공통으로 사용하지 않고 각 Micro App마다 독자적인 기술 스택 구성을 할 수 있다는 장점이 생깁니다.

 

Local Storage는 브라우저에 지속되는 성격이기 때문에, 만약 민감한 정보를 담고 있는 상태라면 해당 방식이 옳은 방식인지는 다시 한번 생각해봐야 합니다.

 

window 객체에 저장

브라우저의 globalThiswindow 객체입니다. 이를 활용해 window 객체의 프로퍼티로 특정 상태를 바인딩 하고, 이를 Micro App에서 공유할 수 있습니다.

하지만 window 객체는 JavaScript로 조작이 가능하기에 민감한 정보를 담을 수 없으며 많은 데이터를 window에 바인딩 할 시 메모리 누수가 발생할 수 있는 점, 전역 스코프가 오염될 수 있는 점을 고려해야 합니다.

 

스토어 패키지

마지막으로 공통 관심사를 패키징 하는 방법 입니다.

MFA을 구현하는 경우 UI, 타입, Provider, 등 공통 관심사를 패키지로 분리합니다.

Micro App 에서 공유하려는 상태 역시 공통 관심사라는 점에 착안해 패키지로 분리하고 각 App에서 빌드 된 패키지를 사용하는 방식으로 상태를 공유할 수 있습니다.

아래의 예시는 Monorepo/MFA 환경에서 구축된 예시입니다.

 

모노레포의 패키지 디렉토리 내 store 패키지를 만들고 라이브러리 모드로 빌드 합니다.

 

각 Micro App에서 해당 Store 패키지를 install 합니다.

Monorepo로 구성되어 있기 때문에 packages 디렉토리는 꼭 workspace에 명시되어야 합니다.
패키지를 설치할 때는 꼭 패키지가 빌드 된 상태여야 합니다.

 

 

Module Federation 플러그인에서 패키지를 singleton으로 공유합니다. singleton으로 공유해야 같은 chunk를 바라보고 상태가 공유됩니다!

export const mfConfig = {
  name: "host",
  filename: "remoteEntry.js",
  shared: {
    // ... 공유될 라이브러리 목록
    "@mfa/store": {
      singleton: true,
    },
  },
};

 

 

각각의 Micro App에서 해당 패키지의 Store을 import하고 사용합니다.

 

 

같은 Shell App, Remote App 모두 @mfa/store 패키지를 설치했고, singleton으로 라이브러리를 공유해 같은 스토어를 바라보고 있습니다.

 

Shell App에서 상태를 변경하니 Remote App에도 변경된 상태를 바라보고 반대의 경우에도 마찬가지 입니다.

 

고려해야 할 점

패키지를 통해 전역 상태를 각 Micro App에서 공유할 수 있게 되었으며, 상태 공유를 위해 런타임에 의존하지 않기 때문에 Micro App 이 느슨하게 결합됩니다.

 

이 방식으로 주의해야 할 점은 만약 상태 공유를 위해 특정 라이브러리를 사용한다면 MFA를 구성하는 App에서 상태 관리를 위해 같은 라이브러리를 사용해야 한다는 점이 있습니다.

 

Micro Frontend는 독립된 프론트엔드 App에서 다양한 팀에 각자의 기술 스택을 사용하며 프로젝트를 진행할 수 있는 장점이 있습니다.

 

패키지를 통해 라이브러리를 컨벤션으로 고정하여 팀의 자율성을 해칠 수 있기 때문에 각 팀의 논의 하에 패키징이 되어야 합니다.