Background
최근 팀 내에서
MonoRepo
를 도입하는 것에 대한 논의가 이루어진적이 있다.MonoRepo
란 PolyRepo
의 반댓말로, 하나의 레포지토리 안에서 여러 프로젝트들을 관리하는 것을 뜻한다. 팀에서 모노레포에 대한 논의가 나온 이유는 웹과 웹뷰 서비스의 통합을 위해서이다. 현재, 웹 서비스는 Next.js
로, 웹뷰 서비스는 React
로 서비스가 되고 있는데, 웹 서비스도 사실 반응형으로 이루어져 있기 때문에 동일한 서비스를 두 번이나 개발을 해야하는 것에 대해서 피로를 느끼고 있었다.따라서, 웹뷰 서비스를
Next.js
로 마이그레이션하고 웹과 웹뷰를 모노레포로 통합하여 중첩되는 모듈이나 코드를 공통화시켜 재사용성을 높이자는 의견이다.정식으로 도입하기로 한 것은 아니기 때문에, 개인적으로
MonoRepo
를 학습하려고 한다. 해당 아티클은 원티드 프리온보딩 5월에서 지식공유자님께서 공유해준 내용을 정리한 것이다.살펴보기
해당 실습에서는 모노레포를
yarn workspace
로 구축한다. 필요한 스택들의 버전은 다음과 같다.node
- v16 이상
yarn
- v1, 추후에 version berry로 업그레이드함
1. yarn version 변경
yarn 버전을 v1에서 berry로 변경한다.
$ yarn set version berry
2. yarn workspace
이번 실습에서는
yarn workspace
로 MonoRepo
를 구축한다.$ yarn init -w
3. package.json 수정
root directory의
package.json
을 수정한다. 실습에서 특정 서비스의 코드들은 /apps
경로에 소스 코드가 담겨있다고 가정한다.{ "name": "monorepo_excercise", "packageManager": "yarn@3.5.1", "private": true, "workspaces": [ // 서비스되는 소스 코드의 경로 "apps/*", ], "devDependencies": { "typescript": "^5.0.4" } }
4. apps 디렉토리에 create next app
/apps
디렉토리는 Next.js 기반 서비스이다.$ cd app $ yarn create next-app .
5. apps 디렉토리의 package.json 수정
여기서 핵심은
package.json
name에 @을 추가해주는 것이다.{ // @가 핵심 "name": "@wanted/web", "version": "0.1.0", "private": true, "scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint" }, "dependencies": { "@types/node": "20.1.1", "@types/react": "18.2.6", "@types/react-dom": "18.2.4", "@wanted/lib": "workspace:^", "eslint": "8.40.0", "eslint-config-next": "13.4.1", "next": "13.4.1", "react": "18.2.0", "react-dom": "18.2.0", "typescript": "5.0.4" } }
각 디렉토리는 root에서 실행시킬 수 있다.
/apps
디렉토리에서 서비스되는 프로젝트는 다음과 같이 실행시킬 수 있다.$ yarn workspace @wanted/web run dev
6. TypeScript 오류 해결
yarn berry
는 기존에 node_modules
로 모듈을 불러오는것에 비해 plug n play
로 불러오기 때문에 TypeScript
오류가 발생한다. 이는 다음과 같이 해결할 수 있다.$ yarn add -D typescript $ yarn dlx @yarnpkg/sdks vscode
7. 공통 패키지 만들어보기
이제
MonoRepo
의 강력함을 경험하기 위한 작업을 진행할 것이다. 공통 패키지를 만들어 여러 서비스에 사용될 수 있도록 할 것이다.해당 패키지의 디렉토리는
/packages/lib
이다.# 해당 디렉토리에 package.json을 설치한다. $ yarn init $ yarn add -D typescript
해당 디렉토리에서 마찬가지로
package.json
을 수정한다.{ // @가 마찬가지로 핵심이다! "name": "@wanted/lib", "packageManager": "yarn@3.5.1", "main": "./src/index.ts", "dependencies": { "typescript": "^5.0.4" } }
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"] }
여러 서비스에서 사용할 수 있는 메서드를 만들어보자.
// packages/lib/src/index.ts export const sayHello = () => { return 'Say Hello From packages lib'; }
8. 의존성 주입
여러 서비스에서 공통 패키지에 만든
sayHello
메서드를 사용하기 위해서는 의존성을 주입해주는 작업이 필요하다. 해당 작업은 root directory에서 진행한다.# @wanted/web에 @wanted/lib 의존성을 추가한다. $ yarn workspace @wanted/web add @wanted/lib
해당 작업이 진행되면,
/apps/wanted
디렉토리의 package.json
에서 의존성이 주입된 것을 확인할 수 있다."dependencies": { "@types/node": "20.1.1", "@types/react": "18.2.6", "@types/react-dom": "18.2.4", // @wanted/lib 의존성이 잘 주입되었다. "@wanted/lib": "workspace:^", "eslint": "8.40.0", "eslint-config-next": "13.4.1", "next": "13.4.1", "react": "18.2.0", "react-dom": "18.2.0", "typescript": "5.0.4" }
9. apps 서비스에서 공통 패키지의 메서드 사용해보기
이제 @wanted/web 에서
sayHello
메서드를 사용해볼 것이다.// /apps/wanted/src/pages/index.tsx // 사용하기 import { sayHello } from '@wanted/lib';
댓글