Nx로 프로젝트 관리해보면 어떨까?

기운찬곰·2023년 11월 18일
1

프론트개발이모저모

목록 보기
18/20
post-thumbnail

Overview

갑자기 왜 Nx 인가 싶은데, 일단 제가 영향을 받은건 역시나 모노레포...! 저번에도 한번 다뤘던 내용이고 그때는 Turbo에 대해 살펴봤지만 다소 아쉽게 끝냈던 내용이라서요. 그리고 면접을 다니다보니 회사마다 어떤 기술을 사용하는지 대략적으로 파악이 가능했는데요. 좀 괜찮은 회사는 모노레포를 많이들 사용하는거 같더라고요? 특히 Turbo나 Nx, Lerna 같은 모노레포 지원 툴을 많이 쓴다고 하고요. 그래서 이번에 저는 Turbo 대신 Nx에 대해 알아봤습니다.


모노레포 지원 도구 비교

참고 : https://npmtrends.com/lerna-vs-nx-vs-turbo

가장 많이 사용된다고 생각하는 3대장하면 Nx, Turbo, Lerna가 있는데요. 이를 npm trends로 비교해보면 다음과 같습니다.

Nx가 2배이상 사용자가 많군요. Turbo는 Lerna를 제치고 2위로 올라왔습니다. Lerna는 좀 더 분발해야겠네요.


Nx 공식 문서

메인 페이지 소개

참고: https://nx.dev/

한줄 소개 - Smart, Fast Extensible Build System (똑똑하고, 빠르게 확장 가능한 빌드 시스템)

최고 수준의 모노레포 지원 및 강력한 통합을 갖춘 차세대 빌드 시스템입니다. 당신의 작업 공간에 단일 프로젝트가 있든 수천 개가 있든 Nx는 CI를 빠르게 유지하고 작업 공간을 유지 관리할 수 있습니다.

당신의 시간을 낭비하지 마세요. Nx를 사용하면 확장이 쉬워집니다. distributed task execution(분산 작업 실행)computation caching(계산 캐싱) 과 같은 최신 기술을 사용하면 작업 공간에 프로젝트를 계속 추가하더라도 CI 시간을 빠르게 유지할 수 있습니다.

Intro to Nx

참고 : https://nx.dev/getting-started/intro

Nx는 개발자 생산성 향상, CI 성능 최적화 및 코드 품질 유지를 위한 도구와 기술을 제공하는 강력한 오픈 소스 빌드 시스템입니다. Nx가 무엇인지 자세히 알아보려면 동영상을 시청하세요.

핵심 기능은 다음과 같습니다.

  • 효율적으로 작업 실행: Nx는 작업을 병렬로 실행하고 작업 간의 종속성에 따라 작업 순서를 지정합니다.
  • 로컬 및 원격 캐시: Nx는 로컬 및 원격 캐싱을 통해 불필요한 작업 재실행을 방지하여 귀중한 개발 시간을 절약합니다.
  • 종속성 업데이트 자동화: Nx 플러그인을 활용하면 코드 생성 및 도구와 같은 추가 기능을 사용하여 코드베이스 및 종속성을 자동으로 업그레이드할 수 있습니다.
  • 나만의 것을 만드세요: Nx는 고도로 사용자 정의 가능하고 확장 가능합니다. 자신만의 플러그인을 만들어 세부적으로 조정하고 선택적으로 커뮤니티와 공유하세요.

구체적인 기능별 특징을 알아보고 싶다면 https://nx.dev/core-features 를 참조하세요.

Why Nx?

참고 : https://nx.dev/getting-started/why-nx

개발자들이 다양한 도구와 프레임워크를 구성, 유지 관리, 특히 통합하는 데 어려움을 겪고 있기 때문에 우리는 Nx를 만들었습니다. 소수의 개발자에게 잘 작동하는 동시에 전체 조직으로 쉽게 확장할 수 있는 시스템을 설정하는 것은 어렵습니다. 여기에는 하위 수준 빌드 도구 설정, 빠른 CI 구성, 코드베이스를 정상적이고 최신 상태로 유지 관리 가능하게 유지하는 것이 포함됩니다. 우리는 채택과 확장이 쉬운 솔루션을 제공하고 싶었습니다.

