๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Web

Turborepo์™€ PNPM์œผ๋กœ Monorepo ์‹œ์ž‘ํ•˜๊ธฐ

by LasBe 2025. 3. 16.
๋ฐ˜์‘ํ˜•

๐Ÿ“’ Turborepo์™€ PNPM์œผ๋กœ Monorepo ์‹œ์ž‘ํ•˜๊ธฐ


์š”์ฆ˜์—” ๋ชจ๋†€๋ฆฌ์‹ ํ˜น์€ ๋ฉ€ํ‹ฐ๋ ˆํฌ ๊ตฌ์กฐ๋ณด๋‹ค ์ค‘๋ณต ์ฝ”๋“œ์™€ ์˜์กด์„ฑ ๊ด€๋ฆฌ ์ธก๋ฉด์—์„œ ์œ ๋ฆฌํ•œ ๋ชจ๋…ธ๋ ˆํฌ ๊ตฌ์กฐ๊ฐ€ ๋งŽ์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

๋ชจ๋…ธ๋ ˆํฌ ๊ตฌ์กฐ๋ฅผ ๊ตฌ์ถ•ํ•˜๋Š” ๋ฐฉ๋ฒ•์—” ์—ฌ๋Ÿฌ ๊ฐ€์ง€๊ฐ€ ์žˆ์ง€๋งŒ ์ €๋Š” Turborepo๋กœ ์†์‰ฝ๊ฒŒ ํ™˜๊ฒฝ์„ ๊ตฌ์ถ•ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค.

 

๐Ÿ“Œ Turborepo๋ž€?

Turborepo๋Š” Vercel์—์„œ ๊ฐœ๋ฐœํ•œ JS/TS ๋ชจ๋…ธ๋ ˆํฌ ๋นŒ๋“œ ์‹œ์Šคํ…œ์ž…๋‹ˆ๋‹ค.

๊ธฐ์กด ๋ชจ๋…ธ๋ ˆํฌ ๊ด€๋ฆฌ ๋„๊ตฌ์ธ Lerna๋‚˜ Nx์™€ ์œ ์‚ฌํ•˜์ง€๋งŒ, ๋” ๋น ๋ฅด๊ณ  ํšจ์œจ์ ์ธ ๋นŒ๋“œ ์„ฑ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

 

์ฃผ์š” ์žฅ์ ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ์บ์‹ฑ ๋ฐ ๋ณ‘๋ ฌ ์‹คํ–‰
    • ๊ฐ™์€ ์ž‘์—…์„ ์—ฌ๋Ÿฌ ๋ฒˆ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ  ๊ฒฐ๊ณผ๋ฅผ ์บ์‹ฑํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œ ์ค‘๋ณต ๋นŒ๋“œ๋ฅผ ๋ฐฉ์ง€
    • ์—ฌ๋Ÿฌ ํŒจํ‚ค์ง€์˜ ๋นŒ๋“œ๋ฅผ ๋ณ‘๋ ฌ๋กœ ์‹คํ–‰ํ•˜์—ฌ ์†๋„ ์ตœ์ ํ™”
  • ํšจ์œจ์ ์ธ ์˜์กด์„ฑ ๋ถ„์„
    • ๊ฐ ํŒจํ‚ค์ง€์˜ ์˜์กด์„ฑ์„ ๋ถ„์„ํ•˜์—ฌ, ๋ณ€๊ฒฝ๋œ ๋ถ€๋ถ„๋งŒ ๋‹ค์‹œ ๋นŒ๋“œํ•ด์š”.
    • turbo run build ๊ฐ™์€ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋ณ€๊ฒฝ๋œ ํŒจํ‚ค์ง€๋งŒ ๋‹ค์‹œ ์ฒ˜๋ฆฌํ•ด์„œ ๋นŒ๋“œ ์‹œ๊ฐ„์„ ๋‹จ์ถ•ํ•  ์ˆ˜ ์žˆ์–ด์š”.
  • ์›๊ฒฉ ์บ์‹ฑ
    • Vercel๊ณผ ํ†ตํ•ฉํ•˜์—ฌ ํŒ€์›๋“ค๋ผ๋ฆฌ ์บ์‹œ๋ฅผ ๊ณต์œ 
    • ๋กœ์ปฌ์—์„œ ๋นŒ๋“œํ–ˆ๋˜ ๊ฒฐ๊ณผ๋ฅผ ๋‹ค๋ฅธ ํŒ€์›์ด ๋‹ค์‹œ ์‹คํ–‰ํ•  ๋•Œ๋„ ์žฌ์‚ฌ์šฉ

 

