🚁

Yarn workspace로 모노레포 알아보기

분류
Dev Log 💻
작성자
1 more property

[도입 배경]

테스트뱅크의 경우 프론트엔드 개발자가 React Client와 GraphQL 서버를 모두 개발하는 구조입니다. 그러다보니 자연스레 서버 프로젝트와 클라이언트 프로젝트를 왔다갔다 하면서 개발해야 하는 일이 많을 수 밖에 없는 데요. 그렇기 때문에, 서버와 클라이언트를 한 프로젝트에 넣어 관리하는 모노레포 구조를 택하는 것이 적합하다고 판단을 내리게 되었습니다.

[모노레포란]

하나의 Repo
기존의 여러개의 Github Repository에서 관리되던 프로젝트들을 하나의 Repository에서 관리하는 구조입니다.
이해를 돕기 위해 아래의 이미지와 함께 보도록 하죠. 아래의 이미지는 멀티레포 구조에서 클라이언트 프로젝트와 서버 프로젝트를 별도로 두고 관리했을 때의 모습입니다. 서버와 클라이언트가 별도의 Repository에서 관리되는 모습입니다.
반면 모노레포에서 관리했을 때는 위의 2개가 아래와 같이 하나의 repo에서 관리 됩니다. 차이가 느껴지시나요?
자 그러면 ‘하나의 repo’라는 개념을 담아두고, 실제 프로젝트를 보면서 자세히 알아보도록 합시다. 아래 부터는 글 작성의 편의를 위해 ‘~하다’ 체로 글을 이어나가도록 하겠습니다.

[프로젝트 구조 훑기]

먼저 프로젝트 구조를 알아보자
물론 틀린 표현이긴 하지만, 이해를 돕기위해 아주 단순히 말하자면, 새로운 디렉토리 내부에 기존 프로젝트들을 복붙한 형태를 생각하면 이미지화 하기 쉬울 것이다.
현재 테스트뱅크의 프로젝트 중 하나인 cms의 프로젝트 구조 이미지를 한번 보자.
1개의 프로젝트 cms 디렉토리 안에 cms-client와 cms server 2개의 프로젝트가 들어있는 형태다.

[도구를 정해보자 - Yarn workspace]

자 그러면 그림이 대강 그려졌으니 본격적으로 설정법을 알아보자. 구글에 모노레포라고 검색해보면 yarn workspace와 lerna라는 2가지에 대한 레퍼런스들이 많이 나온다. 아무래도 이 2가지 옵션이 가장 유명한 것 같으니 둘중에 우리의 도구를 선택해보자
yarn workspace vs lerna
lerna의 경우 별도의 설치가 필요하고, 러닝커브도 yarn workspace에 비해 높은 편이다. yarn v2와 호환되지 않는 점도 우리와 궁합이 맞지 않는다. yarn workspace를 사용하도록 하자. yarn workspace는 yarn의 내장 기능이기 때문에, 별도의 설치가 필요없어 사용하기가 용이하고, 러닝커브도 거의 없는 편이다.

[Yarn workspace와 node_modules]

yarn workspace 설정에 대해 알아보기 전에, 먼저 yarn workspace와 node_modules에 대해 한가지만 알아두자.
workspace의 설정을 완료하고 yarn 커맨드를 입력하면, 프로젝트 레벨의 패키지들이 대부분 root의 node_modules로 이동한다.
이 때, 기존 프로젝트 레벨에 존재하던 node_modules 디렉토리는 전부다 혹은 일부만 남고 사라진다.
자연스러운 현상이니 당황하지 말자

[Yarn workspace 설정법]

핵심 키워드

1.
node_modules
2.
package.json
3.
tsconfig.json
4.
eslintrc
5.
prettierrc
위에서 말했듯이, yarn workspace는 yarn의 내장 기능이기 때문에 별도로 설치할 것이 없다. package.json에 설정 몇줄만 해주면 바로 사용이 가능하다. 말 나온 김에 package.json 부터 살펴보도록 하자.

