Development Environment

Webpack의 Module Federation 동작 흐름 그리고 Dynamic import

남희정 2024. 11. 23. 17:48

📌 목차

Webpack의 Module Federation. 해당 주제가 모오던 웹 개발 아키텍처 관련 글에서 눈에 띄었는데 궁금해져서 공부해보고 싶었다. 나의 이전 번들러 글을 좋아하신 분들이라면 또 반가운 주제일 수 있겠다.

 

2024.08.10 - [Development Environment] - Why Vite? JS 모듈화의 역사, CJS, ESM, Webpack

 

What is the Module Federation?

Webpack은 js 모듈의 의존 관계를 파악하고 실행할 때 필요한 모듈로 로딩해주는 역할을 한다. 그러나 단일 Webpack 빌드에 포함된 모듈뿐만 아니라 여러 서버에 배포되어 있는 원격 모듈을(Webpack에서의 Chunk) 하나의 앱에서 로딩할 수 있는 기능이다.

 

Zack Jackson이 이 개념의 창시자이다. Apollo GraphQL Federation개념을 JS 모듈에 적용한 것이라고.

 

 

Webpack Module Federation 용어 정리

Module

Webpack에서 module이라고 하는 것은 Webpack으로 빌드할 때 사용하는 코드를 포함한 모든 리소스를 말한다. JS, CSS, HTML, JSON, 이미지 파일 등. Module Federation을 말할 때 module은 Javascript module을 의미한다. 하지만 CSS, JSON 등의 다른 타입 리소스들도 js module로 번들링할 수 있기 때문에 다른 타입의 리소스도 모듈이라 할 수 있다.

웹팩에서의 Module Federation 파트를 들여다보면 Local module, Remote module이 등장한다. 해당 개념을 먼저 익혀보자.

Local module 단일 웹팩 빌드에 포함되는 모듈이다. 서로 다른 Webpack 빌드의 결과물은 서로 다른 로컬 모듈이다. 로컬 모듈은 단일 빌드 안에서만 로딩할 수 있다.

Remote module

다른 웹팩 빌드에서 만든 모듈을 대상으로 런타임에 로딩할 수 있는 모듈을 말한다. 즉 A 빌드와 B 빌드의 결과물은 서로 원격 모듈이 될 수 있다. 각 빌드는 개별 서버에 배포될 수 있으며 런타임에 *Dynamic Imports하듯이 원격 모듈을 로딩할 수 있다.

 

Dynamic imports : 코드 실행 중에 필요할 때 모듈을 동적으로 불러오는 것. 모듈을 별도의 Chunk로 분리해서 요청이 있을 때만 로딩할 수 있게 해준다.

Container

각각의 빌드를 말하며 하나의 빌드가 하나의 웹 애플리케이션을 나타낸다. A 컨테이너는 B 컨테이너의 원격 모듈을 로딩할 수 있고 B에서 A 방향으로도 로딩할 수 있다.

Expose

웹팩의 Expose로 원격 모듈의 목록을 설정한다. 내보낼 모듈 이름 : 로컬 모듈 경로 로 표현할 수 있다.

 

new ModuleFederationPlugin({
  name: "app2",
  exposes: {
    "./Button": "./src/Button",
  },
});

 

app2라는 컨테이너는 로컬 모듈 "./src/Button" 을 "./Button"이라는 이름의 원격 모듈로 Expose(노출)한다는 의미다. 

 

https://medium.com/frontend-for-everyone/module-federation-clearly-explained-with-a-simple-example-5aa761bfef8c

 

왜 필요한 걸까?

Motivation
여러 개의 개별 빌드가 단일 애플리케이션을 형성해야 한다. 이 구분된 빌드들은 전부 컨테이너처럼 작동한다,. 그리고 서로 간에 코드를 노출하고 소비하며 하나의 통합된 애플리케이션을 만들 수 있게 된다.

- Webpack Module Federation 중

 

여러 개의 애플리케이션을 따로 빌드한 다음 런타임에 통합하여 하나의 애플리케이션으로 동작하게 한다는 멋진 기능…!

⇒ 웹팩의 설정만으로 가능하게 되었다.

 

점점 서비스 규모가 커질수록 작은 변경에도 영향 범위가 커질 수 있으며 영향 범위 예측도 점점 복잡하고 어려워진다. Module Federation은 컨테이너 빌드를 따로 하므로 빌드 시간, 영향 범위, 로딩 시간 측면에서 유리하다.

 