์ €๋„ ์ง€๊ธˆ์€ ๊ณ„์†ํ•ด์„œ ํ•™์Šตํ•˜๋Š” ์ค‘์ด์ง€๋งŒ ์„ค์ •์ด ์ง๊ด€์ ์ด๋ผ ๋Ÿฌ๋‹์ปค๋ธŒ๊ฐ€ ๋†’์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ๋„ ํฐ ์žฅ์ ์ด๋ผ ์ƒ๊ฐ๋ฉ๋‹ˆ๋‹ค.

 

๐Ÿ“Œ Turborepo + pnpm ๋ชจ๋…ธ๋ ˆํฌ ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ

 

Installation | Turborepo

Learn how to get started with Turborepo.

turbo.build

$ npx create-turbo@latest

์œ„ ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด ์„ค์น˜ํ•˜๋ฉด ํด๋”๋ช…๊ณผ ํŒจํ‚ค์ง€ ๋งค๋‹ˆ์ €๋ฅผ ์„ ํƒํ•˜๊ณ , ๊ธฐ๋ณธ์ ์ธ monorepo ํ…œํ”Œ๋ฆฟ๊ณผ ํ•จ๊ป˜ ํ”„๋กœ์ ํŠธ๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

์ €๋Š” ํŒจํ‚ค์ง€ ๋งค๋‹ˆ์ €๋กœ pnpm์„ ์„ ํƒํ–ˆ์œผ๋ฉฐ, pnpm workspace๋กœ ์ƒ์„ฑ๋œ ํ”„๋กœ์ ํŠธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํด๋”๊ตฌ์กฐ๋ฅผ ๊ฐ–์Šต๋‹ˆ๋‹ค.

 

๋‹ค์–‘ํ•œ ํ”„๋ ˆ์ž„์›Œํฌ์— ๊ธฐ๋ฐ˜ํ•œ ์˜ˆ์ œ๋“ค์„ ํ™•์ธํ•˜๊ณ  ์‹ถ์œผ์‹œ๋ฉด ์œ„ ๊ณต์‹๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•ด ์ฃผ์„ธ์š”.

๊ทธ๋Ÿผ monorepo๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ์ฃผ์š” ํŒŒ์ผ๋“ค์— ๋Œ€ํ•ด ์„ค๋ช…๋“œ๋ฆฝ๋‹ˆ๋‹ค.

 

๐Ÿ“Œ pnpm-workspace.yaml

packages:
  - "apps/*"
  - "packages/*"

pnpm-workspace.yaml์€ pnpm์—์„œ ๋ชจ๋…ธ๋ ˆํฌ๋ฅผ ๊ด€๋ฆฌํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ์›Œํฌ์ŠคํŽ˜์ด์Šค ์„ค์ • ํŒŒ์ผ์ž…๋‹ˆ๋‹ค.

 