[1. yarn workspace - package.json]

workspace 설정에서 가장 핵심이 되는 설정파일이다. cms 프로젝트를 예시로 들어 설명하도록 하겠다. 현재 cms는 모노레포이기 때문에 프로젝트에서 package.json 파일은 3개가 존재한다.
프로젝트 루트에 1개, Nestjs 루트에 1개, React 루트에 1개씩으로 총 3개이다.
루트의 package.json에는 프로젝트가 공통으로 공유할 패키지에 대한 정보와 workspace에 대한 설정이 담겨 있다. 이미지와 함께 각 프로퍼티들에 대해 설명하도록 하겠다.

[workspaces]

필수로 입력해야한다. workspaces 는 모노레포로 관리할 프로젝트 명을 입력한다. 각 프로젝트들의 package.json의 name 프로퍼티의 값과 동일하게 설정해줘야한다.

[scripts]

필수로 입력해야한다. 루트 package.json에 스크립트를 설정해주지 않으면 매번 프로젝트를 실행할 때마다, “cd ..” 을 입력해야하는 귀찮은 일이 벌어진다.
이걸 쓰면 각 프로젝트의 package.json의 script를 root에서 경로 이동 없이 바로 사용할 수 있다. scripts의 key 값인 client와 server는 그 때 사용하는 용도다. 예를 들어 아래와 같이 가능하다.
yarn client start yarn client add {package} yarn client remove {package} yarn client build yarn client dev yarn server start yarn server lint yarn server add {package} yarn server remove {package}
값의 경우는 아래와 같은 문법으로 작성한다.
yarn workspace {개별 프로젝트의 package.json 파일의 name 프로퍼티}

[dependencies]

이건 필수사항은 아니다. 중복되는 패키지가 없다면 굳이 root로 분리할 필요는 없다. 중복되는 패키지가 있을 경우도 필수는 아니지만, 프로젝트 패키지의 중복을 막고, 용량을 줄이기 위해 분리해주는 것이 좋다.
cms의 경우, 타입스크립트와 buf 관련 패키지들은 React와 Nest 프로젝트 모두에서 공통으로 쓰기 때문에 root에 설치해주었다.
root에 패키지를 설치할 때는 기존의 멀티레포 방식과 동일하게 쓰면 된다. yarn add 명령어 중간에 키워드를 사용하지 않으면 root에 자동으로 설치된다. 설치된 패키지는 전역으로 공유되기 때문에 각 프로젝트 레벨에서 가져다 쓸 수 있다.
yarn add {설치할 package명}
YAML
복사
각 프로젝트 레벨의 package.json 파일은 기존 멀티레포 구조와 다를게 없으니 별도로 설명하지 않겠다. 다만, 사용하는 package가 root와 중복될 경우, 프로젝트 단의 패키지는 삭제해주도록 하자.
— [yarn workspace - package.json] 섹션 끝

[2. yarn workspace - tsconfig.json]

