nx를 활용한 nextjs MonoRepo 구성하기 [1]

nx로 반복되는 코드를 제거하기

Posted by yoogomja on May 4, 2023

최근 진행했던 프로젝트에서 비슷한 UI를 가지나, 각각 독립적으로 배포되어야 웹 사이트를 제작하게 되었다. 기획을 듣고나서 설계하는 과정에서 느낀 개발 요구사항은 다음과 같았다.

  1. 디자인 요구 사항이 반영된 UI 컴포넌트, 스타일들을 공유 해야한다.
  2. 몇 가지 비즈니스 로직들을 공유해야 한다.
  3. 타입을 공유해야한다.

위 요구 사항을 충족하기 위해서 npm private package 혹은 npm workspace등을 먼저 떠올렸었다. npm private package는 이전에 활용해본 적이 있었다. 각 배포마다 패키지를 직접 업데이트를 해주어야 했는데, 그렇다보니 각 배포 사이에 버전이 다르게 되는 경우가 없지 않았다. 버전 관리에 굉장히 까다로움을 느꼈다. npm workspace는 이전에 활용했을 때, 참조 관련 에러를 만났던 적이 있어서 새로 공부가 필요했었다. 하지만, 이번 경우에는 새로운 기능을 사용해보고 싶어서 공부 삼아 monorepo로 진행하기로 했다.

그 중에서도 turborepo, nx 등을 찾게 되었으나 가장 먼저 알게된 nx를 사용하기로 했다. nx의 기능들이 nestjs-cli처럼 굉장히 강력하게 느껴졌기 때문인 것 같다.

Installation

monorepo가 관장하는 큰 영역을 workspace라고 부르는데, 이를 생성하기 위해서는 아래의 명령어를 사용한다.

1
yarn create nx-workspace

위 코드를 수행하면 어떤 형식을 선택할 것 인지 묻는데, 다음과 같이 출력된다.

1
2
3
4
5
Package-based monorepo: Nx makes it fast but lets you run things your way.
Integrated monorepo:    Nx configures your favorite frameworks and lets you focus on shipping features.
Standalone React app:   Nx configures Vite (or Webpack), ESLint, and Cypress.
Standalone Angular app: Nx configures Jest, ESLint, and Cypress.
Standalone Node app:    Nx configures a framework (ex. Express), esbuild, ESlint and Jest.

여기서 Package-based, Integrated, Standalone의 선택지가 보이는데, 각각 아래와 같은 차이점이있다.

Integrated Repos vs. Package-Based Repos vs. Standalone Apps

Package-basedworkspace하위의 app마다 각각 독립적인 package.json을 가진다. 그리고 중첩된 각각의 node_modules 폴더를 가지게 된다. 이를 통해 각각 프로젝트마다 다른 의존성을 가지게 된다.

Interaged는 오직 하나의 의존성만 가지게 된다. 모두가 node_modules를 공유하며 모든 프로젝트에서 하나의 버전만을 가지게 된다. 나의 경우에는 이 항목으로 작업하였다.

Standalonemonorepo로서 사용하는 것이 아닌, React, Angular등을 위해 단독으로 사용하는 경우다. nx-cli나 빌드 전략, 캐싱등의 기능등이 굉장히 유용하기 때문에, monorepo가 아니더라도 사용하는 경우이다.

New App

새로운 프로젝트를 생성할때에는 원하는 항목에 알맞는 명령어를 공식 홈페이지에서 확인할 수 있다. 나의 경우에는 Next앱을 활용했다.

1
2
3
4
nx generate application myapp --directory

# same
nx g app myapp --directory

통상적으로 앱을 생성할때에는 위의 명령어를 사용한다. 축약어로도 사용가능하다. 그런데, 이 경우에는 어떤 어플리케이션을 생성할지 선택하게 되는데, 바로 next 프로젝트를 만들기 위해서는 다음과 같이 입력한다.

1
nx g @nx/next:application

이렇게 작성하면 e2e테스트 코드를 포함하여 /apps폴더에 생성된다.

이렇게 생성된 어플리케이션은 다음과 같이 실행할 수 있다.

1
nx run myapp:serve

:serve는 해당 프로젝트의 실행 명령어인데, package.json에 작성되어있다.

VS Code Extension

위의 명령을 사용하다보면, 매번 명령어를 입력하는데 어려움이 따른다. VS Code를 사용하는 경우 Nx Console을 사용하면 훨씬 수월하게 사용할 수 있다. 기본적으로 NX 명령어와 프로젝트를 볼 수 있는 탭을 추가로 제공하고, 각 명령어의 실행 시에 편리한 입력 form을 제공해준다.

New Library

실제 배포가 되는 Application이 아닌, UI등의 코드는 Library를 생성하여 사용한다. Library의 경우, JavaScript, TypeScript는 물론 React, NextJS, NestJS등도 제공한다.

나의 경우에는 UI, Type, 훅 등의 비즈니스 로직등을 나누어 두었는데, UI는 React가 아닌 Next Library를 사용했다. next/image등을 활용해야 하는 탓이었다.

명령어는 다음과 같다.

1
nx generate @nrwl/next:library

기본적으로 이렇게 생성한 Library는 다음과 같이 참조하여 사용할 수 있다.

1
2
3
import { something } from "@my-workspace/your-lib-name";

something();