원티드에서 5월 프리온보딩 챌린지를 진행하여 참가하였다.
이번달 주제는 바로 monorepo와 관련된 것! 평소에 너무 궁금하고 배워보고 싶었는데 이런 기회가 오다니 ! 바로 신청했다.
이번 챌린지는 모노레포인 만큼 실습이 많았는데 환경 세팅하는 과정에서 놓치는 부분이 많았다.
다시보기로 놓친 부분도 공부하겸 블로그에 정리해 놓기로 마음을 먹었다.
모노레포 관련 아티클
사전 미션으로 모노레포와 관련된 아티클을 읽어보라고 추천해주셨는데 너무 재미있고 흥미롭게 읽을 수 있었다. 그러면서 나의 프로젝트를 잠시 회고해 볼 수 있었다.
나는 주로 멀티 레포로만 서비스를 운영했었다. 각 프로젝트가 고유 저장소를 가지므로 독자적으로 빠르게 개발을 가능했고, 각각의 프로젝트를 관리하기엔 가벼웠다.
하지만 같은 도메인의 프로젝트가 점점 들어나다 보니, 프로젝트 별로 중복되는 모듈이 많았고 관리하기에 비효율적이라는 생각이 들었다. 또 오랫동안 건드리지 않는 코드는 관리하기 어려웠으며 각 프로젝트마다의 컨벤션이 달라 빠르게 코드를 파악하고 유지보수 하기 어려웠다.
이런 문제점에서 모노레포가 나왔구나 라는 생각에 크게 와닿았다.
팀워크 향상을 위한 모노레포(Monorepo) 시스템 구축
콴다 프론트엔드 팀이 모노레포를 선택한 이유
blog.mathpresso.com
모노레포의 문화적 의의
Overview 콴다 프론트엔드 팀에서 최근 효율적인 프로젝트 관리를 위해 "모노레포(monorepo)"를 도입했습니다. (레포 이름도 굉장히 Semantic 한 "qanda-frontend"입니다) 팀 내에서 모노레포를 도입하자는
yeoulcoding.me
https://d2.naver.com/helloworld/0923884
multirepo와 monorepo ?
monorepo
monolitic + repository
단단하게 하나로 짜여진 깃 저장소라는 의미로
여러 개의 개별 프로젝트를 잘 정의된 관계를 통해 하나의 레포에 담은 것이다.
https://news.hada.io/topic?id=6061
Monorepo에 대한 모든 것 | GeekNews
Monorepo란 무엇인가"여러 개의 개별 프로젝트를, 잘 정의된 관계를 통해서 하나의 Repo에 담은 것"Monorepo ≠ Monolith왜 해야할까 ?기존의 Polyrepo(여러개의 Repo를 사용하던 방식)를 선택한 이유는 "팀
news.hada.io
multirepo = polyrepo
깃 저장소가 프로젝트 마다 따로따로 있는 형태이다.
monorepo를 사용하는 보편적인 케이스
라이브러리 개발, 디자인 시스템 개발
예시로 바벨과 radix가 있다.
https://github.com/babel/babel
GitHub - babel/babel: 🐠 Babel is a compiler for writing next generation JavaScript.
🐠 Babel is a compiler for writing next generation JavaScript. - GitHub - babel/babel: 🐠 Babel is a compiler for writing next generation JavaScript.
github.com
https://github.com/radix-ui/primitives
GitHub - radix-ui/primitives: Radix Primitives is an open-source UI component library for building high-quality, accessible desi
Radix Primitives is an open-source UI component library for building high-quality, accessible design systems and web apps. Maintained by @workos. - GitHub - radix-ui/primitives: Radix Primitives is...
github.com
B2B, B2C, admin 을 하나로
현재 원티드의 멀티레포 구조는 다음과 같다.
B2B, B2C, admin를 멀티 레포로 구현 시 공통적인 모델이 많다.

위 와 같은 멀티레포 구조를 모노 레포로 바꾸면 다음과 같아진다.
apps아래에 하나로 뭉쳐 코드를 중복된 코드 없이 효율적으로 짤 수 있게 된다. 추가로 우아콘 자료 역시 비슷한 구조로 짜여있다.



Monolity -> Microservice
거대한 하나의 서비스를 모노레포를 활용하여 각각의 쪼갠다.
monorepo의 장단점
장점
1. 내가 담당하는 프로젝트가 아니라도 개선의 여지가 있다면 자유롭게 수정할 수 있다.
2. 다른 사람의 코드에 자주 기웃거릴 수 있다.
3. 내가 알지 못했던 offical Document API를 통해서 문제를 더 깔끔하게 해결할 수 있다.
4. 동료들간의 상호작용으로 기술적 비지니스적 성장 할 기회가 많이 열린다.
단점
1. 개발환경을 구성하는데 투자가 필요하다.
2. 코드 관리의 어려움 (코드 소유권 문제)
3. 대규모 리팩토링이 쉬워지는게 장점이자 단점.
간단한 monorepo 맛보기
nvm
nvm은 노드 버전을 자유롭게 바꿀 수 있다. nvm을 설치 후 vscode extensions인 vscode nvm integration 을 설치해준다. (자동으로 노드 버전은 스위칭 해주는 extensions이다 )
프로젝트 별로 노드 환경을 세팅하기
프로젝트를 생성하고 nvmrc 를 만든다. 터미널에 nvm list 명령어를 치면 버전마다 원소기호가 나오는데 .nvmrc에 원소 기호 또는 버전을 넣어준다. 프로젝트를 다시 실행 시키면 자동으로 nvm use가 나오면서 설치한 extensions에 의해 파일의 버전을 읽어 자동으로 버전을 로드 시켜준다. 이때 노드는 16이상으로 바꿔준다.


