Nx 및 React를 사용한 동적 마이크로 프런트엔드

프로젝트에 많은 팀이 있는 경우, 동적 프런트엔드 확장이 필요한 경우 및 전체 프로젝트의 재구축이 옵션이 아닌 경우 Micro Frontends의 개념이 Dynamic Module Federation와 함께 작동합니다.

Nx에는 이 주제에 대한 훌륭한 자습서angular stack가 있습니다. react 스택에 대해 이 개념을 구현해 봅시다.

Nx 설명서는 다음과 같이 말합니다.

Nx is a smart, fast and extensible build system with first class monorepo support and powerful integrations.



이제 실제로 확인하고 여러 응용 프로그램과 도우미 라이브러리를 생성합니다.

Nx 작업 공간 만들기



Nx 작업 영역을 만들려면 다음 명령을 실행합니다.

npx create-nx-workspace@latest


이름과 유형( apps )을 선택하면 Nx Cloud를 연결하지 않은 상태로 둘 수 있습니다.

호스트 앱 및 하위 앱 생성



개발 종속성으로 플러그인@nrwl/react을 설치합니다. Nx 작업 공간 내에서 React 앱과 라이브러리를 쉽게 관리할 수 있는 편리한 생성기와 유틸리티를 제공합니다.

npm install -D @nrwl/react


호스트 앱 및 마이크로 프런트엔드 만들기:

npx nx g @nrwl/react:host host --remotes=cart,blog,shop


애플리케이션에서 필요한 스타일링 설정을 선택하고 생성이 끝날 때까지 기다립니다.

마이크로 프런트엔드를 쉽게 등록하고 가져오기 위한 라이브러리 만들기



URL로 마이크로 프런트엔드를 동적으로 가져오려면 이를 도와줄 라이브러리를 만들어야 합니다. 이를 위해 @nrwl/js 제너레이터를 사용하여 라이브러리를 생성하고 load-remote-module라고 합니다.

npx nx g @nrwl/js:library load-remote-module


새로 생성된 라이브러리/libs/load-remote-module/src/lib/load-remote-module.ts에 코드를 추가해 보겠습니다.

export type ResolveRemoteUrlFunction = (
  remoteName: string
) => string | Promise<string>;

declare const __webpack_init_sharing__: (scope: 'default') => Promise<void>;
declare const __webpack_share_scopes__: { default: unknown };

let resolveRemoteUrl: ResolveRemoteUrlFunction;

export function setRemoteUrlResolver(
  _resolveRemoteUrl: ResolveRemoteUrlFunction
) {
  resolveRemoteUrl = _resolveRemoteUrl;
}

let remoteUrlDefinitions: Record<string, string>;

export function setRemoteDefinitions(definitions: Record<string, string>) {
  remoteUrlDefinitions = definitions;
}

let remoteModuleMap = new Map<string, unknown>();
let remoteContainerMap = new Map<string, unknown>();

export async function loadRemoteModule(remoteName: string, moduleName: string) {
  const remoteModuleKey = `${remoteName}:${moduleName}`;
  if (remoteModuleMap.has(remoteModuleKey)) {
    return remoteModuleMap.get(remoteModuleKey);
  }

  const container = remoteContainerMap.has(remoteName)
    ? remoteContainerMap.get(remoteName)
    : await loadRemoteContainer(remoteName);

  const factory = await container.get(moduleName);
  const Module = factory();

  remoteModuleMap.set(remoteModuleKey, Module);

  return Module;
}

function loadModule(url: string) {
  return import(/* webpackIgnore:true */ url);
}

let initialSharingScopeCreated = false;

async function loadRemoteContainer(remoteName: string) {
  if (!resolveRemoteUrl && !remoteUrlDefinitions) {
    throw new Error(
      'Call setRemoteDefinitions or setRemoteUrlResolver to allow Dynamic Federation to find the remote apps correctly.'
    );
  }

  if (!initialSharingScopeCreated) {
    initialSharingScopeCreated = true;
    await __webpack_init_sharing__('default');
  }

  const remoteUrl = remoteUrlDefinitions
    ? remoteUrlDefinitions[remoteName]
    : await resolveRemoteUrl(remoteName);

  const containerUrl = `${remoteUrl}${
    remoteUrl.endsWith('/') ? '' : '/'
  }remoteEntry.js`;

  const container = await loadModule(containerUrl);
  await container.init(__webpack_share_scopes__.default);

  remoteContainerMap.set(remoteName, container);
  return container;
}


이 코드는 angular 에 대한 Nx 플러그인의 코드를 기반으로 합니다.