빌드 범위와 배포 시간 변경된 컨테이너만 빌드하고 배포해서 시간이 줄어든다.

영향도 변경 영향이 해당 컨테이너에 국한되므로 검증 범위로 줄어든다.

(단, 원격 모듈의 인터페이스를 변경했다면 호스트 애플리케이션도 검증이 필요하다)

로딩 시간 배포한 컨테이너의 원격 모듈만 새로 로딩하므로 배포 직후 로딩 시간도 상대적으로 짧다.

 

이쯤에서 나는 생각의 늪에 빠졌다

 

Module Federation은 번들러의 이점 중 하나이다. 근데 이전에 공부한 번들러의 작동방식 중에 번들링에서 정적 import로 의존성을 매치하는 단계가 있다. 그 단계 이후에 Module Federation은 동적 import 방식처럼 (nodeJS의 require()처럼) 또 리모트를 한다는건가? 정적 방식과 동적 방식을 전부 쓰는 거네?

 

정적 import 기반으로 동적 import 방식으로 remote module을 로드한다....

정적 Import는 로컬 모듈을 번들링할 때, 동적 Import는 원격 모듈을 런타임에 매칭할 때 사용된다! 

 

  1. 정적 import ⇒ 로컬 모듈 번들링 및 최적화
  2. 동적 import ⇒ 원격 모듈 매칭 및 런타임 로드

 

Module Federation의 전체 동작 과정

빌드할 때와 런타임일 때를 나눠서 보여주려 한다.

build Time (Webpack 설정과 번들링)

1️⃣ Host와 Remote 설정

Remote => 외부에서 접근할 모듈을 exposes로 지정

Host => Remote에서 가져올 모듈을 remotes로 지정

// Remote App
new ModuleFederationPlugin({
  name: 'appB',
  filename: 'remoteEntry.js', 
  exposes: {
    './Button': './src/components/Button', 
  },
});

// Host App
new ModuleFederationPlugin({
  name: 'appA',
  remotes: {
    appB: 'appB@<http://localhost:3001/remoteEntry.js>',
  },
});

 

2️⃣ Webpack이 의존성 분석 및 번들 생성

  • Host, Remote 각각 앱에 대해 Webpack이 정적 import를 분석하고 생성한다.
  • Remote는 remoteEntry.js라는 엔트리 파일을 생성해 노출된 모듈 정보를 포함시킨다.
    => 이 파일을 통해 Host가 런타임에 Remote 모듈에 접근할 수 있도록 도와준다.

RunTime (앱 실행 및 원격 모듈 로드)

1️⃣ Host App 실행

2️⃣ Remote 엔트리 파일 로드(remoteEntry.js)

3️⃣ Host는 네트워크 요청으로 remoteEntry.js 가져오기

4️⃣ Dynamic import로 Remote module 로드
5️⃣ Host가 Remote 모듈을 동적으로 import 요청하면, Webpack이 remoteEntry.js를 참고해 Remote의 노출된 모듈을 로드한다.

 

Button 모듈을 들고 오는 예시.

import('appB/Button').then((module) => {
  const Button = module.default;
  console.log(Button); 
});

 

 


🤓

Webpack에서 제공하는 Module Federation을 넓은 흐름으로 둘러보았다. 여담으로 원래 모오던 웹 개발 아키텍처에 대해 좀 보다가 Module Federation을 둘러보다가 내부에 local module, remote module 개념에 흥미가 생기고 초점이 맞춰졌다. 처음 들여다보는 개념이라 넓게 훑어보는 느낌으로 작성했다. 내부 동작 원리를 상세하게 다루진 못한 것 같아 아쉽다. 추가하려니 너무 길어서 다음 글에서 해당 부분을 좀 깊게 다뤄볼까한다. 이전에 번들링에 대해 들여다보던 부분들이랑 연관이 되면서 굉장히 즐겁게 공부한 것 같다. 

 

로컬 모듈 빌드와 원격 모듈 패치에 고려된 그런 흐름을 공부하다보니 내가 편하게 쓰고 있는 만큼 모두 섬세하게 고려되어있구나를 확실하게 느꼈다.

 

https://pks2974.medium.com/dynamic-import-로웹페이지-성능-올리기-caf62cc8c375

https://fe-developers.kakaoent.com/2022/220623-webpack-module-federation/

https://webpack.kr/concepts/module-federation/

https://yceffort.kr/2020/09/webpack-module-federation

https://dev.to/waldronmatt/module-federation-for-enterprise-part-2-men

https://maxkim-j.github.io/posts/module-federation-concepts/