vite + @origin/vite-plugin-federation를 이용한 module-federation 도입기 - turbo monorepo 공용 패키지 share하기

Jung Wish·2024년 3월 20일
1

오늘의_코딩

목록 보기
9/11

TL;DR

  • 공용 패키지는 패키지 경로 또는 package version(workspace:*)을 명시해주어야 사용할 수 있다.
import pkg from "./package.json";
...
shared: [
    'react',
    'react-dom',
    'zustand',
    'react-error-boundary',
    '@tanstack/react-query',
    { '@sm/ui': { version: pkg.dependencies['@sm/ui'] } },
    { '@sm/util': { version: pkg.dependencies['@sm/util'] } },
  // or
	{
      '@sm/ui': {
        packagePath: '../../packages/ui/',
       },
      '@sm/util': {
        packagePath: '../../packages/util/',
      },
    },
]

문제 상황

module federation 작업중에 생긴 문제들이나 구현 방법등을 기록하는 시리즈를 써보고자 한다.(나는야 콘텐츠에 미친 사람..)

  • 저번주에 첫 세팅을 진행하면서 겪은 문제중 하나인데 shared라는 설정에서 발생했다.
  • 보통 module federation 설정을 할때 공용 패키지(shared)를 설정할 수 있는데 쉽게 말해 host단에 있는 패키지를 재사용하는 것으로, remote에서 build할때 해당 패키지를 포함하지 않아 빌드 용량면에서나 재사용성 측면에서 장점이 있다.
  • 문제가 발생한 지점은 정확히 turbo monorepo에서 사용하는 packages/* 내부의 공용 패키지와 관련된 것이었다.
    • @origin/vite-plugin-federation은 특별한 설정이 없어도 host app과 remote app에 공유하고자 하는 패키지들은 배열 형태로 명시만 해줘도 일반적인 패키지(=monorepo에서 workspace 형태로 사용하는 패키지말고 npm에서 install해서 사용하는 것들)들은 얼추 잘 동작한다. (물론 패키지 버전 문제가 크게 없다는 가정하에..!)

문제 해결

  • 사실 오류에서 해결 방법을 명시해주고 있긴하다.
    • Add version to description file, or manually specify version in shared config.
    • 버전 파일을 인식할 수 없으니 추가적으로 config에 명시해달라는 것이다.
// host
const federationConfig = env => ({
  name: 'container',
  remotes: {
    qm: {
      external: `${env?.['WORKSPACE_QM_URL']}/qm/v2/assets/remoteEntry.js`,
      from: 'vite',
    },
    dc: {
      external: `${env?.['WORKSPACE_DC_URL']}/dc/v2/assets/remoteEntry.js`,
      from: 'vite',
    }
  },
  shared: [
    'react',
    'react-dom',
    'react-error-boundary',
    'zustand',
    '@tanstack/react-query',
    { '@sm/ui': { version: pkg.dependencies['@sm/ui'] } },
    { '@sm/util': { version: pkg.dependencies['@sm/util'] } },
  ],
});

// remote
export const mfConfig = {
  name: 'dc',
  filename: 'remoteEntry.js',
  // Modules to expose
  exposes: {
    './app': './src/app.tsx',
    './useStore': './src/stores/global.ts',
  },
  shared: ['react', 'react-dom', 'zustand', '@sm/ui', '@sm/util'],
};
  • 사실 처음에는 오류 메세지 끝까지 안읽고 혼자 고민하다가, npm workspace라는 개념을 도입하기 전에 배포되지 않은 local package를 가져올 때 dependencies에 해당 패키지의 상대경로를 적어줬던 것이 생각나서 package의 경로 설정을 해줬더니 이 또한 잘 동작했다. 엄밀히 따지면 workspace:*도 결국엔 경로를 제공해주는 것일테니(뇌피셜..) 같은 설정이라 봐도 되지 않을까...?
    • 다만 상대 경로로 표시하게 될 경우 첫 번째 케이스보다 안좋은 점은 경로가 바뀌었을때 계속 config file의 경로도 수정을 해줘야 한다는 점이 있다.
// host
const federationConfig = env => ({
  name: 'container',
  remotes: {
    qm: {
      external: `${env?.['WORKSPACE_QM_URL']}/qm/v2/assets/remoteEntry.js`,
      from: 'vite',
    },
    dc: {
      external: `${env?.['WORKSPACE_DC_URL']}/dc/v2/assets/remoteEntry.js`,
      from: 'vite',
    }
  },
  shared: [
    'react',
    'react-dom',
    'react-error-boundary',
    'zustand',
    '@tanstack/react-query',
    {
      '@sm/ui': {
        packagePath: '../../packages/ui/',
       },
      '@sm/util': {
        packagePath: '../../packages/util/',
      },
    },
  ],
});

// remote
export const mfConfig = {
  name: 'dc',
  filename: 'remoteEntry.js',
  // Modules to expose
  exposes: {
    './app': './src/app.tsx',
    './useStore': './src/stores/global.ts',
  },
  shared: ['react', 'react-dom', 'zustand', '@sm/ui', '@sm/util'],
};
profile
Frontend Developer, 올라운더가 되고싶은 잡부 개발자, ISTP, 겉촉속바 인간, 블로그 주제 찾아다니는 사람

0개의 댓글