Nx에서 마이그레이션

이 가이드는 기존 Nx 리포지토리를 Turborepo로 마이그레이션하는 데 도움이 됩니다.

왜 전환하나요?

Nx에서 Turborepo로 마이그레이션하려는 이유는 여러 가지가 있습니다. 아래에 개발자들이 마이그레이션을 위해 참조한 가장 일반적인 동기를 나열했습니다.

생태계 표준 사용

Turborepo의 목표는 리포지토리를 진실의 원천으로 삼아 경량화하는 것입니다. 이에 대한 예로 Turborepo가 JavaScript/TypeScript 지원을 위해 JavaScript 패키지 매니저 워크스페이스 위에 구축된 것이 있습니다.

반면 Nx는 플러그인, 종속성 및 기타 Nx 전용 코드 계층을 사용하여 리포지토리에 대한 정보를 추론합니다. 이러한 플러그인은 기능 계층을 제공할 수 있으며 선택 사항이지만, 마이그레이션을 원하는 Nx 사용자는 코드베이스에서 Nx 전용 코드를 제거하는 것을 변경의 주요 동기로 자주 언급합니다.

소스 코드에 대한 더 큰 제어

Nx의 철학은 플러그인, 종속성 및 Nx 전용 코드 계층으로 코드를 래핑하는 것입니다. 이러한 코드 계층은 선택 사항이지만 Nx의 많은 가치를 제공하며 Nx에서 권장하므로 대부분의 Nx 리포지토리에 있습니다. Turborepo로 마이그레이션할 때 많은 개발자는 이러한 계층이 리포지토리를 제어에서 추상화하는 난독화 계층을 만들어 문제를 일으키는 경향이 있다고 설명합니다.

Turborepo는 원하는 대로 도구를 설정(또는 설정하지 않음)하여 자신의 조건에 따라 도구를 처리할 수 있도록 선택합니다.

리포지토리 매니저를 위한 더 적은 설정

Turborepo는 리포지토리의 요구 사항을 자동으로 추론하므로 Turborepo로 마이그레이션하려면 Nx에 대해 가지고 있던 이전 설정을 삭제하고 Turborepo에 대한 더 적은 설정으로 대체해야 할 가능성이 높습니다. 예를 들어, 다음은 아래에서 사용된 Turborepo 및 Nx의 동등한 스타터에서 찾을 수 있는 도구별 설정입니다.

Turborepo logo
turbo.json
{
  "$schema": "/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
    }
  }
}

마이그레이션 단계

이 마이그레이션의 목표는 가능한 한 빨리 작동하는 Turborepo 작업을 얻어 Turborepo 기능을 점진적으로 채택할 수 있도록 하는 것입니다. Nx 스캐폴더를 사용하여 Next.js 앱이 있는 리포지토리를 만드는 것부터 시작하겠습니다.

Terminal
npx create-nx-workspace --preset=next --ci=skip --e2eTestRunner=none --style=tailwind --nextAppDir=true --nextSrcDir=false --packageManager=pnpm --appName=starter

1단계: .gitignore 업데이트

Turborepo는 .turbo 디렉토리를 사용하여 리포지토리에 대한 로컬 캐시 및 기타 정보를 보관합니다. 이러한 이유로 .gitignore에 추가해야 합니다.

.gitignore
.turbo

2단계: 워크스페이스 정의 추가

Turborepo는 JavaScript 생태계 표준인 패키지 매니저 워크스페이스 위에 구축되었습니다. 패키지를 포함할 워크스페이스에 디렉토리 경로를 추가합니다.