Q. 어떻게 도울 수 있는데?

A. 간단히 말해서 Nx는 로컬 및 CI에서 계산(예: 빌드, 테스트 등) 속도를 높이고 플러그인을 통해 도구를 통합하고 자동화하는 데 도움이 됩니다. 이 모든 것은 점진적으로 채택될 수 있습니다. 플러그인을 사용할 수 있지만 반드시 그럴 필요는 없습니다. 자세한 내용은 다음 섹션의 Nx 아키텍처를 참조하세요.

Nx를 사용하여 다음을 수행할 수 있습니다.

  • 로컬 및 CI에서 기존 프로젝트의 빌드 및 테스트 속도를 높입니다 (단일 저장소이든 독립 실행형 애플리케이션이든 관계 없음)
  • 하위 수준 빌드 도구를 구성할 필요 없이 Nx 플러그인을 사용하여 새 프로젝트를 빠르게 스캐폴드합니다.
  • 새로운 도구(예: Storybook, Tailwind 등)를 프로젝트에 쉽게 통합할 수 있습니다.
  • 맞춤형 생성기와 Lint 규칙을 사용하여 일관성과 코드 품질을 보장합니다.
  • 자동화된 코드 마이그레이션 기능을 사용하여 프레임워크와 도구를 업데이트하고 작업 공간을 상시 유지하세요.

Q. 어떻게 동작하는가?

Nx는 필요한 기능만 사용할 수 있도록 모듈식 방식으로 구축되었습니다.

  • Nx 패키지는 작업 공간 분석, 작업 실행, 캐싱, 배포, 코드 생성 및 자동화된 코드 마이그레이션과 같은 기술에 구애받지 않는 기본적인 기능을 제공합니다.
  • 플러그인은 Nx 패키지에서 제공하는 기본 기능을 기반으로 구축된 NPM 패키지입니다. Nx 플러그인에는 코드 생성기, 실행기(하위 수준 빌드 도구를 추상화하기 위한) 및 도구를 최신 상태로 유지하기 위한 자동화된 코드 마이그레이션이 포함되어 있습니다. 동일한 방식으로 작동하는 Nx 패키지와 달리 플러그인은 일반적으로 기술에 따라 다릅니다. 예를 들어 @nx/react는 React 앱 및 라이브러리 구축에 대한 지원을 추가하고, @nx/cypress는 Cypress를 사용하여 e2e 테스트 기능을 추가합니다. 플러그인은 서로 다른 도구를 서로 통합하는 데 따른 마찰을 제거하고 도구를 최신 상태로 유지하는 유틸리티를 제공함으로써 개발자의 생산성을 높여줍니다. Nx 팀은 React, Next, Remix, Angular, Jest, Cypress, Storybook 등을 위한 플러그인을 유지 관리합니다. @nx/plugin 패키지를 사용하면 새 플러그인을 쉽게 스캐폴딩하거나 로컬 작업 공간을 자동화할 수도 있습니다.
  • Devkit은 Nx 플러그인을 빌드하기 위한 유틸리티 세트입니다.
  • Nx Cloud는 원격 캐싱 및 분산 작업 실행을 추가하여 CI에서 프로젝트를 확장하는 데 도움이 됩니다. 또한 GitHub, GitLab 및 BitBucket과 통합하고 검색 가능한 구조화된 로그를 제공하여 개발자 생산성을 향상시킵니다. nx.app에서 자세히 알아보세요.
  • Nx 콘솔은 VSCode, IntelliJ 및 VIM의 확장입니다. 코드 자동 완성, 대화형 생성기, 작업 공간 시각화, 강력한 리팩토링 등을 제공합니다.

튜토리얼

공식 문서에 나와있는 튜토리얼을 따라해보면서 위에서 설명한 기능에 대해 체감해보도록 하겠습니다.

1. Getting Started with Package-Based Repos

참고 : https://nx.dev/getting-started/tutorials/package-based-repo-tutorial

