TurboRepo 살펴보기

hodu·2024년 2월 12일
6
post-thumbnail

✅ 개요

연휴를 맞이하여 시간적 여유가 생겼기에, 이번 기회에 모노레포 구축에 도전하기로 결정했습니다.

본 글에서는 TurboRepo의 설치 과정과 작동 원리를 탐색하고, 실제로 적용해보는 과정을 단계별로 소개할 예정입니다.

  1. TurboRepo 설치하기
  2. ESLint config를 통해 모노레포 동작 방식 이해하기
  3. tailwindCSS 공통으로 적용해보기


🚩 TurboRepo 설치 과정

모노레포 구축을 위해 공식 문서를 참고하여 TurboRepo 설치를 시작했습니다.

가장 먼저, 모노레포를 전역 환경에 설치하는 것으로 출발했습니다.

npm install turbo --global

전역 설치를 완료 한 후, 새로운 모노레포 프로젝트 생성을 위해 아래 명령어를 실행했습니다.

npx create-turbo@latest

이 과정을 통해 turborepo에서 권장하는 기본 세팅을 할 수 있습니다.

실행이 끝이 나면 appspackages 두 개의 폴더를 생성합니다.

apps 폴더

이 폴더에는 개별 프로젝트들이 위치합니다. 초기 설정으로 docsweb이라는 두 개의 Next.js 최신 버전 프로젝트가 생성됩니다.

packages 폴더

모노레포 내에서 공통적으로 사용될 설정 파일이나 UI 컴포넌트를 담는 곳입니다.
초기 상태에는 eslint-configts-config가 포함되어 있으며, 공용 UI 컴포넌트도 여기에 위치합니다.

최상위 package.json

설치를 완료하면, 다양한 스크립트 명령어가 package.json 파일에 추가됩니다. 이를 통해 최상위 폴더에서 여러 앱을 통합적으로 실행하거나 빌드할 수 있습니다.

Prettier, ESLint, 그리고 Turbo를 활용해 여러 스크립트를 실행할 수 있으며, 필요에 따라 추가적인 스크립트를 구성할 수 있습니다. 전역적으로 작업을 진행하고자 한다면, 이곳에 필요한 도구를 설치하고 Turbo를 통해 관리하면 됩니다.

이제 TurboRepo가 어떤 방식으로 작동하는지 packages에 eslint 설정을 살펴보며 알아보겠습니다.



👀 모노레포 공통 파일 관리하는 방법 살펴보기 (with ESLint)

모노레포 구조에서 packages 디렉토리는 프로젝트 전반에 걸쳐 공통적으로 사용될 설정, 라이브러리, 컴포넌트 등을 관리하는 공간입니다.
이번 섹션에서는 packages 내의 eslint-config 설정을 예로 들어, 모노레포 내에서 공통 설정을 어떻게 적용하고 사용하는지 설명하겠습니다.

eslint-config 설정

eslint-config 폴더는 ESLint 설정을 위한 공간으로, 다양한 프로젝트 유형(예: 라이브러리용, Next.js용 등)에 맞춰 ESLint 설정을 제공합니다. 현재 구조는 다음과 같습니다:

library.js  next.js  node_modules/  package.json  react-internal.js  README.md

위와 같은 구조를 이룹니다.
이름을 보면 라이브러리용, next 용 이렇게 보입니다.

먼저 eslint-config에 package.json을 살펴보겠습니다.

{
  "name": "@repo/eslint-config",
  "version": "0.0.0",
  "private": true,
  "files": [
    "library.js",
    "next.js",
    "react-internal.js"
  ],
  "devDependencies": {
    "@vercel/style-guide": "^5.1.0",
    "eslint-config-turbo": "^1.11.3",
    "eslint-config-prettier": "^9.1.0",
    "eslint-plugin-only-warn": "^1.1.0",
    "@typescript-eslint/parser": "^6.17.0",
    "@typescript-eslint/eslint-plugin": "^6.17.0",
    "typescript": "^5.3.3"
  }
}

