ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Module federation이란
    Web 2022. 1. 30. 10:54

    Module federation과 마이크로 프론트엔드(micro frontend)에 대한 기본적인 개념과 적용 방법을 습득하실 수 있도록 구성했습니다.

     

     

    시작하며

    Module federation는 마이크로 프론트엔드를 이루기 위한 수단입니다. 그러므로 module federation을 알아보기 전에 마이크로 프론트엔드의 개념을 먼저 알아보도록 합니다.

    마이크로 프론트엔드란

    아래는 마이크로 프론트엔드가 적용되지 않은 예시입니다. 백엔드에는 micro service architecture (MSA)가 적용되어 각 기능 조직, 페이지 별로 자체적으로 개발, 빌드, 배포할 수 있습니다. 하지만 프론트엔드는 하나의 거대한 모노리틱 프로젝트로 운영되기에 서비스 A와 연관된 프론트엔드 컴포넌트가 수정될 경우 전체 프론트엔드 프로젝트를 다시 배포해야 합니다. 이는 빌드와 배포 과정에 드는 비용을 늘리고 더 나아가서는 개발 효율을 떨어트립니다.

    서버단 MSA만 적용 된 모노리틱 프론트엔드 프로젝트

     

     

    아래는 위와 같은 백엔드 구성에 마이크로 프론트엔드가 적용된 예시입니다. 각 개발팀에서 각자가 담당하는 기능에 대한 백엔드와 프론트엔드를 모두 구현합니다. 이렇게 구현된 프론트엔드 모듈은 프론트엔드를 총괄하는 팀이 관리하는 Application Shell에 들어가서 사용자에게 보여집니다. 여기서 중요한 포인트는 하나의 모듈이 다시 빌드되어 배포되어도 Application Shell에는 영향을 끼치지 않는다는 점입니다. (Shell은 껍데기라는 의미로 여러 마이크로 프론트엔드 프로젝트를 모아서 보여주는 하나의 프론트엔드 프로젝트입니다, 더 자세한 개념은 마틴 파울러의 글을 참고하시면 좋습니다)

    마이크로 프론트엔드까지 적용된 프로젝트

    두 사진의 출처

     

    React로 마이크로 프론트 엔드 구축

    최근에는 "마이크로 프론트 엔드"라는 용어가 기술의 주류가되었습니다. 이 패턴을 옹호하는 사람들은 마이크로 프런트 엔드가 마이크로 서비스가 백엔드에 제공하는 것과 동일한 자유를 프런

    ichi.pro

     

     

    마이크로 프론트엔드로 무얼 할 수 있나

    • 각 페이지별로 다른 프로젝트의 빌드 파일을 이용하여 사용자에게 제공할 수 있습니다. 
    • 라이브러리만 노출하는 하나의 프로젝트를 만들어서 여러 프로젝트에서 사용할 수 있습니다.
      • 이를 통해 의존성 버전 관리를 한곳에서 할 수 있습니다.

     

    장점

    • 프론트엔드부터 백엔드까지 하나의 기능에 대해 한 팀에서 개발할 수 있습니다.
      • 예를 들면, 마이크로 프론트엔드와 MSA로 구성된 환경에서 배너 광고에 대한 기능의 프론트엔드와 백엔드를 한 팀에서 구현하고 배너 광고 프론트엔드를 다른 페이지에 끼워넣어 사용자에게 제공합니다.
    • 하나의 큰 프론트엔드 프로젝트가 아니라 작은 여러 개의 프로젝트로 구성됩니다. 
      • 빌드 타임을 줄일 수 있습니다. 
      • 오류에 대한 격리가 가능합니다.
      • 수평적 확장을 효율적으로 할 수 있습니다.
    • 관련 자료

     

    단점

    • 회사의 조직 구조나 개발 방식이 하나의 큰 프로젝트로 이뤄져 있을 경우에는 적용하기 어렵습니다.
    • 여러 개의 프론트엔드 서버를 띄워야 하기에 컴퓨팅 자원을 효율적으로 사용하지 않으면 과금이 많이 될 수 있습니다.

     

    마이크로 프론트엔드 적용 방법

    아래와 같은 5가지 방법이 있습니다. 크게는 서버단에서 html을 달리 랜더링 하기, 빌드할 때에 여러 프로젝트를 합치기, 여러 기술을 사용하여 런타임에 합치기 정도로 나눌 수 있습니다.

     

    • Server-side template composition
    • Build-time integration
    • Run-time via iframes
    • Run-time via JavaScript (번들이라는 단위를 참조합니다)
    • Run-time via web components (웹 컴포넌트 자체가 마이크로 프론트엔드입니다)
    • 참고자료1 (차이가 코드로도 나와있습니다)
    • 참고자료2

    처음 두 방법은 정적이기에 하나의 작은 프로젝트에 수정이 가해질 경우 이를 배포하려면 결국에는 전체 프로젝트를 다시 빌드해야 하므로 마이크로 프론트엔드의 이점을 완벽히 이용할 수 없습니다. 런타임에 합치는 방법은 각각의 프로젝트 별로 개발 및 배포를 가능하게 하지만 사용자 경험과 적용하는 데에 드는 불편함이 있습니다.

    앞으로 소개할 module federation은 웹팩을 사용하기에 위의 방법보다 쉽고 현대적입니다.

     

    본격적으로 알아보기

    공식문서

    개념 

    • 2020년 10월 웹팩5에 추가된 기능입니다.
    • 컴포넌트나 서비스 단위의 앱 요소를 각각 빌드하고 노출하여 이를 다른 앱에서 불러와 사용할 수 있도록 합니다.
    • 즉 하나의 앱에서 다른 빌드에 있는 코드를 동적으로 실행할 수 있습니다.
    • 위의 동적 실행은 한 방향이 아니라 양방향으로도 가능합니다.
    • 참고 문서

     

    용어 설명

    • 앱(App) : 개발, 빌드, 배포하는 리액트 애플리케이션
    • 호스트(Host) : module federation을 통해 다른 앱을 동적으로 사용하는 앱
      • 예) Shell은 다른 앱을 사용하기에 호스트로 볼 수 있습니다.
    • 리모트(Remote) : module federation을 통해 노출되는 앱
      • 예) Shell에서 사용되는 모듈은 리모트입니다. (상단 예시 이미지에서 Module A~D) 
    • 단방향 : 호스트 앱에서 리모트 앱의 컴포넌트를 사용
    • 양방향 : 호스트 앱이건 리모트 앱이건 서로의 컴포넌트를 사용
    • Expose : 리모트 앱이 노출할 리액트 컴포넌트(JS 파일)나 라이브러리

     

    예시 프로젝트 둘러보기

    Module federation에서 공식적으로 제공하는 레포지토리를 둘러봅니다.

    기본 예시 (basic-host-remote)

    호스트 앱 (코드 출처)

    // ... webpack.config.js
    
    const { ModuleFederationPlugin } = require('webpack').container;
    
    // ...
    
    plugins: [
        new ModuleFederationPlugin({
          name: 'app1', // 호스트 앱의 이름
          remotes: {
            app2: "app2@http://localhost:3002", // 사용할 리모트 앱의 이름과 
          },
          shared: { react: { singleton: true }, 'react-dom': { singleton: true } }, // 공유하는 라이브러리 옵션 (공식 문서에서 자세한 내용을 확인하세요)
        }),
        new HtmlWebpackPlugin({
          template: './public/index.html',
        }),
      ],
      
    // ... webpack.config.js
    import React from 'react';
    
    const RemoteButton = React.lazy(() => import('app2/Button')); // lazy 로딩
    
    const App = () => (
      <div>
        <h1>Basic Host-Remote</h1>
        <h2>App 1</h2>
        <React.Suspense fallback="Loading Button">
          {/* 리모트 앱에서 노출한 컴포넌트 사용 */}
          <RemoteButton />
        </React.Suspense>
      </div>
    );
    
    export default App;

    리모트 앱 (코드 출처)

    // ... webpack.config.js
    
    const { ModuleFederationPlugin } = require('webpack').container;
    
    // ...
    
    plugins: [
        new ModuleFederationPlugin({
          name: 'app2', // 리모트 앱 이름
          library: { type: 'var', name: 'app2' },
          filename: 'remoteEntry.js', // 리모트 앱이 노출할 번들의 이름
          exposes: {
            './Button': './src/Button', // 리모트 앱이 노출할 컴포넌트의 이름과 프로젝트에서의 위치
          },
          shared: { react: { singleton: true }, 'react-dom': { singleton: true } }, // 공유 라이브러리
        }),
        new HtmlWebpackPlugin({
          template: './public/index.html',
        }),
      ],
      
    // ... webpack.config.js

     

    프로젝트를 클론 받고 아래의 순서대로 구동해봅니다.

    • 각 앱의 App.js 파일을 확인합니다.
    • 각 앱의 webpack.config.js 파일을 확인합니다.
    • 리모트 앱(app2)만 구동해봅니다.
    • 호스트 앱(app1)도 구동해봅니다.
    • 리모트 앱의 반영사항이 호스트 앱에 적용되는지 확인합니다.
    • 리모트 앱을 종료한 후 호스트 앱의 동작을 살펴봅니다.

     

    Typescript 예시 (typescript)

    • 기본 예제와 동일한 구성이지만 typescript의 특성상 리모트 앱에서 가져오는 컴포넌트에 대한 모듈 정의를 해줘야 합니다.(모듈 정의 코드)

     

    복합 리액트 예시 (complete-react-case)

    • 메인 호스트 앱, 컴포넌트 제공 앱, 라이브러리 제공 앱으로 구분된 프로젝트를 확인할 수 있습니다.
    • 초반에 설명한 "라이브러리만 노출하는 프로젝트"의 예시를 확인할 수 있습니다.

     

    라우팅 예시 (shared-routing)

    • Shell 어플리케이션에 여러 다른 페이지를 가져와서 사용합니다.
    • react-router-dom을 사용하여 라우팅 합니다 (예시 코드)

     

    양방향 예시 (bi-directional)

    • app1에서 app2를 사용하고 app2에서도 app1을 사용합니다.

     

    정리하기

    분산되어 있는 여러 서비스를 하나의 서비스에 모으는 작업을 진행하고 있습니다. 이를 위해 마이크로 프론트엔드를 알아보고 적용해보다가 module federation까지 알게 되었습니다. Shell로 사용하는 프로젝트 하나와 내부에서 사용할 프로젝트 2개를 개발 중이며 추후에는 다른 서비스를 마이그레이션 할 예정입니다. 현재까지는 일반적인 마이크로 프론트엔드의 장점을 취하며 큰 무리 없이 개발하고 있습니다. 사용하며 느낀 단점은 shell에서 장애가 났을 경우에 원인을 찾기 쉽지 않다는 점입니다. 이는 아무래도 에러의 발생 가능 부분이 호스트 앱, 리모트 앱, 모듈 페더레이션 설정과 같이 퍼져있기 때문입니다. 또한 비교적 최신 기술이고 필수적인 기술이 아니다 보니 트러블 슈팅에 대한 레퍼런스 찾기가 쉽지 않다는 점입니다. 하지만 본문에 첨부한 공식 예제가 올라온 레포지토리의 이슈 페이지에서 유익한 글을 많이 찾을 수 있기에 무서워하지 않으셔도 됩니다. 제작자는 소통을 활발하게 하고 웹팩의 공식 지원까지 받으니 라이브러리에 대한 지원이 끊길 걱정은 안 하셔도 될 것 같습니다. 모쪼록 module federation을 알아보고 계시거나 적용하고 싶으신 분들께 도움이 되길 바랍니다.

    감사합니다!

    'Web' 카테고리의 다른 글

    Meta Tag & Open Graph Tag & Google Analytics 리액트에 적용하기  (0) 2020.08.13
    Endpoint란  (9) 2020.07.13

    댓글

Toneyparky Blog