본문 바로가기

Frontend

모노레포 구축하기

모노레포를 처음부터 다시 구축해보았다. 이전에 멘토님과 함께 프로젝트를 진행할 때는 디자인시스템과 스토리북을 모노레포로 관리했었는데, 이번에는 ui라는 워크스페이스와 그것들을 사용하는 워크스페이스를 하나의 모노레포로 관리하고자 하였다.

어떤 방식이 바람직한 방식인지에 대한 고민이 있었는데, 물론 모노레포의 장점도 많지만, 서비스의 크기가 크지 않은 경우 모노레포를 적용하는 것은 오버스펙이 될 수 있다는 것을 알게 되었다. 현업에서도, 그러한 경우는 shared 폴더 안에서 관리를 하고 있었다.

 

모노레포란?

  • 다수의 프로젝트를 한 개의 레포지토리 내에서 관리하는 소프트웨어 개발 전략

 

구현 방법

$ mkdir [folder name]
$ cd [folder name]
$ pnpm init

 

그러면 다음과 같은 package.json이 생성된다.

{
  "name": "monorepo-test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \\"Error: no test specified\\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "packageManager": "pnpm@10.12.1"
}

 

그 다음, pnpm-workspace.yaml을 생성한다.

touch pnpm-workspace.yaml

 

아래와 같이 파일 내용을 입력한다.

// pnpm-workspace.yaml
packages:
  - 'apps/*'
  - 'packages/*'
// 위 설정은 다음 네 개를 모두 프로젝트(또는 워크스페이스 패키지)로 인식한다.
// apps/web, apps/admin, packages/ui, packages/utils
.
├── apps
│   ├── web
│   └── admin
├── packages
│   ├── ui
│   └── utils
├── turbo.json (or nx.json, lerna.json)

 

디렉토리 구조를 생성한다.

mkdir -p apps/web
mkdir -p apps/admin
mkdir -p packages/ui/src
mkdir -p packages/utils/src

 

root 경로의 package.json 수정한다.

{
  "name": "monorepo-test",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "dev": "pnpm --filter web dev",
    "build": "pnpm -r build"
  }
}

 

Next.js 앱을 만든다.

먼저, web 앱을 만든다.

cd apps/web
pnpm create next-app . --ts

 

이후, admin 앱을 만든다.

cd ../../apps/admin
pnpm create next-app . --ts

 

 

이러면, 디렉토리 구조가 아래와 같이 적용된다.

 

 

UI 패키지를 만든다.

web 앱을 만든다.

cd ../../packages/ui
pnpm init
pnpm add -D @types/react @types/react-dom
touch src/index.ts
touch src/Button.tsx
// src/Button.tsx
export const Button = () => {
  return <button style={{ padding: '8px', backgroundColor: '#eee' }}>Hello from UI</button>;
};
// src/index.ts
export * from './Button';
// package.json 수정
{
    "name": "@monorepo/ui",
    "version": "1.0.0",
    "main": "src/index.ts", // 추가
    "types": "src/index.ts", // 추가
    "devDependencies": {
        "@types/react": "^19.1.8",
        "@types/react-dom": "^19.1.6"
    }
}

 

web에서 사용할 수 있도록 해보자.

cd ../../apps/web
pnpm add @monorepo/ui

 

pnpm add @monorepo/ui 명령은 기본적으로 npm registry에서 검색하기 때문에, 해당 패키지를 직접 workspace로 연결하려면 pnpm add를 쓰지 않고, 아래와 같이 package.json을 직접 수정했다.

// /apps/web/package.json
{
    "name": "web",
    "version": "0.1.0",
    "private": true,
    "scripts": {
        "dev": "next dev --turbopack",
        "build": "next build",
        "start": "next start",
        "lint": "next lint"
    },
    "dependencies": {
        "@monorepo/ui": "workspace:*",
        "react": "^19.0.0",
		...
}

 

pages/index.tsx를 수정한다.

import { Button } from '@monorepo/ui';

export default function Home() {
  return (
    <main>
      <h1>Web App</h1>
      <Button />
    </main>
  );
}

 

다음부터는 구조를 이해하는 것을 넘어서서 직접 실무에 적용해볼 수 있는 기회가 있으면 좋겠다.