새 작업 공간을 만드는 것부터 시작해봅시다. 다음 명령을 사용해서 프로젝트를 생성할 수 있습니다.

❯ npx create-nx-workspace@latest package-based --preset=npm
Need to install the following packages:
  create-nx-workspace@17.1.1
Ok to proceed? (y) y

 >  NX   Let's create a new workspace [https://nx.dev/getting-started/intro]

✔ Enable distributed caching to make your CI faster · Yes

 >  NX   Creating your v17.1.1 workspace.

   To make sure the command works reliably in all environments, and that the preset is applied correctly,
   Nx will run "npm install" several times. Please wait.

✔ Installing dependencies with npm
✔ Successfully created the workspace: nx-package-based.
✔ NxCloud has been set up successfully

 —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

 >  NX   Nx CLI is not installed globally.

   This means that you might have to use "yarn nx" or "npx nx" to execute commands in the workspace.
   Run "yarn global add nx" or "npm install -g nx" to be able to execute command directly.

 >  NX   Distributed caching via Nx Cloud has been enabled

   In addition to the caching, Nx Cloud provides config-free distributed execution,
   UI for viewing complex runs and GitHub integration. Learn more at https://nx.app

   Your workspace is currently unclaimed. Run details from unclaimed workspaces can be viewed on cloud.nx.app by anyone
   with the link. Claim your workspace at the following link to restrict access.

   https://cloud.nx.app/orgs/workspace-setup?accessToken=ZjA1YWRhNjQtOWU3Ny00NzIyLThmODQtYjNkNWE1YTU0ZmRifHJlYWQtd3JpdGU=

 —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

 >  NX   First time using Nx? Check out this interactive Nx tutorial.

   https://nx.dev/getting-started/tutorials/package-based-repo-tutorial

프로젝트를 살펴보면 처음에는 이런 형태로 되어있습니다.

package.json을 보면 workspaces 설정이 되어있습니다.

{
  "name": "package-based",
  "version": "0.0.0",
  "license": "MIT",
  "scripts": {},
  "private": true,
  "dependencies": {},
  "devDependencies": {
    "@nx/js": "17.1.1",
    "nx": "17.1.1"
  },
  "workspaces": [
    "packages/*"
  ]
}

패키지 폴더는 모노레포 라이브러리를 호스팅하는 곳입니다. 여기서는 가볍게 새 is-even 폴더를 만듭니다. 그 아래에는 index.ts와 package.json을 작성해줍니다.

export const isEven = (x: number) => x % 2 === 0;
{
  "name": "is-even",
  "version": "0.0.0",
  "main": "dist/index.js",
  "devDependencies": {},
  "scripts": {
    "build": "tsc index.ts --outDir dist"
  }
}

다음으로 TypeScript를 설치합니다. 패키지 수준에서 TypeScript를 설치할 수도 있지만 전체 모노레포에 대해 전역적으로 설치하는 것이 더 편리합니다. 아래 명령을 실행해줍니다.

npm i typescript -D -W

-W 플래그는 workspaces 라는 의미입니다. 원래대로라면 작업공간 루트에서 TypeScript를 설치해야 했겠지만 -W를 사용하면 경로 상관없이 실행해도 전역적으로 설치하게 됩니다. - 참고

이제 build를 해봅시다. is-even를 선택하면 해당 프로젝트 내에 package.json에 작성한 build가 수행됩니다.

❯ npx nx build is-even

> nx run is-even:build

> is-even@0.0.0 build
> tsc index.ts --outDir dist

 —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

 >  NX   Successfully ran target build for project is-even (3s)
 
   View logs and investigate cache misses at https://nx.app/runs/D9dcMh7AAO

빌드된 패키지가 예상대로 packages/is-even/dist 디렉터리에 있는 것을 볼 수 있습니다.

package-based 모노레포 스타일로 패키지를 로컬로 연결하는 것은 NPM/Yarn/PNPM workspaces을 통해 수행됩니다. 패키지를 로컬로 연결하는 방법을 설명하기 위해 is-odd라는 또 다른 패키지를 만들어 보겠습니다. 기존 is-even 패키지를 복사할 수 있습니다.

