← 글 목록

notes

Architect - 모노레포, 터보 레포

모노레포·Turborepo 구조와 패키지·빌드 파이프라인 구성 메모.

모노레포

모노레포 사용이유.

멀티 레포지토리에서 겪은 문제상황

  • 프로젝트마다 서로 다른 컨벤션 (코드, Git/브랜치)
  • 프로젝트마다 서로 다른 린트 환경과 코드 패턴들 (eslint, prettier, stylelint, tsconfig)
  • 프로젝트마다 서로 다른 라이브러리/프레임워크 사용 (react, vue, next)
  • 새로운 서비스(프로젝트)를 구축하기 위한 비용
  • 새로운 프로젝트를 생성할 때마다 서비스의 환경과 린트 환경을 반복적으로 세팅
  • 공통으로 사용하는 UI 컴포넌트, 패키지들을 새로운 환경에 맞게 반복 구현
  • 중복된 코드와, 프로젝트 관리에 대한 비효율
  • 각 서비스에서 사용하는 프로젝트의 라이브러리 버전이 통일되지 않음
  • 공통 MDS 컴포넌트, 정책에 변경 사항이 생겼을 경우 모든 레포지토리 담당자에게 수정 요청
  • 히스토리가 레포지토리 별로 흩어져 있음
  • 위와 같은 문제들로 인해서 해당 레포지토리 담당자 외의 다른 팀원이 해당 레포지토리에서 작업을 하려면 코드와 환경을 파악하기 위해 많은 시간이 발생했고, 새로운 사람이 프로젝트를 맡게 되었을 때 초기 온보딩 비용이 많이 들어갔습니다.

모노레포 구성하기.

  • pnpm init
  • package.json에 "packageManager": "pnpm@[version예)1.0.0]" 추가하기
  • pnpm.workspace.yaml 생성
  • pnpm.workspace.yaml에 아래 내용 추가하기
packages:
-"packages/*"
- "apps/*";

폴더 구조

apps - 서비스

  • user - passblock 사용자 서비스
  • admin - passblock 관리자 서비스 pacakages - 공통으로 사용하는 패키지
  • api - api 서버
  • shared - 공통으로 사용할 components,hooks,utils (React)

공통 라이브러리

1. ag-grid - 테이블

2. lottiefile - 애니메이션

3. react-hook-form - 폼

4. tailwindcss - css

tailwindcss 를 사용하기 위해선 일단 shared에서 tailwindcss.config.js, postcss.config.js를 추가해준다.

tailwind.config.js는 아래와 같이 설정해주자.


/** @type {import('tailwindcss').Config} */

module.exports = {
content: [
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
extend: {},
},
plugins: [],
};

아래와 같이 설정이 완료하고 tailwindcss를 이용해 컴포넌트까지 완성했다면 실제 프로젝트 tailwind.config.js 에서도 다음과 같이 추가해줘야한다.


import type { Config } from "tailwindcss";
const config: Config = {
content: [
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
"../../packages/shared/src/components/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {},
plugins: [],
};

export default config;

패키지 공유하기


pnpm --filter [패키지명 A] add [패키지명 B] --workspace

// A서비스에서 B패키지를 의존하고싶을 때

루트레벨 라이브러리 프로젝트에서 사용하기

pnpm을 사용하는 모노레포에서 루트 레벨에서 설치한 라이브러리를 하위 프로젝트에서 사용 할 수 있습니다.

그러나 이를 위해선 루트레벨의 pacakage.json 파일에서 해당 라이브러리를 dependencies에 명시적으로 추가 해주고

각 하위 프로젝트 에서도 해당 라이브러리를 dependencies에 명시적으로 추가 해주어야 합니다.

아래와 같이 설정하면 됩니다.


// root 레벨 package.json
"dependencies": {
"ag-grid": "^25.3.0"
}

// 하위 프로젝트 package.json
"dependencies": {
"ag-grid": "^25.3.0"
}

터보레포


모노레포를 효율적으로 생성관리 가능

Turborepo 공식(turbo.build) 기준으로 구조를 맞춘다.

공식문서

project 구조 및 동작원리 (whith. tailwind 연결 )

packages -> 해당 폴더는 공통 요쇼로 사용될 파일들의 집합체 
 

//package.json 연결구문 


 "@repo/eslint-config": "workspace:*",
 "@repo/typescript-config": "workspace:*",
 

// tsconfig.lint.json

{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "outDir": "dist"
  },
  // 인식 ,"tailwind.config.js","postcss.config.js"
  "include": ["src", "turbo","tailwind.config.js","postcss.config.js"],
  "exclude": ["node_modules", "dist"]
}

