프론트 찍먹해보기 (모노레포)
Monorepo - 하나의 Git 저장소 에서 여러개의 프로젝트를 관리하는 방식을 모노레포라고 한다. - 모노레포는 프론트, 백 모두 사용가능하다.
프로젝트 구성의 발전

모놀리식 애플리케이션
모놀리식 애플리케이션은 모듈화 없이 모든 구성 요소가 한 프로젝트 안에 통합된 소프트웨어 애플리케이션을 이야기합니다.
DB 커넥션을 맺고, 데이터를 요청하며, 화면을 그리는 로직이 한 프로젝트 안에 구현된 초기 웹 서비스를 모놀리식 애플리션으로 볼 수 있다.
**장점** - 소수의 개발자가 빠르게 개발할 수 있음
**단점** - 관심사 분리가 어려워서 설계, 리팩토링이 어려움 - 매번 거대한 프로젝트를 배포해야 함 - 일부분의 에러가 전체 서비스에 영향을 줄 수 있음
멀티레포 멀티레포는 폴리레포(Polyrepo)라고도 불린다. 모놀리식 애플리케이션을 모듈화하여 별도의 저장소에서 관리하는 구조입니다. 이렇게 분리된 프로젝트는 서로 독립적이기 때문에 개발, 테스트, 빌드 배포 등이 각각 존재하게 됩니다. 현재 보편적으로 사용되는 방법으로 하나의 서비스는 하나의 저장소에서 관리하는 형태이다.
**장점** - 다른 프로젝트와 의존성을 가고 있지 않아 독립적으로 개발이 가능 - 모듈화하여 관심사 분리가 쉬움 - 강한 오너쉽 **단점** - 각 프로젝트의 코드 컨벤션 통일이 어려움 - 코드 재사용이 어려워 중복 코드가 만들어질 가능성이 높음 - 관리 포인트 증가
모노레포 (Monorepo) 하나의 저장소에 여러 프로젝트를 관리하는 구조이다. NPM 배포 없이 프로젝트 간에 코드 공유가 가능하다.
**장점** - 코드 재사용이 용이함 - NPM에 배포할 필요가 없어 의존성 관리가 쉬움
**단점** - CI 속도 저하 가능성이 있음 - 무분별한 리펙토링의 가능성이 있음
프로젝트 시작
Yarn 설치
// Yarn을 전역으로 설치
npm i -g yarn
// Yarn Berry 프로젝트로 시작
yarn init -2
// Yarn Classic 에서 Yarn Berry로 마이그레이션
yarn set version stable
yarn workspace 설정하기
//package.json
{
"name": "MonorepoStudy",
"packageManager": "yarn@4.2.2",
"workspaces": [
"packages/*" -> packages 하위에 모든 workspace가 존재 한다는 것을 뜻함
]
}
- workspace는 monorepo의 하위 프로젝트를 말한다. 위와 같이 package.json에 workspace가 어느 경로에 있는지 작성해 줘야 한다.
VSCode 설정하기
1. **ZipFS VSCode 확장 프로그램 설치하기**: `Yarn Berry`는 Zip 형태로 의존성을 관리하기 때문에 Zip 파일을 읽기 위한 확장 프로그램이 필요.
2. **TypeScript 설치하기**: TypeScript를 사용하기 위해 monorepo 프로젝트 루트에 `yarn add -D typescript` 명령어를 사용하여 TypeScript를 설치
3. **yarn sdk 설치**: VSCode에서 `Yarn Berry`를 사용하기 위해서는 yarn의 vscode sdk가 필요한데, `yarn dlx @yarnpkg/sdks vscode` 명령어를 사용하여 설치
4. **TypeScript 허용**: yarn sdk 설치가 끝나면, `Command Pallette`(Cmd(Crtl) + Shift + P) -> `TypeScript: Select TypeScript Version...` -> `Use Workspace Version`를 클릭하여 VSCode 자체의 타입스크립트 버전이 아닌 워크스페이스의 타입스크립트 버전을 사용 할 수 있도록 설정
[https://beomy.github.io/tech/etc/monorepo-yarn-berry/](https://beomy.github.io/tech/etc/monorepo-yarn-berry/)
[https://blog.hwahae.co.kr/all/tech/11962](https://blog.hwahae.co.kr/all/tech/11962)
하위 프로젝트 만들기
- packages 하위 폴더에 test-project 디렉토리를 생성하고 package.json을 작성
{
"name": "@monorepo/test-project",
"version": "0.0.0",
}
- test-project 에 필요 패키지 설치 yarn workspace <workspaceName> <commandName> 형태로 특정 워크스페이스의 스크립트를 실행 할 수 있다.
$ yarn workspace @monorepo/test-project add -D typescript react react-dom @emotion/react @emotion/styled @types/react @types/react-dom
- test-project 디렉토리에 src 디렉토리를 생성 후 컴포넌트를 만들어 준다.
- 해당 컴포넌트를 만들었을 때 react를 import 하는 부분에서 에러가 발생 하면 위에서 실행 했던 `workspace`의 typescript 버전 설정이 잘 못 되거나 typescript와 관련 있는 확장 프로그래밍 때문에 발생 했을 가능성이 있으므로 다시 설정하고 시도 해보는 것이 좋을 것 같다.
import React, { ReactNode } from 'react';
import styled from '@emotion/styled';
type ButtonProps = {
children: ReactNode
}
const StyledButton = styled.button`
background-color: transparent;
padding: 10px;
border: 1px solid #777;
border-radius: 5px;
`;
const Button = ({ children }: ButtonProps) => {
return <StyledButton>{children}</StyledButton>
}
export default Button
- 컴포넌트 exports
- test-project 에서 만든 컴포넌트를 다른 프로젝트에서 사용할 수 있도록 exports 설정을 추가
// packages/test-project/src/index.ts
export { default as Button } from './Button'
서비스 프로젝트 생성
위에서 작성한 컴포넌트를 사용할 서비스 프로젝트 생성
- 프로젝트 생성
yarn create react-app packages/service-test --template typescript
rm -rf node_modules package-lock.json
- 프로젝트 이름 변경
- 모노레포 네임스페이스로 이름을 변경
//packages/service/package.json
{
"name": "@monorepo/service-test"
}
- 패키지 설치
yarn workspace @monorepo/service-test add @monorepo/test-project @emotion/react @emotion/styled craco
yarn workspace @monorepo/service-test add -D @emotion/babel-plugin @craco/craco @craco/types
- craco 설정
- 다른 워크스페이스의 코드를 가져와 사용하기 위해서는 webpack 설정을 추가해 주어야 하는데, craco를 사용해서 webpack 설정
// packages/service-test/craco.config.ts
// craco.config.ts를 작성하여, Emotion 바벨 플러그인과 webpack의 babel-loader를 확장
import { getLoader, loaderByName } from '@craco/craco'
import { CracoConfig } from '@craco/types'
const cracoConfig: CracoConfig = {
babel: {
plugins: ['@emotion'],
},
webpack: {
configure: (webpackConfig) => {
const { isFound, match } = getLoader(webpackConfig, loaderByName('babel-loader'))
if (isFound) {
// babel-loader의 include 필드를 undefined로 재정의 해주어야, 다른 워크스페이스의 코드를 가져와 사용할 수 있다.
match.loader.include = undefined
match.loader.exclude = /node_modules/
}
return webpackConfig
},
},
}
export default cracoConfig
- service-test 의 package.json 의 script 변경
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test",
"eject": "craco eject"
},
- 컴포넌트 사용
// packages/service-test/src/App.tsx
import { Button } from '@monorepo/design-system';
function App() {
return (
<div>
<Button>TEST</Button>
</div>
);
}
export default App;
- yarn workspace @monorepo/service-test start 명령어를 실행하여 결과물 확인
스크립트 타이핑 최소화
모노레포의 워크스페이스의 스크립트를 실행하기 위해 매번 yarn workspace @monorepo/service-test start을 타이핑 하는 것은 너무 귀찮을 수 있다.
이런 타이핑 양을 줄이기 위해 아래 코드와 같이 `package.json`의 `scripts` 필드를 작성하면 작성해야 할 커맨드 라인이 줄일 수 있다.
- 루트 디렉토리의 package.json 에서 다음과 같이 script 를 작성하면 줄일 수 있다.
"scripts": {
"tp" : "yarn workspace @monorepo/test-project",
"st" : "yarn workspace @monorepo/service-test"
}
위와 같이 작성 하면 yarn st start 만 입력 해도 실행 가능하다.
모노레포에서 각 프로젝트 간의 의존성을 효율적으로 관리하려면 workspace:*를 활용하여 내부 패키지 의존성을 명확히 지정할 수 있다. 예를 들어, test-project에서 service-test에 의존성을 추가할 때, 다음과 같이 내부 의존성을 명시할 수 있다:
"dependencies": {
"@monorepo/test-project": "workspace:*"
}
이렇게 설정하면 각 워크스페이스의 변경 사항을 실시간으로 반영할 수 있어, 별도의 배포 없이도 빠르게 개발하고 테스트할 수 있다. 또한, yarn install 명령을 실행하면 내부 의존성이 자동으로 연결되므로 효율적인 협업 환경을 구축할 수 있다.
CI/CD 최적화
모노레포 구조에서는 모든 프로젝트를 한 번에 빌드하거나 테스트하면 CI/CD 시간이 느려질 수 있다. 이를 해결하기 위해 다음과 같은 방법을 사용할 수 있다.
변경된 프로젝트만 빌드/테스트하기
git diff명령어를 이용해서 특정 커밋 이후 변경된 디렉토리만 감지하고, 해당 워크스페이스만 빌드하거나 테스트한다.병렬 실행 설정하기
CI 도구(GitHub Actions, Jenkins 등)를 사용해서 각 워크스페이스별로 병렬 실행을 설정하면 빌드 시간을 단축할 수 있다.
예를 들어, yarn workspaces foreach 명령어를 사용하면 모든 워크스페이스에서 특정 작업을 실행할 수 있다.
yarn workspaces foreach run test
위 명령어는 모든 워크스페이스에서 test 스크립트를 실행하며, 병렬 실행 옵션을 추가하면 속도를 더 높일 수 있다.
yarn workspaces foreach -pt run test
이렇게 하면 변경된 프로젝트만 효율적으로 테스트할 수 있어서 CI/CD 시간을 크게 줄일 수 있다.