package-based/
├── packages/
│   ├── is-even/
│   │   ├── index.ts
│   │   └── package.json
│   └── is-odd/
│       ├── index.ts
│       └── package.json
├── nx.json
└── package.json

여기서 isOdd 함수는 isEven 함수를 불러와서 사용해보도록 하겠습니다.

import { isEven } from 'is-even';

export const isOdd = (x: number) => !isEven(x);

그러기 위해서는 package.json 파일은 is-even 패키지를 종속성으로 설정해야 합니다.

루트 수준 package.json의 workspaces 속성이 npm에게 packages 디렉터리에 있는 모든 패키지에 대한 링크를 생성하도록 지시합니다. 이렇게 하면 먼저 npm 레지스트리에 게시할 필요가 없습니다. 따라서 아래와 같이 설정해줘도 잘 작동합니다.

{
  "name": "is-odd",
  "version": "0.0.0",
  "main": "dist/index.js",
  "devDependencies": {},
  "scripts": {
    "build": "tsc index.ts --outDir dist"
  },
  "dependencies": {
    "is-even": "*"
  }
}

작업공간 루트에서 다음을 실행합니다.

> npm install

npm은 파일 시스템 node_modules/is-even 및 node_modules/is-odd에 심볼릭 링크를 생성하므로 packages/is-even 및 packages/is-odd 디렉터리에 대한 변경 사항이 발생하면 이를 반영합니다.

심볼릭 링크는 아래와 같이 화살표 표시가 되어있는게 특징입니다. 즉, node_modules안에 진짜로 존재하는게 아니라 실제로는 packages 안에 내용이 있고 이를 연결만 해준다는 느낌입니다.

그리고 여기서 유용한게 VSCode에 Nx console을 설치해서 Nx graph를 확인해볼 수 있습니다. (굳이 설치 안해도 nx 명령을 사용해도 되긴 합니다)

여기서 의존성 그래프를 확인하는 기능을 사용해보면 다음과 같이 나옵니다. 의존성이 바로 확인이 되죠?

자, 그러면 여기서 중요한 점. is-odd를 빌드하게 되면 is-even도 변경사항이 있는지 확인 후 빌드 되어야 할 것입니다. 의존성이라는 건 그런겁니다...

Nx는 nx.json에 targetDefaults 속성을 추가하여 이러한 작업 종속성을 정의할 수 있습니다.

{
  ...
  "targetDefaults": {
    "build": {
      "cache": true,
      "dependsOn": ["^build"]
    }
  }
}

이는 Nx에게 패키지 자체의 빌드 타켓이 실행되기 전에 먼저 모든 종속 프로젝트의 빌드 타겟이 실행하도록 지시합니다. 기존 dist 폴더를 제거하고 다음을 실행합니다.

❯ npx nx build is-odd

   ✔    1/1 dependent project tasks succeeded [1 read from cache]

   Hint: you can run the command with --verbose to see the full dependent project outputs

 ————————————————————————————————————————————————————————————————————————————————————————————————————————————

> nx run is-odd:build

> is-odd@0.0.0 build
> tsc index.ts --outDir dist

 ————————————————————————————————————————————————————————————————————————————————————————————————————————————

 >  NX   Successfully ran target build for project is-odd and 1 task it depends on (3s)
 
   Nx read the output from the cache instead of running the command for 1 out of 2 tasks.
 
   View logs and investigate cache misses at https://nx.app/runs/ZJZVtnSD15

먼저 is-even 패키지에 대한 빌드를 자동으로 실행한 다음 is-odd에 대한 빌드를 자동으로 실행한다는 것을 알 수 있습니다. 단, is-even이 이전에 빌드된 경우 캐시에서 복원됩니다. 지금은 is-even이 캐시가 된 상태이고 is-odd만 빌드가 실행된 것을 알 수 있습니다.

한번 더 실행해보니 이제는 둘 다 캐시가 되어있다고 나오네요. 빌드 시간 또한 3s에서 51ms로 감소했습니다.

> nx run is-odd:build  [existing outputs match the cache, left as is]