호스트 애플리케이션load-remote-module/apps/host/webpack.config.js 라이브러리를 등록합니다.

const withModuleFederation = require('@nrwl/react/module-federation');
const moduleFederationConfig = require('./module-federation.config');

const coreLibraries = new Set([
  'react',
  'react-dom',
  'react-router-dom',
  '@microfrontends/load-remote-module',
]);

module.exports = withModuleFederation({
  ...moduleFederationConfig,
  shared: (libraryName, defaultConfig) => {
    if (coreLibraries.has(libraryName)) {
      return {
        ...defaultConfig,
        eager: true,
      };
    }

    // Returning false means the library is not shared.
    return false;
  },
});


오류를 방지하려면 등록이 필요합니다: Uncaught Error: Shared module is not available for eager consumption .

마이크로 프런트엔드 구성 및 연결



마이크로 프런트엔드에 대한 링크 목록을 JSON 파일 형식으로 저장해 보겠습니다. 이것은 런타임에 호스트 앱 측에서 링크 목록을 가져오는 가장 쉬운 방법 중 하나이며 남은 것은 GET 요청을 만드는 것입니다. 앞으로는 이러한 목적으로 서버 API를 사용할 수 있습니다.

폴더module-federation.manifest.json에 파일/apps/host/src/assets/module-federation.manifest.json을 만듭니다.

{
  "cart": "http://localhost:4201",
  "blog": "http://localhost:4202",
  "shop": "http://localhost:4203"
}


열기/apps/host/src/main.ts 및 변경 대상:

import { setRemoteDefinitions } from '@microfrontends/load-remote-module';
import('./bootstrap');

fetch('/assets/module-federation.manifest.json')
  .then((res) => res.json())
  .then((definitions) => setRemoteDefinitions(definitions))
  .then(() => import('./bootstrap').catch((err) => console.error(err)));


보시다시피 우리는:
  • JSON 파일 가져오기
  • 내용이 있는 setRemoteDefinitions 호출
  • 이를 통해 webpack은 마이크로 프런트엔드가 배포된 위치를 이해할 수 있습니다
  • .

    호스트 앱에서 마이크로 프런트엔드를 로드하는 방법을 동적으로 변경합니다.



    현재 웹팩은 /apps/host/module-federation.config.js 구성 파일에 지정된 대로 빌드 단계 중에 마이크로 프런트엔드가 있는 위치를 결정합니다.

    host-app 폴더module-federation.config.js에 있는 /apps/host/module-federation.config.js 를 열고 remotes 값을 빈 배열로 설정하여 웹팩이 빌드할 때 모듈을 찾지 않도록 합니다. 다음과 같이 표시됩니다.

    module.exports = {
      name: 'host',
      remotes: [],
    };
    


    다음으로 마이크로 프런트엔드가 호스트 앱에 로드되는 방식을 변경해야 합니다. 파일/apps/host/src/app/app.tsx을 열고 가져오기 코드를 다음으로 바꿉니다.

    import { loadRemoteModule } from '@microfrontends/load-remote-module';
    
    const Cart = React.lazy(() => loadRemoteModule('cart', './Module'));
    
    const Blog = React.lazy(() => loadRemoteModule('blog', './Module'));
    
    const Shop = React.lazy(() => loadRemoteModule('shop', './Module'));
    

    Static Module FederationDynamic Module Federation 로 바꾸는 데 필요한 전부입니다.

    서빙 및 확인



    호스트 앱 및 마이크로 프런트엔드를 제공하려면:

    npm run start
    


    또는 모든 앱의 병렬 시작:

    nx run-many --parallel --target=serve --projects=host,cart,blog,shop --maxParallel=100
    

    localhost:4200를 열고 마이크로 프런트엔드 Dynamic Module Federation이 작동하는 것을 확인합니다.
  • 구성이 module-federation.manifest.json 요청
  • 을 통해 GET에서 가져오고 있습니다.
  • 응용 프로그램 중 하나를 제거하면 브라우저에 오류가 표시됩니다
  • .
  • 추가 마이크로 프런트엔드를 추가할 수 있습니다
  • .



    GitHub 저장소 - dynamic-micro-frontends-with-Nx-and-react .

    추가 정보:
  • dynamic-module-federation-with-angular
  • Monorepos in JavaScript & TypeScript
  • Nx docs

  • load-remote-module 라이브러리에 대한 도움을 주신 ScorIL에게 큰 감사를 드립니다.

    좋은 웹페이지 즐겨찾기