yarn workspace에서는 tsconfig.json 작성 방식중 2가지를 선택할 수 있다. 아래와 같다
1.
멀티레포 구조에서 처럼 각 패키지에 tsconfig.json에 설정하는 법.
2.
공통 설정사항을 root tsconfig에 두고, 개별 설정사항을 각 프로젝트의 tsconfig에 두는 법
1번은 가장 간단하면서 쉬운 방법이다. 멀티레포 일때의 설정법이 같으며, root에 별도의 tsconfig 파일이 존재할 필요가 없다.
2번은 1번보다 설정이 복잡하다. 그러나 이 방법을 쓰면, 공통되는 설정을 root에서 관리할 수 있는 것이 장점이다. 설정법이 멀티레포와 다소 다른점이 있으니 2번을 중점적으로 설명해보려한다. cms의 프로젝트를 예시로 하여 설명하겠다.
위의 이미지는 cms 프로젝트 root의 tsconfig 파일을 캡처한 것이다. 각 항목별로 설명하겠다.
1.
compilerOptions
두 프로젝트가 공통으로 사용하는 compilerOptions을 root에 설정해준것이다.
2.
references
아마 이 프로퍼티는 생소할 수 있다. root의 tsconfig에게 개별 tsconfig파일이 위치한 경로를 알려주는 역할이다. 이것이 필요한 이유는 타입스크립트 컴파일러가 코드를 컴파일 할 때, 개별 tsconfig 파일의 내용도 알아야 하기 때문이다.
3.
exclude
여기에 설정한 값은 타입스크립트 컴파일러가 컴파일 하지 않는다. 우리의 경우 node_modules이다
2번의 경우 개별 프로젝트의 tsconfig 파일도 같이 봐야하므로 추가 설명을 하도록 하겠다. 아래 이미지들을 보자. 이미지들은 클라이언트와 서버의 tsconfig 파일을 각각 캡처한 것이다.
cms/cms-server/tsconfig.json
cms/cms-client/tsconfig.json
extends 키워드를 보자. root에 tsconfig 파일로 compilerOption을 분리했을 경우 프로젝트 레벨에서는, extends 프로퍼티의 값으로 root tsconfig 파일의 경로를 반드시 입력해주어야한다.
— [yarn workspace - tsconfig] 섹션 끝

[3. yarn workspace - Prettier]

prettier는 아래의 사항만 알면된다.
1.
prettier의 경우는 대부분 같은 포맷팅 설정을 공유하는 경우가 많기 때문에 root에 한번만 설정한다. root에 .prettierrc.json파일과 .prettierignore파일을 작성해주자. 개별 프로젝트에 동일한 파일이 존재한다면, 중복을 막기 위해 개별 프로젝트의 prettier 관련 설정 파일을 삭제해주자
2.
Vscode에서 prettier auto formatting을 설정할 때 사용하는 파일인 .vscode/settings.json도 root에 설정해준다.
— [yarn workspace - prettier] 섹션 끝

[4. yarn workspace - Eslint]

* eslint 설정파일 - eslintrc와 eslintignore
eslint는 3가지 방법을 사용할 수 있다. cms에서는 참고로 가장 간단한 1번 설정을 사용하고 있다.
1.
개별 프로젝트에 eslint 설정하고, 개별 프로젝트에서 관리한다.
2.
root에 eslint 설정하고, root에서 관리한다
3.
root에 eslint를 설정하고, 개별 사항은 개별 프로젝트에서 관리한다.
1번을 사용하는 이유는 Create React App 내부적으로 eslint가 별도로 설정되어있기 때문이다. 이 말은 cra가 내부의 eslint를 사용하지 않고 root의 eslint를 바라보게 해야한다는 것인데, 알다시피 CRA에서는 eslint 설정파일이 숨김처리 되어있다.
물론 가능은 하지만, 이 설정 파일을 만지려면 아래의 둘중 한가지 방법을 사용해야한다
1.
Eject 한다
2.
React App을 CRA 없이 직접 만든다.
1번의 경우 관리 포인트가 늘어나는 단점이 생기고, 2번의 경우는 세팅에 시간이 오래걸린다.
밥먹으려고 농사짓지 말자. React는 React의 eslint 대로 돌아가게 냅두고, Nest는 Nest의 eslint대로 돌아가게 설정하면 그만이다.
— [yarn workspace - eslint] 섹션 끝

[5. yarn workspace - 최종 구조 확인하기]

아래 이미지를 통해 최종 프로젝트 구조를 확인하자.
글 마침

Reference

고원진 Software Engineer
실제로 동작하는 것을 만들어내는 즐거움으로 여기까지 왔고, 이제는 유저에게 효익을 주는 서비스를 개발합니다.