> is-odd@0.0.0 build
> tsc index.ts --outDir dist

 ————————————————————————————————————————————————————————————————————————————————————————————————————————————

 >  NX   Successfully ran target build for project is-odd and 1 task it depends on (51ms)

만약 is-even을 바꾸면 어떨까요? 의존성이 있는 태스크에 대해서는 캐시가 안되어있다고 나오네요. 작업 시간 또한 시간 다시 3s가 되었습니다.

❯ npx nx build is-odd

   ✔    1/1 dependent project tasks succeeded [0 read from cache]

>  NX   Successfully ran target build for project is-odd and 1 task it depends on (3s)

✍️ 정확히 어떤 메커니즘에 의해 캐시가 되어있는지 판단하는지는 살펴봐야 알겠지만 변경되지 않은 부분에 대해서는 빌드를 다시 실행하지 않고 캐시된 결과를 가져다 쓰면서 작업 시간을 단축한다는 점은 매우 좋은 기능 같습니다. 실제로 Nx 뿐만 아니라 Turbo를 비롯한 많은 모노레포 지원 도구들이 기본으로 지원하는 기능입니다.

작업공간의 모든 패키지에 대한 빌드 대상을 실행하려면 다음 명령을 사용하세요.

❯ npx nx run-many -t build
 
    ✔  nx run is-even:build  [local cache]
    ✔  nx run is-odd:build  [local cache]

 ————————————————————————————————————————————————————————————————————————————————————————————————————————————

 >  NX   Successfully ran target build for 2 projects (55ms)
 
   Nx read the output from the cache instead of running the command for 2 out of 2 tasks.
 
   View logs and run details at https://nx.app/runs/Dmg0w1szVe

두 빌드 모두 캐시에서 재생됩니다. --skip-nx-cache 옵션을 추가하여 캐시를 건너뛸 수 있습니다.

❯ npx nx run-many -t build --skip-nx-cache

		✔  nx run is-even:build (1s)
    ✔  nx run is-odd:build (1s)

 ————————————————————————————————————————————————————————————————————————————————————————————————————————————

 >  NX   Successfully ran target build for 2 projects (3s)

다음 명령을 사용하여 변경된 패키지에서만 작업을 실행할 수도 있습니다.

❯ npx nx affected -t build

 >  NX   Affected criteria defaulted to --base=main --head=HEAD

 
    ✔  nx run is-even:build  [existing outputs match the cache, left as is]
    ✔  nx run is-odd:build  [existing outputs match the cache, left as is]

 ————————————————————————————————————————————————————————————————————————————————————————————————————————————

 >  NX   Successfully ran target build for 2 projects (43ms)

2. Getting Started with Integrated Repos

참고 : https://nx.dev/getting-started/tutorials/integrated-repo-tutorial
참고 2 : https://youtu.be/-_4WMl-Fn0w?si=jiqDHqC8dixyqrGQ&t=302

Nx는 크게 3가지 정도의 작업 공간 생성 방법이 있는 거 같은데 이번에 소개한 거는 통합 레포 입니다. 이번에도 마찬가지로 새 작업 공간을 만들어보겠습니다. 여기서는 대신에 preset=ts 를 사용했습니다.

npx create-nx-workspace@latest integrated --preset=ts

Nx에는 스캐폴딩 애플리케이션에 도움이 될 수 있는 generators가 함께 제공됩니다. 이 생성기를 실행하여 is-even이라는 새 라이브러리를 만들 수 있습니다. 이는 "@nx/js"가 이미 설치가 되어있기에 가능합니다.

❯ npx nx generate @nx/js:library is-even \
--directory=packages/is-even \
--publishable \
--importPath=@myorg/is-even

>  NX  Generating @nx/js:library