packages ํ‚ค์›Œ๋“œ๋กœ ๋ชจ๋…ธ๋ ˆํฌ ๋‚ด์—์„œ ๊ด€๋ฆฌํ•  ํŒจํ‚ค์ง€๋“ค์˜ ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์œ„์—์„œ ์ƒ์„ฑํ•œ ํ”„๋กœ์ ํŠธ์˜ ๊ฒฝ์šฐ apps/*, packages/* ํด๋”๋ฅผ ๊ด€๋ฆฌํ•  ํŒจํ‚ค์ง€๋กœ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ ๋“ฑ๋กํ•œ ํŒจํ‚ค์ง€๋“ค์€ ์„œ๋กœ ๊ฐ ํด๋” ๋‚ด package.json์˜ dependencies๋กœ ์ถ”๊ฐ€ํ•ด ๋งํฌํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, install์‹œ ๊ฐ ํŒจํ‚ค์ง€์˜ ์ตœ์‹  ๋ฒ„์ „์ด ์ž๋™์œผ๋กœ ๋ฐ˜์˜๋˜์–ด ์ค‘๋ณต๋œ ์ฝ”๋“œ๋ฅผ ์†์‰ฝ๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

"dependencies": {
  "@repo/ui": "workspace:*",
  ...
},

์œ„ ํ”„๋กœ์ ํŠธ์—์„œ packages/ui ํŒจํ‚ค์ง€๋ฅผ apps/web์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„ , ์œ„์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•  ํŒจํ‚ค์ง€ ์ด๋ฆ„๊ณผ ๋ชจ๋…ธ๋ ˆํฌ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๋ฒ„์ „  ["@repo/ui: "workspace:*"]์„ ์ง€์ •ํ•ด ์ฃผ๋ฉด ํ•ญ์ƒ ๋กœ์ปฌ์˜ ์ตœ์‹  ๋ฒ„์ „์„ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

"workspace:"๋Š” pnpm, Yarn, npm์—์„œ ์ œ๊ณตํ•˜๋Š” ์›Œํฌ์ŠคํŽ˜์ด์Šค ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜๋กœ, ๋ชจ๋…ธ๋ ˆํฌ ๋‚ด์—์„œ ํŠน์ • ํŒจํ‚ค์ง€๋ฅผ ์ฐธ์กฐํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋ฒ„์ „ ์ง€์ • ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

 

 

์ด๋Ÿฌํ•œ ๊ณตํ†ต ์ปดํฌ๋„ŒํŠธ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ eslint, tsconfig, prettier ์„ค์ •๋“ค๋„ ํ•˜๋‚˜๋กœ ๋ชจ์•„์„œ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด ์—ฌ๋Ÿฌ ํ”„๋กœ์ ํŠธ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์šฉ์ดํ•ฉ๋‹ˆ๋‹ค.

 

๐Ÿ“Œ turbo.json

{
  "$schema": "https://turbo.build/schema.json",
  "ui": "tui",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "inputs": ["$TURBO_DEFAULT$", ".env*"],
      "outputs": [".next/**", "!.next/cache/**"]
    },
    "lint": {
      "dependsOn": ["^lint"]
    },
    "check-types": {
      "dependsOn": ["^check-types"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}

turbo.json์€ Turborepo์—์„œ ๋นŒ๋“œ, ํ…Œ์ŠคํŠธ, ๋ฐฐํฌ ๋“ฑ์˜ ์ž‘์—…์„ ๊ตฌ์„ฑํ•˜๋Š” ํ•ต์‹ฌ ์„ค์ • ํŒŒ์ผ์ž…๋‹ˆ๋‹ค.

์ด ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ชจ๋…ธ๋ ˆํฌ ๋‚ด์—์„œ ๊ฐ ํŒจํ‚ค์ง€์˜ ์ž‘์—… ์‹คํ–‰ ์ˆœ์„œ, ์บ์‹ฑ, ๋ณ‘๋ ฌ ์‹คํ–‰ ๋“ฑ์„ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์—ฌ๋Ÿฌ ์†์„ฑ๋“ค์ด ์žˆ์ง€๋งŒ ์ฃผ์š”ํ•œ ํ‚ค์›Œ๋“œ๋“ค๋งŒ ์„ค๋ช…๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

 

๐Ÿ”Ž tasks

{
  "tasks": {
    "build": {
      ...
    },
    "lint": {
      ...
    },
  }
}

tasks๋Š” turbo.json์—์„œ ๊ฐ ์ž‘์—…์˜ ์‹คํ–‰ ๋ฐฉ์‹, ์‹คํ–‰ ์ˆœ์„œ, ์บ์‹ฑ, ์ž…์ถœ๋ ฅ ํŒŒ์ผ ๋“ฑ์„ ์ •์˜ํ•˜๋Š” ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค.

์ด ์†์„ฑ ์•ˆ์— ์žˆ๋Š” ๋‚ด๋ถ€ ์†์„ฑ๋“ค์˜ key ๊ฐ’๋“ค์€ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ์ž‘์—…์œผ๋กœ ๋“ฑ๋ก๋˜๊ณ , $ turbo run <task-key>๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 $ turbo run <task-key>๊ฐ€ ์‹คํ–‰๋˜์—ˆ๋‹ค๋ฉด ๋“ฑ๋ก๋œ workspace ํŒจํ‚ค์ง€๋“ค์˜ package.json์— ํ•ด๋‹นํ•˜๋Š” task-key ๋ช…๋ น์–ด๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด turbo run build๋ฅผ ์‹คํ–‰ํ–ˆ๋‹ค๋ฉด ๋ชจ๋“  ํŒจํ‚ค์ง€์˜ build ๋ช…๋ น์–ด๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

 

๐Ÿ”Ž dependsOn

"dependsOn": ["^build"]

dependsOn์€ ์ž‘์—… ๊ฐ„์˜ ์˜์กด ๊ด€๊ณ„๋ฅผ ์„ค์ •ํ•˜๋Š” ์†์„ฑ์ž…๋‹ˆ๋‹ค.

์ฆ‰, ํŠน์ • ์ž‘์—…์„ ์‹คํ–‰ํ•˜๊ธฐ ์ „์— ๋‹ค๋ฅธ ์ž‘์—…์ด ๋จผ์ € ์‹คํ–‰๋˜๋„๋ก ์ง€์ •ํ•  ์ˆ˜ ์žˆ์–ด, ์ด๋ฅผ ํ†ตํ•ด ์ž‘์—… ์‹คํ–‰ ์ˆœ์„œ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์˜ˆ๋ฅผ ๋“ค์–ด ์•„๋ž˜์™€ ๊ฐ™์ด ์„ค์ •ํ•ด ๋‘์—ˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

{
  "tasks": {
    "build": {
      "dependsOn": ["^build"]
    },
    "lint": {
      "dependsOn": ["^lint"]
    },
    "test": {
      "dependsOn": ["build", "lint"]
    }
  }
}
  • "build": { "dependsOn": ["^build"] }
    • ^build๋Š” ํ˜„์žฌ ์ž‘์—…๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ์˜์กดํ•˜๋Š” ๋ชจ๋“  ํŒจํ‚ค์ง€์—์„œ build ์ž‘์—…์„ ๋จผ์ € ์‹คํ–‰ํ•˜๋„๋ก ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
    • build ์ž‘์—…์ด ์‹คํ–‰๋˜๊ธฐ ์ „์—, ๋ชจ๋“  ์˜์กด์„ฑ ํŒจํ‚ค์ง€๋“ค์˜ build ์ž‘์—…์ด ๋จผ์ € ์™„๋ฃŒ๋ฉ๋‹ˆ๋‹ค.
    • ์˜ˆ๋ฅผ ๋“ค์–ด, ui ํŒจํ‚ค์ง€๊ฐ€ web์„ ์˜์กดํ•˜๊ณ  ์žˆ์œผ๋ฉด, web์˜ build ์ž‘์—…์€ ui๊ฐ€ ๋จผ์ € ๋นŒ๋“œ๋œ ํ›„ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
  • "test": { "dependsOn": ["build", "lint"] }
    • test ์ž‘์—…์„ ์‹คํ–‰ํ•˜๊ธฐ ์ „์— build์™€ lint ์ž‘์—…์ด ๋จผ์ € ์™„๋ฃŒ๋˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
    • ๋”ฐ๋ผ์„œ, test๋Š” build์™€ lint๊ฐ€ ๋ชจ๋‘ ๋๋‚œ ํ›„์— ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

 

๐Ÿ”Ž ์บ์‹ฑ

turborepo์˜ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜์ธ ์บ์‹ฑ์€ ์—ฌ๋Ÿฌ ์†์„ฑ์— ์˜ํ•ด ์˜ํ–ฅ๋ฐ›๊ธฐ ๋•Œ๋ฌธ์— ํ•œ ๋ฒˆ์— ๋ฌถ์–ด์„œ ์„ค๋ช…๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

{
  "tasks": {
    "build": {
      "inputs": ["$TURBO_DEFAULT$", ".env*"],
      "outputs": [".next/**", "!.next/cache/**"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}
  • cache
    • ์บ์‹ฑ ํ™œ์„ฑํ™” ์—ฌ๋ถ€
    • false๋ฉด ๋งค๋ฒˆ ์ƒˆ๋กœ ์‹คํ–‰
  • presistent
    • ์ง€์† ์‹คํ–‰ ์—ฌ๋ถ€
    • true๋ฉด ์‹คํ–‰ ํ›„ ์ข…๋ฃŒ๋˜์ง€ ์•Š๊ณ  ๊ณ„์† ์‹คํ–‰
    • watch mode๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์‚ฌ์šฉ
  • inputs
    • ์บ์‹ฑ์„ ๋ฌดํšจํ™”ํ•  ํŒŒ์ผ ์ง€์ •
  • outputs
    • ํŠน์ • ํด๋”๋ฅผ ๋นŒ๋“œ ๊ฒฐ๊ณผ๋ฌผ๋กœ ์ง€์ •ํ•ด์„œ ๋ณ€ํ™” ์œ ๋ฌด์— ๋”ฐ๋ผ ์บ์‹ฑ

๊ทธ๋Ÿผ ํ„ฐ๋ณด๋ ˆํฌ๋ฅผ ์ด์šฉํ•ด ๋ชจ๋…ธ๋ ˆํฌ๋ฅผ ๊ตฌ์ถ•ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์—ฌ๊ธฐ์„œ ๋งˆ๋ฌด๋ฆฌํ•˜๋ฉฐ ์ด์ •๋„๋งŒ ์•Œ๊ณ  ์žˆ์–ด๋„ ์‹œ์ž‘ํ•˜๋Š”๋ฐ๋Š” ํฐ ๋ฌด๋ฆฌ๊ฐ€ ์—†์„ ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

์ €๋Š” ๊ณ„์† ํ•™์Šตํ•˜๋ฉฐ ๋นŒ๋“œ ๋ฐฉ๋ฒ•๊นŒ์ง€ ์†Œ๊ฐœํ•˜๋Š” ๊ธ€์„ ์˜ฌ๋ ค๋ณด๋„๋ก ๋…ธ๋ ฅํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€


์˜คํ”ˆ ์ฑ„ํŒ