pnpm-workspace.yaml
packages:
  - apps/*

3단계: 애플리케이션에 package.json 추가

project.json과 같은 추가 설정 파일을 추가하는 대신 Turborepo는 표준 package.json 파일을 사용합니다.

starter 애플리케이션에 package.json을 추가합니다. devbuild 스크립트가 포함된 package.json./apps/starter/package.json에 만듭니다.

./apps/starter/package.json
{
  "name": "starter",
  "scripts": {
    "dev": "next dev",
    "build": "next build"
  }
}

4단계: Nx 플러그인 제거

./apps/starter/next.config.js에서 Nx 플러그인을 제거합니다. 아래 예제 파일에는 설정이 없지만 기존 Next.js 애플리케이션에는 일부가 필요할 수 있습니다.

./apps/starter/next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {};
 
module.exports = nextConfig;

5단계: packageManager 필드 추가

루트 package.json에 packageManager 필드가 있어야 합니다. 이를 통해 리포지토리의 개발자가 올바른 패키지 매니저를 사용하고 Turborepo가 lockfile을 기반으로 패키지 그래프를 최적화할 수 있습니다.

./package.json
{
  "packageManager": "pnpm@9.0.0"
}

6단계: 패키지 매니저의 설치 명령 실행

설치 명령을 실행하여 lockfile을 업데이트합니다.

Terminal
pnpm install

이 작업을 완료하면 패키지가 패키지 매니저의 워크스페이스에 추가되었음을 나타내는 lockfile diff가 표시되어야 합니다.

7단계: Turborepo 설치

워크스페이스의 루트 package.json에 Turborepo를 추가합니다.

Terminal
pnpm add turbo --save-dev --workspace-root

Turborepo 작업 시 편의성을 높이기 위해 turbo를 전역으로 설치할 수도 있습니다.

Terminal
pnpm add turbo --global

8단계: turbo.json 추가

루트에 turbo.json을 생성하여 작업을 등록하고 작업 종속성을 설명합니다.

Turborepo logo
./turbo.json
{
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "!.next/cache/**"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}

9단계: turbo build 실행

Turborepo로 애플리케이션을 빌드합니다. 전역 turbo를 사용하면 turbo build입니다. 패키지 매니저를 통해 명령을 실행할 수도 있습니다:

Terminal
pnpm exec turbo build

10단계: Remote Caching 활성화 (선택 사항)

기본적으로 Turborepo는 다음을 실행할 때 무료로 사용 가능한 Vercel Remote Cache에 연결됩니다:

Terminal
turbo login
turbo link

자체 호스팅 Remote Cache를 구성할 수도 있습니다.

고급 마이그레이션 고려 사항

위의 마이그레이션 가이드는 좋은 시작점이지만 모노레포의 가능성과 기능의 폭이 넓기 때문에 모든 경우에 대한 일반화된 지침을 만들기 어렵습니다. 아래에 고려할 수 있는 몇 가지 일반적인 다음 단계를 나열했습니다.

복잡한 모노레포를 점진적으로 마이그레이션

점진적 마이그레이션을 권장합니다. 즉, 리포지토리에 Nx와 Turborepo가 동시에 있게 됩니다. Nx 작업 그래프가 어떻게 구성되는지 이해하는 데 시간을 투자하세요. 작업 그래프를 분할하는 전략에는 다음이 포함될 수 있습니다:

  • 한 번에 하나의 작업 마이그레이션: nx run lintturbo run lint로 변경
  • 한 번에 하나의 패키지/프로젝트 마이그레이션: nx run-many lint test --projects=webturbo run lint test --filter=web로 변경
  • 일부 작업을 이중 실행: 안정성을 보장하기 위해 마이그레이션 초기 단계에서 익숙해지고 확신을 구축하는 동안 turbo run lint nx run lint를 실행하도록 선택할 수 있습니다.

사용되는 곳에 종속성 설치

Turborepo는 캐시 적중률을 개선하고 종속성 정리 기능을 지원하며 개발자에게 어떤 패키지에 어떤 종속성이 사용되는지 명확히 하기 위해 사용되는 곳에 패키지를 설치할 것을 권장합니다. 이는 모든 종속성이 리포지토리의 루트에 설치되어 워크스페이스의 모든 패키지에서 모든 종속성을 사용할 수 있는 Nx 전략과 다릅니다.

역사적으로 Nx는 모든 종속성을 리포지토리의 루트에 설치하여 워크스페이스의 모든 패키지에서 모든 종속성을 사용할 수 있도록 권장했습니다. 이 지침을 따랐다면 필요한 패키지 및 애플리케이션의 package.json으로 종속성을 이동하는 것을 강력히 권장합니다. 자세한 내용은 종속성 관리에 대한 문서를 참조하세요.

공유 패키지 생성

패키지 매니저의 워크스페이스에 패키지를 추가하려면 위와 거의 동일한 단계를 따릅니다.

  1. 패키지의 디렉토리가 워크스페이스 정의(예: ./packages/*)에 포함되어 있는지 확인합니다.
  2. 실행해야 하는 스크립트가 있는 package.json을 패키지에 추가합니다.
  3. turbo.json에서 작업 종속성을 확인하여 종속성 그래프가 요구 사항을 충족하는지 확인합니다.

다중 언어 모노레포

Turborepo는 JavaScript 및 TypeScript를 기본적으로 지원하며 사용하려는 다른 언어에 대한 보조 지원을 제공합니다. 자세한 내용은 다중 언어 지원 문서를 참조하세요.

설정 동등성

nx.json에서 발견되는 설정은 아래 표를 사용하여 turbo.json에 매핑할 수 있습니다.

파일 캡처를 위한 대부분의 glob은 Nx와 Turborepo 간에 동일합니다. 자세한 내용과 엣지 케이스는 파일 glob 사양을 참조하세요.

전역 설정

NxTurborepo
sharedGlobalsglobalDependencies
sharedGlobals.envglobalEnv
sharedGlobals.namedInputglobalDependencies
cacheDirectorycacheDir

작업 설정

NxTurborepo
inputs filestasks[task].inputs
inputs.envtasks[task].env
outputs filestasks[task].outputs
cachetasks[task].cache

CLI 동등성

NxTurborepo
nx generateturbo generate
nx runturbo run
nx run-manyturbo run
nx reset--force
--parallel--concurrency
--nxBail--continue
--projects--filter
--graph--graph
--output-style--log-order
--no-cloud--cache
--verbose--verbosity