yarn 버전 세팅
yarn 버전을 바꿔준다. yarn berry에서만 모노레포를 지원하는것이 생긴것이 아니지만, yarn berry가 모노레포를 지원해주는 기능들이 막강해졌기 때문이다.
yavn -v
//둘중에 하나로 설치, 둘다 똑같음
yarn set version berry
yarn set version stable
yarn -v
yarn cli지원
( -w : 워크스페이지를 쓸 수 있는 초기화를 진행해준다. )
yarn init -w
root package.json 파일 수정
apps 폴더 추가 및 workspaces 배열에 app/* 추가 하기
apps 에 next 프로젝트 추가
yarn create next-app
next 프로젝트 package.json 에 이름을 바꿔준다.
그리고 다시 root로 가서 yarn 을 해준다.
왜 yarn 을 다시 해줄까 ? 프로젝트가 생성될때 정보들을 .pnp.cjs에 저장되어 있다. 루트에서 yarn 명령어를 치지 않으면 정보가 업데이트가 안된다. 따라서 갱신? 하는 작업을 시켜줘야한다.
프로젝트 실행하기
yarn 에서는 모노레포 환경을 workspace 개념으로 사용한다. 따라서 모노레포를 구성하기 위해 yarn의 workspace 기능을 사용한다고 생각하면 된다.
next 프로젝트를 실행시키는 방법은 두가지 있다. 직접 프로젝트 경로에 들어가서 yarn dev로 하는 방법이 있다. 하지만 이 방법은 모노레포 환경에서 굉장히 복잡한일이 될 수 있다. 따라서 루트에서 프로젝트를 실행하는 방법을 알아보자.
yarn workspace @wanted/web run dev
next 프로젝트에서 package.json의 name을 위에서 수정해줬을 것이다.
이름 수정의 이유는 바로 프로젝트 실행을 위해서 였다.
typescript error 발생 원인 및 해결
순조롭게 실행까지 완료 되었지만 next 프로젝트 index.tsx 에러 타입스크립트 관련 빨간 에러가 발생하는 것을 볼 수 있을 것이다.
이 에러의 원인은 yarn berry pnp는 설치된 의존성을 node_modules를 불러오는 방식이 아니라, .yarn을 불러오는데 .yarn은 zip 파일로 되어 있어 vscode에 읽지 못하는 것이다. 따라서 vscode가 알아먹을 수 있게 해야하는 것!
루트에 다음과 같은 명령어를 입력한다.
yarn add -D typescript
yarn dlx @yarnpkg/sdks vscode
만약 그래도 안 될 경우 yarn pnp를 사용하기 위한 extensions을
.vscode/extensions.json 에 추가한다.
{
"recommendations": ["arcanis.vscode-zipfs"]
}
packages/lib 공통 패키지 만들기
packages에 lib폴더를 만들고 아래 스크립트를 실행한다.
yarn init //pakage.json 파일 생성
yarn add typescript //타입스크립트 설치
lib아래에 src폴더와 index.ts파일을 만들어 준다. 생성된 index.ts에는 다음 코드를 넣어보자.
export const sayHello = () => {
return "hello from lib";
};
그리고 package.json으로 가서 name을 수정하고, main 을 다음과 같이 수정한다.
여기서 main은 메인이 되는 엔트리 파일이라고 생각하면 된다.
tsconfig.json을 만들고 아래 코드를 넣어준다.
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"strict": true,
"useUnknownInCatchVariables": true,
"allowJs": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"newLine": "lf",
"module": "ESNext",
"moduleResolution": "node",
"target": "ESNext",
"lib": ["ESNext", "dom"],
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"baseUrl": "./src",
"noEmit": false,
"incremental": true,
"resolveJsonModule": true,
"paths": {}
},
"exclude": ["**/node_modules", "**/.*/", "./dist", "./coverage"],
"include": ["**/*.ts", "**/*.js", "**/.cjs", "**/*.mjs", "**/*.json"]
}
next 프로젝트에서 lib 의존해보기
우리가 처음에 만들었던 Next프로젝트에서 package/lib 에 만든 코드를 의존해 보자.
일단 만들었던 lib 프로젝트를 갱신하기 위해 루트로 가서 yarn을 실행해준다.
그리고 아래 스크립트를 입력해보자.
// root에서 실행한다.
yarn workspace @wanted/web add @wanted/lib
그리고 next 프로젝트에 package.json으로 가보면 우리가 추가한 @wantd/lib를 의존하는 것을 확인해 볼 수 있다.
next 프로젝트에서 lib 함수 사용해 보기
next 프로젝트에 index.tsx에 들어가서 lib에서 만들었던 sayHello 함수를 사용하고 프로젝트를 실행해보자.
yarn workspace @wanted/web run dev
hello from lib가 노출된 것을 볼 수 있다 :)
한 레포에 있지만 여러 레포에 있는 것 처럼 프로젝트 별로 구별이 된 구조가 된것이다.

'Front-end' 카테고리의 다른 글
모노레포 환경에서 코딩 컨벤션 & 공통 로직 공유 (0) | 2023.05.08 |
---|---|
[Flutter Error] Permission denied vector_math (0) | 2023.04.09 |
bootstrap grid (0) | 2022.03.14 |
Concurrently? (0) | 2022.01.29 |
Proxy Server? (0) | 2022.01.29 |