개발자
류준열
마이크로 프론트엔드끼리의 빌드된 타입 정보 공유
module federation을 통해 remote App을 container App에서 import 하면 타입이 공유되지 않는 현상이 발생힌다.
@module-federation/typescript
를 이용하여 타입이 공유되지 않는 문제를 해결할 수 있다.
프로젝트 구조는 다음과 같다.
// component-app: Button.tsx가 있는 곳
// main-app: component-app의 Button.tsx를 사용하는 container app
ts-example/
│
├── apps/
│ ├── component-app/
│ │ ├── dist/
│ │ ├── node_modules/
│ │ ├── src/
│ │ │ ├── components/
│ │ │ │ └── Button.tsx
│ │ │ ├── App.tsx
│ │ │ ├── index.css
│ │ │ ├── index.html
│ │ │ └── index.ts
│ │ ├── .babelrc
│ │ ├── .gitignore
│ │ ├── compilation.config.js
│ │ ├── package.json
│ │ ├── tsconfig.json
│ │ └── webpack.config.js
│ │
│ ├── main-app/
│ │ ├── node_modules/
│ │ ├── src/
│ │ │ ├── App.tsx
│ │ │ ├── declaration.d.ts
│ │ │ ├── index.css
│ │ │ ├── index.html
│ │ │ └── index.ts
│ │ ├── .babelrc
│ │ ├── .gitignore
│ │ ├── compilation.config.js
│ │ ├── package.json
│ │ ├── tsconfig.json
│ │ └── webpack.config.js
│
├── node_modules/
├── package.json
├── pnpm-lock.yaml
└── pnpm-workspace.yaml
두 앱의 Module federation 세팅 과정은 생략한다.
모노레포가 아닐 때
component-app에서 expose할 타입폴더 만들기
component-app에서 패키지를 설치해준다.
pnpm add @module-federation/typescript
webpack.config.js 수정
기존 /component-app/webpack.config.js
에서 주석친 부분만 추가한다.
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
// 추가
const { FederatedTypesPlugin } = require("@module-federation/typescript");
//
const federationConfig = {
name: "component_app",
filename: "remoteEntry.js",
remotes: {},
exposes: {
"./Button": "./src/components/Button",
},
shared: {
...deps,
react: {
singleton: true,
requiredVersion: deps.react,
},
"react-dom": {
singleton: true,
requiredVersion: deps["react-dom"],
},
},
};
module.exports = (_, argv) => ({
...
plugins: [
new ModuleFederationPlugin(federationConfig),
new FederatedTypesPlugin({ federationConfig }), // 추가
new HtmlWebPackPlugin({
template: "./src/index.html",
}),
],
...
})
빌드 후 생성되는 타입 폴더 확인
위와 같이 webpack.config.js를 수정하고 빌드하면 다음과 같이 dist 내에 @mf-types
가 생성된다.
빌드된 파일을 localhost:3001에 띄우고 /@mf-types
에 접근했을때도 폴더를 확인할 수 있다.
main-app에서 component-app의 타입 사용하기
main-app에서 패키지를 설치해준다.
pnpm add @module-federation/typescript
webpack.config.js 수정
webpack.config.js에서 주석친 부분을 추가해준다.
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
// 추가
const { FederatedTypesPlugin } = require("@module-federation/typescript");
//
const federationConfig = {
name: "main_app",
filename: "remoteEntry.js",
remotes: {
component_app: "component_app@http://localhost:3001/remoteEntry.js",
},
exposes: {},
shared: {
...deps,
react: {
singleton: true,
requiredVersion: deps.react,
},
"react-dom": {
singleton: true,
requiredVersion: deps["react-dom"],
},
},
};
module.exports = (_, argv) => ({
...
plugins: [
new ModuleFederationPlugin(federationConfig),
new FederatedTypesPlugin({ federationConfig }), // 추가
new HtmlWebPackPlugin({
template: "./src/index.html",
}),
],
})
component-app에서 빌드한 타입 파일이 main-app 내부에 생성되는 것 확인
이렇게 main-app의 webpack.config.js를 변경하고 빌드된 component-app을 localhost:3001에 켜놓은 상태로 main-app을 실행하면 main-app 내부에 폴더가 하나 생성되는데 자세히 살펴보면 component-app에서 빌드된 @mf-types 폴더와 동일하다.
빌드된 타입 정보를 두 마이크로 프론트간에 공유할 수 있는 것이다.
tsconfig.json에서 path 설정
마지막으로 tsconfig.json에서 path를 설정해준다. main-app 내부에 생성된 @mf-types의 경로를 지정해주면 된다.
{ "paths": { "*": ["./@mf-types/*"] } }
타입에러가 사라진것을 확인 할 수 있다.
모노레포일때
모노레포일때는 그냥 main-app의 tsconfig.json에서 path를 다음과 같이 설정해주면 된다.
{ "paths": { "component_app/Button": ["../component-app/src/components/Button"] } }