1. Flight 및 Hotel 모듈 개요
Flight 및 Hotel 모듈은 각각 비행 시간 예약과 호텔 예약 기능을 제공하는 독립적인 애플리케이션으로, 이 두 모듈은 NextPederationPlugin을 사용하여 통합 애플리케이션인 app-front에 연동됩니다. 이 글에서는 각 모듈의 구성과 설정 방법을 단계별로 살펴보겠습니다.
2. Flight 모듈 구성
1. `package.json` 및 주요 스크립트
`package.json` 파일은 다음과 같이 구성됩니다:
{
"name": "amu-front-flight",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "rm -rf .next && SET NEXT_PRIVATE_LOCAL_WEBPACK=true && next dev -p 3011",
"build": "SET NEXT_PRIVATE_LOCAL_WEBPACK=true && next build"
},
"dependencies": {
"next": "^12.0.7",
"react": "^17.0.2",
"react-dom": "^17.0.2"
},
"devDependencies": {
"typescript": "^4.5.2",
"webpack": "^5.58.2"
}
}
- dev: 개발 서버를 실행합니다. `NEXT_PRIVATE_LOCAL_WEBPACK` 환경 변수를 설정하여 Webpack을 로컬에서 실행합니다.
- build: 빌드 명령어로, `NEXT_PRIVATE_LOCAL_WEBPACK` 환경 변수를 설정하여 빌드를 수행합니다.
2. `next.config.js` 파일 설정 및 NextFederationPlugin 사용법
`next.config.js` 파일은 다음과 같이 구성됩니다:
const NextFederationPlugin = require('@module-federation/nextjs-mf');
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
compiler: {
styledComponents: true,
},
eslint: {
ignoreDuringBuilds: true,
},
webpack(config, options) {
config.resolve.alias.canvas = false;
const url = 'http://localhost:3011';
const location = options.isServer ? 'ssr' : 'chunks';
config.plugins.push(
new NextFederationPlugin({
name: 'flight',
filename: 'static/chunks/remoteEntry.js',
remotes: {
container: `container@${url}/_next/static/${location}/remoteEntry.js`,
},
exposes: {
'./home': './src/pages/flight/index.tsx',
'./search': './src/pages/flight/search/index.tsx',
'./flightSearch': './src/components/FlightSearch/index.tsx',
},
shared: {
'styled-components': { eager: true, singleton: true },
'@tanstack/react-query': { eager: true, singleton: true },
dayjs: { eager: true, singleton: true },
'@amu/amu-ui-system': { eager: true, singleton: true },
'next/image': { eager: true, singleton: true },
},
})
);
return config;
},
images: {
domains: ['*', 'cdn.domain.net'],
formats: ['image/webp'],
dangerouslyAllowSVG: true,
},
};
module.exports = nextConfig;
NextFederationPlugin 플러그인은 모듈 연동을 위해 설정됩니다.
- name: 현재 모듈의 이름.
- filename: 원격 엔트리 파일의 이름.
- remotes: 원격 모듈의 URL 설정.
- exposes: 현재 모듈에서 제공하는 컴포넌트 경로.
- shared: 공유 모듈 설정.
3. Flight 모듈의 파일 및 폴더 구조
/flight
├── .next
├── node_modules
├── public
└── src
├── components
│ └── FlightSearch
│ └── index.tsx
├── pages
│ ├── flight
│ │ ├── search
│ │ │ └── index.tsx
│ │ └── index.tsx
│ ├── _app.tsx
│ └── _document.tsx
├── styles
│ └── globalStyle.ts
├── types
│ └── common.ts
├── utils
│ └── server.ts
└── remoteType.d.ts
├── env.development
├── next.config.js
├── package.json
└── tsconfig.json
4. `FlightSearch` 컴포넌트와 서버 사이드 렌더링 설정**
// src/components/FlightSearch/index.tsx
import React from 'react';
const FlightSearch = () => {
return <div>Flight Search Component</div>;
};
export default FlightSearch;
// src/pages/flight/index.tsx
import Head from 'next/head';
import { Button } from '@amu/amu-ui-system';
import { useRouter } from 'next/router';
import { PageProps } from 'types/common';
import { makeGetServerSideProps } from 'utils/server';
import FlightSearch from 'components/FlightSearch';
import styled from 'styled-components';
export default function Home({ isMobile }: PageProps) {
const router = useRouter();
return (
<>
<Head>
<title>Flight Home</title>
</Head>
<ButtonWrapper>
<Button>Search Flights</Button>
</ButtonWrapper>
<FlightSearch />
</>
);
}
const ButtonWrapper = styled.div`
margin-bottom: 20px;
`;
export const getServerSideProps = makeGetServerSideProps();
3. Hotel 모듈 구성
1. `package.json` 및 주요 스크립트
`package.json` 파일은 `flight` 모듈과 유사하게 구성됩니다. 다만, `name`과 포트 번호가 다릅니다:
{
"name": "amu-front-hotel",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "rm -rf .next && SET NEXT_PRIVATE_LOCAL_WEBPACK=true && next dev -p 3012",
"build": "SET NEXT_PRIVATE_LOCAL_WEBPACK=true && next build"
},
"dependencies": {
"next": "^12.0.7",
"react": "^17.0.2",
"react-dom": "^17.0.2"
},
"devDependencies": {
"typescript": "^4.5.2",
"webpack": "^5.58.2"
}
}
2. `next.config.js` 파일 설정
`next.config.js` 파일은 `flight` 모듈과 거의 동일합니다. 주요 차이점은 `exposes` 부분입니다:
const NextFederationPlugin = require('@module-federation/nextjs-mf');
const nextConfig = {
reactStrictMode: true,
compiler: {
styledComponents: true,
},
eslint: {
ignoreDuringBuilds: true,
},
webpack(config, options) {
config.resolve.alias.canvas = false;
const url = 'http://localhost:3012';
const location = options.isServer ? 'ssr' : 'chunks';
config.plugins.push(
new NextFederationPlugin({
name: 'hotel',
filename: 'static/chunks/remoteEntry.js',
remotes: {
container: `container@${url}/_next/static/${location}/remoteEntry.js`,
},
exposes: {
'./home': './src/pages/hotel/index.tsx',
'./search': './src/pages/hotel/search/index.tsx',
'./hotelSearch': './src/components/HotelSearch/index.tsx',
},
shared: {
'styled-components': { eager: true, singleton: true },
'@tanstack/react-query': { eager: true, singleton: true },
dayjs: { eager: true, singleton: true },
'@amu/amu-ui-system': { eager: true, singleton: true },
'next/image': { eager: true, singleton: true },
},
})
);
return config;
},
images: {
domains: ['*', 'cdn.domain.net'],
formats: ['image/webp'],
dangerouslyAllowSVG: true,
},
};
module.exports = nextConfig;
3. Hotel 모듈의 파일 및 폴더 구조
`flight` 모듈과 유사한 구조를 따릅니다.
4. `HotelSearch` 컴포넌트와 서버 사이드 렌더링 설정
// src/components/HotelSearch/index.tsx
import React from 'react';
const HotelSearch = () => {
return <div>Hotel Search Component</div>;
};
export default HotelSearch;
// src/pages/hotel/index.tsx
import Head from 'next/head';
import { Button } from '@amu/amu-ui-system';
import { useRouter } from 'next/router';
import { PageProps } from 'types/common';
import { makeGetServerSideProps } from 'utils/server';
import HotelSearch from 'components/HotelSearch';
import styled from 'styled-components';
export default function Home({ isMobile }: PageProps) {
const router = useRouter();
return (
<>
<Head>
<title>Hotel Home</title>
</Head>
<ButtonWrapper>
<Button>Search Hotels</Button>
</ButtonWrapper>
<HotelSearch />
</>
);
}
const ButtonWrapper = styled.div`
margin-bottom: 20px;
`;
export const getServerSideProps = makeGetServerSideProps();
5. 모바일 디바이스 대응 방법
서버 사이드 렌더링 시 모바일 디바이스를 감지하여 적절한 UI를 제공할 수 있습니다. 이를 위해 `server.ts` 파일에 다음과 같은 함수를 정의합니다:
// src/utils/server.ts
import { GetServerSidePropsContext } from 'next';
export const checkMobileDevice = (context: GetServerSidePropsContext) => {
return Boolean(context?.req?.headers['user-agent']?.includes('Mobi'));
};
export const makeGetServerSideProps = () => (context: GetServerSidePropsContext) => {
const isMobile = checkMobileDevice(context);
return {
props: {
isMobile,
},
};
};
이 함수는 `getServerSideProps`를 사용하여 서버 사이드에서 모바일 디바이스 여부를 확인하고, 이를 컴포넌트에 전달합니다.
결론
이 글에서는 Flight 및 Hotel 모듈 애플리케이션을 구성하고 설정하는 방법을 다루었습니다. 각 모듈은 독립적으로 개발되어, NextPederationPlugin을 통해 연동됩니다. 다음 글에서는 이 두 개의 애플리케이션과 지난 시간에 만든 UI 시스템 패키지를 app-front 애플리케이셔너에 구성하고, 이 모듈들을 통합하는 방법을 알아보겠습니다. 이를 통해 최종적으로 완성된 통합 애플리케이션을 구축해 보겠습니다.