이 구조에서 주목해야 할 주요 요소는 다음과 같습니다.

  1. 패키지 이름: package.json에서 정의한 패키지 이름(@repo/eslint-config)을 통해, 다른 프로젝트에서 이 ESLint 설정을 npm install @repo/eslint-config 명령어로 설치할 수 있습니다.

  2. files 필드: package.jsonfiles 필드에는 library.js, next.js, react-internal.js와 같이 공개하고자 하는 설정 파일들이 명시되어 있습니다. 이는 패키지를 설치할 때 이 파일들만이 포함됨을 의미합니다.
    extends: ["@repo/eslint-config/next.js"] 이와 같은 방식으로 files에 있는 파일들을 불러와 .eslintrc.js에서 사용합니다.

  3. 설치된 의존성: devDependencies에는 ESLint 설정에 필요한 다양한 플러그인과 설정 패키지가 포함되어 있습니다.
    중요한 점은 이곳에 ESLint 자체가 포함되어 있지 않다는 것입니다.
    이는 eslint-config가 실제 ESLint 실행을 위한 것이 아니라, ESLint를 위한 설정을 제공하기 위한 것임을 의미하고, 여기서 사용할 의존성만을 설치한다는 것입니다.

이제는 esconfig 파일을 어떤 식으로 작성했는지 살펴보겠습니다.


eslint-config/next.js 살펴보기

우리는 eslint 설정을 할 때, tsconfig를 불러오는 경우가 있습니다.
각 프로젝트별로 이를 불러와서 사용하는 방법이 필요할 것입니다.
그래서 최상단을 살펴보면 이 문제를 해결한 코드가 있습니다.

  1. 동적 tsconfig.json 로드: next.js 설정 파일을 살펴보면 상단에 위치한 코드는 현재 프로젝트의 tsconfig.json 파일을 동적으로 찾아와서 ESLint에 연결합니다.

이는 ESLint가 TypeScript 설정을 인식하게 하여, 프로젝트에 맞는 타입 체크와 규칙 적용이 가능하게 합니다.

    const { resolve } = require("node:path");
    const project = resolve(process.cwd(), "tsconfig.json");
   settings: {
    "import/resolver": {
      typescript: {
        project,
      },
    },
  },
  1. extends 구성: ESLint의 extends 옵션을 통해 다양한 ESLint 규칙 및 설정을 상속받습니다.
    여기서 주목할 점은 eslint-config/package.json에 설치한 것들만 넣었다는 점입니다.
    설정 파일에 설치한 것은 이 파일을 구성하는데 필요한 것들만 다운 받기 때문입니다.
    extends: [
      "eslint:recommended",
      "prettier",
      require.resolve("@vercel/style-guide/eslint/next"),
      "eslint-config-turbo",
    ],

이를 통해 packages/eslint-config에서 어떤식으로 준비하였는지 살펴보았고,
이제 apps에서 어떻게 적용하는지 보겠습니다.

😎 공통 설정을 프로젝트별로 적용하는 방법

  1. apps 내 프로젝트 설정: 우리는 apps/web 프로젝트를 살펴보겠습니다.
    apps/web/package.json에는 @repo/eslint-config가 의존성으로 추가합니다.

이는 eslint-config 에 설정한 이름과 동일하며, 이를 가져와 프로젝트에 설치하고 사용할 수 있음을 의미합니다.

    "@repo/eslint-config": "*"
  1. ESLint 설정 파일에서의 활용: web/.eslintrc.js와 같은 ESLint 설정 파일에서 @repo/eslint-config/next.jsextends에 추가함으로써, 공통 ESLint 설정을 해당 프로젝트에 적용할 수 있습니다.

이는 eslint-config 에 설정한 파일 이름을 불러와 사용하는 것입니다.

    module.exports = {
      root: true,
      extends: ["@repo/eslint-config/next.js"],
      parser: "@typescript-eslint/parser",
      parserOptions: {
        project: true,
      },
    };
  1. 최상위 package.json의 활용: 최상위 package.json.eslintrc.js에서도 @repo/eslint-config와 같은 공통 패키지를 참조하여 설정을 적용할 수 있습니다.

최상위 package.json

{
  "name": "my-turborepo",
  "devDependencies": {
    "@repo/eslint-config": "*",
    "@repo/typescript-config": "*",
    "prettier": "^3.1.1",
    "turbo": "latest"
  },
}

최상위 .esconfigrc.js

// This configuration only applies to the package manager root.
/** @type {import("eslint").Linter.Config} */
module.exports = {
  ignorePatterns: ["apps/**", "packages/**"],
  extends: ["@repo/eslint-config/library.js"],
  parser: "@typescript-eslint/parser",
  parserOptions: {
    project: true,
  },
};

실제로 어떻게 적용하였는지 살펴보았습니다.
이제는 우리가 packages에 폴더를 만들고 이를 프로젝트에 적용해보고
동작 방식을 올바르게 이해했는지 확인해보겠습니다.


🙌 모노레포 환경에서 Tailwind CSS 설정 적용하기

