Module Federation

장유진·2025년 1월 31일

Module Federation에 대해서 설명하기 위해서는 우선 Micro Frontend에 대해서 알아야 한다.

Micro Frontend(MFE)

MFE는 프론트엔드 애플리케이션을 작은 독립적인 모듈로 분리하여 개발하고 관리하는 아키텍쳐로, 전체 시스템의 복잡성을 줄이고 생산성을 향상하는 데 도움이 된다.

여기에서 모듈이란 빌드할 때 사용하는 코드를 포함한 모든 리소스를 말한다. 즉, JS 뿐만 아니라 HTML, CSS, JSON, 각종 이미지 파일 등이 해당한다.

여러 개의 모듈들이 분리되어 독립적인 CI/CD를 진행하고 나면 하나의 웹 페이지로 조립하는 통합 과정이 필요하다.

통합 기법의 종류는 다음과 같다. (자세한 설명은 여기에서)

  1. 서버 측 템플릿 조합 (Server-side template composition)
  2. 빌드 타입 통합 (Build-time integration)
  3. iframe을 통한 런타임 통합 (Run-time integration via iframe)
  4. 웹 컴포넌트를 통한 런타임 통합 (Run-time integration via Web Components)
  5. 자바스크립트를 통한 런타입 통합 (Run-time integration via Javascript)

이 중 5번에 대해 알아보자.

자바스크립트를 통한 런타입 통합

자바스크립트를 통한 런타입 통합이란 웹 페이지를 불러온 시점에, 컨테이너 애플리케이션이 어떤 애플리케이션을 마운트할지 결정하고 관련 함수를 호출하여 애플리케이션에 렌더링할 시기와 위치를 알려주는 기법이다.

장점

  • 빌드 타임 통합과 달리, 각 애플리케이션을 독립적으로 배포할 수 있음
  • iframe과 달리, 애플리케이션 간의 통합을 원하는 대로 구축할 수 있음
  • 런타임에 동적으로 애플리케이션을 로드할 수 있어 유연성이 높음

단점

  • 런타임에 통합되는 과정에서 애플리케이션마다 중복된 코드를 불러올 수 있음
  • 런타임에 동적으로 애플리케이션을 로드하기 때문에 해당 애플리케이션을 로드하지 못해 통합하지 못하는 문제 발생 가능
  • 런타임에서 통합되기 때문에 빌드타임에 타입 검사가 어려울 수 있음

Module Federation은 바로 이 자바스크립트를 통한 런타임 통합 기법을 구현할 수 있는 방법 중 하나이다.

Module Federation

다시 말해서 Module Federation은 MFE를 구현하기 위한 방식들 중 하나로, 런타임에 통합되어 각 앱이 서로 코드를 공유할 수 있도록 하는 기능이다.

Webpack 5에서 처음 도입되었고 다음과 같은 특징이 있다.

  • 독립적인 배포: 각 애플리케이션이나 모듈이 독립적으로 배포되므로 업데이트와 배포 주기를 개별적으로 관리할 수 있다
  • 코드 중복 감소: 공통 모듈을 공유하여 번들 크기를 줄이고 네트워크 성능을 최적화한다.
  • 런타임 모듈 로딩: 모듈을 컴파일 타임이 아니라 런타임에 동적으로 롣하여 최신 버전의 모듈을 공유할 수 있다.
  • ESM 및 CommonJS 지원

주요 개념

  • container: 빌드의 단위. 즉 하나의 컨테이너는 하나의 애플리케이션을 말함
  • host: 다른 애플리케이션에서 제공하는 모듈을 가져다 사용하는 애플리케이션
  • remote: 모듈을 제공하는 애플리케이션
  • expose: remote에서 다른 애플리케이션이 자신의 모듈을 사용할 수 있도록 노출하는 것
  • shared: 공유되는 의존성 설정

Webpack 예시

공식문서: https://webpack.js.org/concepts/module-federation/

webpack.config.js

// remote
new ModuleFederationPlugin({
  name: "appA",
  filename: "remoteEntry.js",
  exposes: {
    "./Button": "./src/Button",
  },
  shared: ["react", "react-dom"],
}),
 
 
// host
new ModuleFederationPlugin({
  name: "appB",
  remotes: {
    appA: "appA@http://localhost:3001/remoteEntry.js",
  },
  shared: ["react", "react-dom"],
}),

공유된 모듈 사용

import Button from 'appA/Button';
 
const Button = React.lazy(() => import('appA/Button')); // dynamic import

⚠️주의사항
런타임에서 모듈을 동적으로 로드해야 하기 때문에 dynamic import를 사용해야 한다. 일반 import를 사용한다면 Webpack이 빌드 시점에 모듈을 찾으려고 시도하기 때문에 에러가 발생할 수 있다.

profile
프론트엔드 개발자

0개의 댓글