✔ Which unit test runner would you like to use? · none
✔ Which bundler would you like to use to build the library? Choose 'none' to skip build setup. · tsc
✔ What should be the project name and where should it be generated? · is-even @ packages/is-even
CREATE packages/is-even/tsconfig.json
CREATE packages/is-even/README.md
CREATE packages/is-even/src/index.ts
CREATE packages/is-even/src/lib/is-even.ts
CREATE packages/is-even/tsconfig.lib.json
CREATE packages/is-even/package.json
CREATE packages/is-even/project.json
CREATE packages/is-even/.eslintrc.json
UPDATE tsconfig.base.json
  • @nx/js 플러그인의 라이브러리 생성기를 사용하여 is-even이라는 새 라이브러리를 스캐폴드합니다.
  • -publishable 플래그를 사용하면 package.json이 생성되고 npm에 게시하기 위해 호출할 수 있는 publish 대상도 얻을 수 있습니다.
  • -importPath를 사용하면 npm 패키지의 이름을 정의할 수 있습니다.

실행을 마치면 아래와 같이 만들어집니다.

packages/
└── is-even/
    ├── src/
    |  └── lib/
    |  |  ├── is-even.ts
    |  └── index.ts
    ├── project.json
    ├── package.json
    ├── ...
    └── tsconfig.json

Nx 플러그인은 프로젝트 수준 project.json을 사용하여 특정 프로젝트에 대해 실행할 수 있는 사용 가능한 대상 주변의 메타데이터를 관리합니다. is-even에 대해 생성된 project.json에는 build, publish, lint 및 test targets이 포함되어 있습니다.

다양한 설정을 살펴보고 패키지 빌드, 게시, 린팅 또는 테스트에 사용되는 옵션을 세부적으로 조정할 수 있습니다. 낮은 수준의 세부 사항은 플러그인에서 처리됩니다.

// packages/is-even/project.json

{
  "name": "is-even",
  "$schema": "../../node_modules/nx/schemas/project-schema.json",
  "sourceRoot": "packages/is-even/src",
  "projectType": "library",
  "targets": {
    "build": {
      "executor": "@nx/js:tsc",
      "outputs": ["{options.outputPath}"],
      "options": {
        "outputPath": "dist/packages/is-even",
        "main": "packages/is-even/src/index.ts",
        "tsConfig": "packages/is-even/tsconfig.lib.json",
        "assets": ["packages/is-even/*.md"]
      }
    },
    "publish": {
      "command": "node tools/scripts/publish.mjs is-even {args.ver} {args.tag}",
      "dependsOn": ["build"]
    },
    "lint": {
      "executor": "@nx/eslint:lint",
      "outputs": ["{options.outputFile}"],
      "options": {
        "lintFilePatterns": [
          "packages/is-even/**/*.ts",
          "packages/is-even/package.json"
        ]
      }
    }
  },
  "tags": []
}
  • npx nx build is-even은 src 파일을 빌드하고 즉시 게시 가능한 패키지를 작업공간 루트의 dist/packages/is-even에 배치합니다.
  • npx nx publish is-even은 dist/packages/is-even에서 publish 스크립트를 실행하여 패키지를 NPM에 푸시합니다.
  • npx nx test is-even는 패키지에 대해 사전 구성된 Jest 테스트를 실행합니다.
  • npx nx lint is-even은 패키지에 대해 사전 구성된 ESLint 검사를 실행합니다.

통합 모노레포 스타일의 패키지 로컬 연결은 tsconfig.base.json 파일의 TypeScript 경로 매핑을 활용하여 Nx에서 자동으로 처리됩니다. 이를 설명하기 위해 is-odd라는 또 다른 패키지를 만들어 보겠습니다. 이를 위해 생성기를 다시 실행할 수 있습니다.

❯ npx nx generate @nx/js:library is-odd \
--directory=packages/is-odd \
--publishable \
--importPath=@myorg/is-odd

이렇게 작성해줘도 알아서 경로를 잘 찾아주는거 같네요.

import { isEven } from '@myorg/is-even';

export function isOdd(x: number): boolean {
  return !isEven(x);
}

이제 tsconfig.base.json에 두 개의 항목이 어떻게 있는지 확인하세요.

{
  "compileOnSave": false,
  "compilerOptions": {
    ...
    "paths": {
      "@myorg/is-even": ["packages/is-even/src/index.ts"],
      "@myorg/is-odd": ["packages/is-odd/src/index.ts"]
    }
  }
}