//components.json
// aliases-> 별칭 지정
{
    "$schema": "https://ui.shadcn.com/schema.json",
    "style": "default",
    "rsc": true,
    "tsx": true,
    "tailwind": {
      "config": "tailwind.config.js",
      "css": "css/styles.css",
      "baseColor": "slate",
      "cssVariables": true
    },
    "aliases": {
      "components": "@ui/components/*",
      "utils": "@ui/lib/clsx.utils"
    }
  }

// tsconfig.json


{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    //"outDir": "dist"
    "baseUrl": ".",
    // 패스 설정  => 공통 알리아스 
    "paths": {
      "@ui/*": ["./src/*"],
      "@ui/components/*": ["./src/components/*"],
    }
  },
  "include": ["."],
  "exclude": ["node_modules", "dist"]
}

packages / ui 에 설정한

tailwind.config , postcss.config 를 각각 프로젝트에 연결만 해주면 되며 tsconfig.json 혹은 package.json 의 export 기능을 사용하면 aliases(별칭)를 사용가능

연결구문은

CommonJS , AMD 택 1 로 연결 (파일 스코프로 전역 연결 )

module.exports = require("@repo/ui/tailwind.config");

혹은 

import type { Config } from "tailwindcss";

    const config: Config = {
      theme: {
        extend: {
          colors: {
          }
        }
      },
      plugins: []
    };
    export default config;

1. 프로젝트 구조

프로젝트 구조는 다음과 같이 구성됩니다.

my-turborepo/
├── apps/
│   └── web/
│       ├── src/
│       │   └── index.jsx
│       ├── package.json
│       └── ...
└── packages/
    └── ui/
        ├── src/
        │   └── styles.css
        ├── package.json
        └── ...
├── turbo.json
└── package.json

2. 패키지 설정

각 패키지(apps/web 및 packages/ui)의 package.json 파일에는 서로 의존성을 설정합니다. 예를 들어, web 패키지는 ui 패키지를 의존성으로 가집니다.

apps/web/package.json

{
  "name": "web",
  "version": "1.0.0",
  "main": "src/index.jsx",
  "dependencies": {
    "ui": "workspace:*"
  }
}

packages/ui/package.json

{
  "name": "ui",
  "version": "1.0.0",
  "main": "src/index.js",
  "dependencies": {
    "@material-design-icons/font": "^0.6.1"
  }
}

3. Turborepo 설정

turbo.json 파일은 Turborepo가 작업을 어떻게 수행할지 정의합니다. 이 예제에서는 build, lint, test, dev와 같은 작업을 정의하고 있습니다. 실제로 공통 CSS와 Material Icons 폰트를 사용하는 경우에는 패키지 간 의존성을 설정하는 것이 중요합니다.

turbo.json

{
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"]
    },
    "lint": {
      "outputs": []
    },
    "test": {
      "outputs": []
    },
    "dev": {
      "cache": false
    }
  }
}

turbo.json 설명

  • build: 각 패키지의 build 작업이 다른 패키지의 build 작업에 의존합니다. 예를 들어, web 패키지는 ui 패키지의 build 작업에 의존합니다. 따라서 web 패키지를 빌드하기 전에 ui 패키지가 먼저 빌드됩니다.
  • outputs: build 작업의 출력 디렉토리를 정의합니다. 여기서는 dist/** 디렉토리가 빌드 출력물입니다.
  • lint, test, dev: 각각의 작업에 대한 설정입니다. 여기서는 출력물이 없거나 캐시를 사용하지 않도록 설정되었습니다.

4. 빌드 및 실행

각 패키지의 의존성을 설치하고 빌드 작업을 실행합니다.

bash코드 복사
# 루트 디렉토리에서 의존성 설치
npm install

# 모든 패키지의 build 작업 실행
npx turbo run build
"build": "tsc --build",
// ui 빌드후 사용