모노레포 구조에서 packages 디렉토리를 활용해 공통 설정을 관리하는 방법을 탐구하여, 모노레포에 대한 이해를 높혀보겠습니다.

Tailwind CSS 설정 준비

  1. 설정 폴더 및 파일 생성: packagestailwind-config 폴더를 생성하고, 필요한 package.json 및 설정 파일들을 작성합니다. 이 폴더 내에서 Tailwind CSS 관련 설정을 중앙에서 관리할 수 있습니다.
    {
      "name": "@repo/tailwind-config",
      "version": "0.0.0",
      "private": true,
      "exports": { ".": "./tailwind.config.ts" },
      "devDependencies": {
        "@repo/typescript-config": "*",
        "tailwindcss": "^3.4.0"
      }
    }

name
먼저 이름은 기존 방식에 맞추어 @repo/tailwind-config로 설정해주었습니다.
이름에 맞추어 설치하여서 설정을 가져올 수 있게 할 것입니다.

private
private은 이를 외부에 공개하지않고 내부적으로 사용하기 위해 작성해주었습니다.

exports
exports에 작성하면 이를 import 해서 사용할 수 있습니다.

import sharedConfig from "@repo/tailwind-config";

파일 이름 tailwind.config.ts로 작성할 것이므로 미리 작성해주었습니다.

devDependencies
우리는 ts를 통해 tailwindCSS를 작성할 것이고,
tailwindCSS가 가지고 있는 type이 필요하므로 이를 설치하였습니다.


  1. TypeScript 설정 연결: tailwind-config 내에 tsconfig.json 파일을 생성하여, @repo/typescript-config의 기본 설정을 확장합니다. 이는 TypeScript를 사용하는 Tailwind 설정 파일의 타입 체킹을 지원합니다.

    {
      "extends": "@repo/typescript-config/base.json",
      "include": ["."],
      "exclude": ["dist", "build", "node_modules"]
    }
  2. Tailwind 설정 파일 작성: Tailwind CSS 설정을 정의하는 tailwind.config.ts 파일을 작성합니다. 이 설정 파일에서는 프로젝트별로 다르게 설정될 수 있는 content 필드를 제외하고, 테마 확장, 플러그인 추가 등의 공통 설정을 정의합니다.

    import type { Config } from "tailwindcss";

    const config: Omit<Config, "content"> = {
      theme: {
        extend: {
          colors: {
            "custom-blue": "#007bff"
          }
        }
      },
      plugins: []
    };
    export default config;

이제 기본적인 세팅은 끝이 났고, 이를 apps에 있는 프로젝트에 적용해보겠습니다.

Tailwind CSS 모노 레포에 적용하기

  1. 필요한 패키지 설치: apps/web 프로젝트에서 tailwindcss, postcss, autoprefixer, 그리고 중앙에서 관리되는 @repo/tailwind-config를 설치합니다.
    yarn add -D tailwindcss postcss autoprefixer @repo/tailwind-config
  1. PostCSS 및 Tailwind 설정 파일 작성: postcss.config.tstailwind.config.ts 파일을 생성하고, 공통 Tailwind 설정을 import하여 적용합니다.
    이를 통해 apps/web 프로젝트에 packages에서 만든 설정을 적용할 수 있습니다.

tailwind.config.ts


    import sharedConfig from "@repo/tailwind-config";
    import type { Config } from "tailwindcss";

    const config: Pick<Config, "content" | "presets"> = {
      content: ["./app/**/*.tsx"],
      presets: [sharedConfig]
    };

    export default config;

아래 작성도 해주셔야합니다.

postcss.config.ts

    module.exports = {
      plugins: {
        tailwindcss: {},
        autoprefixer: {}
      }
    };

global.css

@tailwind base;
@tailwind components;
@tailwind utilities;
  1. 스타일 적용 확인: 테스트 컴포넌트에 Tailwind CSS 클래스를 사용하여 스타일이 정상적으로 적용되는지 확인합니다.
    <main>
      <div className="text-custom-blue">테일윈드 확인용</div>
    </main>

우리가 packages에 작성했던 custom-blue가 작동하는 것을 확인하였습니다.
이를 통해 tailwind-config에서 잘 작성했는지 확인할 수 있었습니다.

위와 같은 방식으로 모노레포 구조를 만들어주고 관리한다면 효과적으로 만들 수 있을 것입니다.


이를 끝으로 간략하게 모노레포에 대해 알아보았습니다.

아쉬운 점이나 설명이 이상한 점이 있다면 댓글로 남겨주시면 감사하겠습니다.


출처 : https://turbo.build/

profile
잘부탁드립니다.

0개의 댓글