나머지 Nx는 nx.json에 targetDefaults 속성을 추가하여 이러한 작업 종속성을 정의하는 부분은 동일합니다.

여기서 재미있는 점은 이번에는 플러그인, 생성기 등을 적극 활용했다는 것입니다. 실제로 많은 개발자는 주로 모노레포 지원이 아니라 도구 지원, 특히 코드베이스를 모듈화하여 더 나은 확장성을 제공하는 기능을 위해 Nx를 사용한다고 합니다. 예를 들어, @nx/react를 활용하면 리액트 프로젝트에 스토리북, 테스팅 라이브러리 등을 쉽게 통합할 수 있고, 라이브러리, 훅, 컴포넌트 등을 생성기를 통해 쉽게 생성할 수 있습니다.

3. Building React Apps with the Nx Standalone Setup

참고 : https://nx.dev/getting-started/tutorials/react-standalone-tutorial


Mental Model

참고 : https://nx.dev/concepts/mental-model

Nx는 모노레포를 효율적이고 효과적으로 구동하기 위해 몇 가지 개념을 사용합니다. 이 가이드에서는 Nx가 프로젝트 그래프, 작업 그래프, 영향을 받는 명령, 계산 해싱 및 캐싱과 함께 작동하는 방식에 대한 정신 모델을 다룹니다.

1. The project graph

프로젝트 그래프는 저장소의 소스 코드와 Webpack, React, Angular 등과 같이 저장소에서 작성되지 않은 모든 외부 종속성을 반영하는 데 사용됩니다. Nx를 사용하면 프로젝트 그래프의 노드가 project.json 파일에 정의됩니다. Nx는 파일의 소스 코드, 설치된 종속성, TypeScript 파일 및 이러한 종속성을 파악하는 기타 항목을 분석합니다.

Nx는 캐시된 프로젝트 그래프도 저장하므로 변경된 파일만 다시 분석합니다.

Nx는 각 분석이 완료된 후 업데이트된 그래프를 제공합니다.

2. Metadata-driven

Nx의 모든 것에는 도구성을 활성화하기 위한 메타데이터가 포함되어 있습니다. 기본값, 유효성 검사, 자동 완성 작업 등은 모두 코드가 아닌 스키마에 정의됩니다. 이 메타데이터는 Nx 자체, VSCode 및 WebStorm 통합, GitHub 통합 및 타사 도구에서 사용됩니다.

이러한 도구는 이 메타데이터를 사용하여 Nx로 더욱 풍부한 경험을 구현할 수 있습니다.

3. The task graph

Nx는 프로젝트 그래프를 사용하여 작업 그래프를 생성합니다. 무엇이든 실행할 때마다 Nx는 프로젝트 그래프에서 작업 그래프를 생성한 다음 해당 그래프의 작업을 실행합니다.

Nx는 프로젝트 그래프를 사용하지만 작업 그래프와 프로젝트 그래프는 같지 않습니다. 즉, 직접 연결되어 있지 않습니다. dependsOn을 설정하지 않으면 app1과 app2가 lib에 의존하지만 nx run-many -t test -p app1 app2 lib를 실행하면 병렬로 실행됩니다.

dependsOn을 설정하면 다음 작업 그래프가 생성됩니다. 이는 종종 app1를 어디서 빌드하던 lib를 먼저 빌드하려는 빌드에 더 적합합니다.

작업 그래프에는 다양한 대상이 포함될 수 있으며 이러한 대상은 병렬로 실행될 수 있습니다. 예를 들어 Nx가 app2를 빌드하는 동시에 app1을 테스트할 수 있습니다. 확실히 이렇게 진행하는 편이 효율적이겠네요. app1과 app2는 별개니까요.

Nx는 또한 작업 그래프의 작업을 올바른 순서로 실행합니다. Nx 작업을 병렬로 실행하면 전체 실행 시간이 단축됩니다.

4. Affected commands

  • nx test app1 : Nx에게 app1:test 작업과 이에 의존하는 모든 작업을 실행하도록 지시하는 것이다.
  • nx run-many -t test -p app1 lib : Nx에게 app1:test 및 lib:test 두 작업에 대해 동일한 작업을 수행하도록 지시하는 것입니다.
  • nx run-many -t test : Nx에게 모든 프로젝트에 대해 이 작업을 수행하도록 지시하는 것입니다.

작업 공간이 커지면 모든 프로젝트를 다시 테스트하는 것이 너무 느려집니다. 이 문제를 해결하기 위해 Nx는 코드 변경 분석을 구현하여 다시 테스트해야 하는 최소 프로젝트 세트를 가져옵니다.

nx 영향을 받는 -t 테스트를 실행하면 Nx는 PR에서 변경한 파일을 살펴보고 변경의 성격(해당 파일에서 정확히 무엇을 업데이트했는지)을 확인한 다음 이를 사용하여 PR에서 프로젝트 목록을 파악합니다. 이 변경으로 영향을 받을 수 있는 작업공간입니다. 그런 다음 해당 목록을 사용하여 run-many 명령을 실행합니다.

예를 들어, 내 PR이 lib를 변경하고 nx에 영향을 받는 -t test를 실행하면 Nx는 app1과 app2가 lib에 의존한다는 것을 파악하여 nx run-many -t test -p app1 app2 lib를 호출합니다. (오호...)

5. Computation hashing and caching

Nx는 작업 그래프의 작업을 올바른 순서로 실행합니다. 작업을 실행하기 전에 Nx는 computation 해시를 계산합니다. computation 해시가 동일한 한 작업 실행 결과는 동일합니다. (오… 해시를 이용해서… 판단하는건가)

기본적으로 nx test app1의 계산 해시에는 다음이 포함됩니다.

  • app1 및 lib의 모든 소스 파일
  • 관련 전역 구성
  • 외부 종속성 버전
  • 사용자가 프로비저닝한 런타임 값
  • CLI 명령 플래그

Nx는 작업에 대한 해시를 계산한 후 이전에 이 정확한 계산을 실행했는지 확인합니다. 먼저 로컬에서 확인하고, 누락된 경우에는 원격으로 확인하고, 원격 캐시가 구성되어 있으면 원격으로 확인합니다.

  • Nx가 계산을 찾으면 Nx는 이를 검색하여 재생합니다. 따라서 사용자의 관점에서 볼 때 명령은 동일하게 실행되었으며 훨씬 더 빠르게 실행되었습니다.
  • Nx가 이 계산을 찾지 못하면 Nx는 작업을 실행하고 작업이 완료된 후 출력과 터미널 출력을 가져와 로컬에 저장합니다(원격으로 구성된 경우).

6. Distributed task execution

Nx는 여러 시스템에서 명령 실행을 지원합니다. 직접 설정하거나 Nx Cloud를 사용할 수 있습니다.

분산 작업 실행을 사용할 때 Nx는 로컬이 아닌 많은 에이전트에서 작업 그래프를 실행할 수 있습니다. 예를 들어 영향을 받은 nx --build는 빌드를 로컬로 실행하지 않습니다(대형 작업 공간의 경우 몇 시간이 걸릴 수 있음). 대신 작업 그래프를 Nx Cloud로 보냅니다. 그런 다음 Nx Cloud 에이전트는 실행할 수 있는 작업을 선택하고 실행합니다.

에이전트가 작업을 완료하면 영향을 받는 nx --build를 호출한 기본 작업이 생성된 파일과 터미널 출력을 수신하기 시작합니다. nx에 영향을 받은 --build가 완료되면 머신은 마치 로컬에서 실행한 것처럼 빌드 파일과 모든 터미널 출력을 갖게 됩니다.

확실히 이러면 빌드 시간은 효과적으로 단축이 가능하겠네요.


마치면서

모노레포 지원 도구인 줄만 알았던 Nx 였는데 실제로는 모노레포 사용을 위해서가 아닌 단일 프로젝트에서도 충분히 사용을 검토해볼 만한 도구임에는 분명한 거 같습니다.


참고 자료

profile
배움을 좋아합니다. 새로운 것을 좋아합니다.

0개의 댓글