이 튜토리얼에서는 "standalone"(모노레포가 아닌) 설정에서 Nx와 함께 React를 사용하는 방법을 배웁니다.
무엇을 배우게 될까요?
React 모노레포를 찾고 계신가요?
이 튜토리얼에서는 루트 레벨에 단일 애플리케이션이 있는 레포지토리를 설정하고 해당 코드를 라이브러리로 분리하여 구조를 추가합니다. React 모노레포 설정을 찾고 계신다면 [React 모노레포 튜토리얼](https://nx.dev/react-tutorial/1-code-generation)을 확인해보세요.
다음은 이 튜토리얼의 최종 결과물의 소스 코드입니다.
Example repository
Open in Stackblitz
다음 명령을 사용하여 새 standalone React 애플리케이션을 생성합니다:
npx create-nx-workspace@latest myreactapp --preset=react-standalone
? Bundler to be used to build the application …
Vite [ https://vitejs.dev/ ]
Webpack [ https://webpack.js.org/ ]
Rspack [ https://www.rspack.dev/ ]
원하는 번들러를 선택할 수 있습니다. 이 튜토리얼에서는 Vite를 사용하겠습니다. 위의 명령은 다음과 같은 구조를 생성합니다:
└─ myreactapp
├─ ...
├─ e2e
│ └─ ...
├─ public
│ └─ ...
├─ src
│ ├─ app
│ │ ├─ app.module.css
│ │ ├─ app.spec.tsx
│ │ ├─ app.tsx
│ │ └─ nx-welcome.tsx
│ ├─ assets
│ ├─ main.tsx
│ └─ styles.css
├─ index.html
├─ nx.json
├─ package.json
├─ project.json
├─ tsconfig.app.json
├─ tsconfig.json
├─ tsconfig.spec.json
└─ vite.config.ts
설정에는 다음이 포함됩니다.
여러분에게 생소할 수 있는 몇 가지를 설명하겠습니다.
nx.json
여기서 Nx의 작동 방식을 미세 조정합니다. 캐시 가능한 연산들을 정의하고 작업 파이프라인을 구성합니다. 이에 대해서는 곧 자세히 설명하겠습니다.
가장 일반적인 작업은 이미 package.json 파일에 매핑되어 있습니다:
// package.json
{
"name": "reactutorial",
"scripts": {
"start": "nx serve",
"build": "nx build",
"test": "nx test"
}
...
}
새 React 애플리케이션을 서비스하려면 다음과 같이 실행하세요. 또는 다음을 사용하여 Nx를 직접 사용할 수도 있습니다.
nx serve
애플리케이션은 http://localhost:4200 에서 제공되어야 합니다.
Nx는 다음 구문을 사용하여 작업을 실행합니다:
서빙, 빌드, 테스트 또는 커스텀 타겟 같은 모든 타겟은 project.json 파일에 정의됩니다.
// project.json
{
"name": "myreactapp",
...
"targets": {
"serve": { ... },
"build": { ... },
"preview": { ... },
"test": { ... },
"lint": { ... },
"serve-static": { ... },
},
}
package.json을 사용할 수도 있습니다.
Nx는 **package.json**과 **project.json** 모두에서 작업을 가져올 수 있습니다. [자세히 보기](https://nx.dev/core-features/run-tasks)
각 타겟에는 해당 타겟을 실행하는 방법을 알려주는 구성 객체가 포함되어 있습니다.
{
"name": "myreactapp",
...
"targets": {
"serve": {
"executor": "@nx/vite:dev-server",
"defaultConfiguration": "development",
"options": {
"buildTarget": "reactutorial:build"
},
"configurations": {
"development": {
"buildTarget": "reactutorial:build:development",
"hmr": true
},
"production": {
"buildTarget": "reactutorial:build:production",
"hmr": false
}
}
},
...
},
}
가장 중요한 부분은 다음과 같습니다:
<plugin>:<excutor-name>
구문으로, 여기서 plugin은 Nx Plugin을 포함하는 NPM 패키지이고 <executor-name>
은 작업을 실행하는 함수를 가리킵니다. 이 경우, @nx/vite 플러그인에는 Vite를 사용하여 React 앱을 서빙하는 dev-server 실행기가 포함되어 있습니다.Nx로 작업을 실행하는 방법에 대해 자세히 알아보세요.
현재 설정에는 React 애플리케이션을 제공하고 빌드하기 위한 타겟뿐만 아니라 단위 테스트, e2e 테스트 및 린팅을 위한 타겟도 있습니다. 다시 말하지만, 이것들은 project.json 파일에 정의되어 있습니다. 이전과 동일한 구문을 사용하여 이러한 작업을 실행할 수 있습니다:
nx test # runs tests using Vitest (or you can configure it to use Jest)
nx lint # runs linting with ESLint
nx e2e e2e # runs e2e tests with Cypress
더 편리하게는 다음 구문을 사용하여 병렬로 실행할 수도 있습니다:
nx run-many -t test lint e2e
✔ nx run e2e:lint (2s)
✔ nx run myreactapp:lint (2s)
✔ nx run myreactapp:test (2s)
✔ nx run e2e:e2e (6s)
——————————————————————————————————————————————————————
> NX Successfully ran targets test, lint, e2e for 2 projects (7s)
한 가지 주목해야 할 점은 Nx가 실행하는 작업을 캐시할 수 있다는 점입니다.
이러한 모든 타겟은 Nx에 의해 자동으로 캐시됩니다. 하나 또는 모든 대상을 다시 실행하면 작업이 즉시 완료되는 것을 볼 수 있습니다. 또한 아래 출력 예제에서 볼 수 있듯이 일치하는 캐시 결과를 찾았으므로 작업을 다시 실행하지 않았다는 메모가 표시됩니다.
nx run-many -t test lint e2e
✔ nx run e2e:lint [existing outputs match the cache, left as is]
✔ nx run myreactapp:lint [existing outputs match the cache, left as is]
✔ nx run myreactapp:test [existing outputs match the cache, left as is]
✔ nx run e2e:e2e [existing outputs match the cache, left as is]
——————————————————————————————————————————————————————
> NX Successfully ran targets test, lint, e2e for 5 projects (54ms)
Nx read the output from the cache instead of running the command for 10 out of 10 tasks.
하지만 모든 작업을 캐시할 수 있는 것은 아닙니다. nx.json 파일에서 cacheableOperations를 구성할 수 있습니다. 캐싱 작동 방식에 대해 자세히 알아볼 수도 있습니다.
평소처럼 새 React 컴포넌트를 만들면 됩니다. 하지만 Nx 플러그인은 보통 제너레이터도 함께 제공합니다. 이를 통해 코드, 구성 또는 전체 프로젝트를 쉽게 scaffold할 수 있습니다. 다음 명령을 실행하고 출력을 검사하여 @nx/react 플러그인이 어떤 기능을 제공하는지 확인해보세요:
npx nx list @nx/react
> NX Capabilities in @nx/react:
GENERATORS
init : Initialize the `@nrwl/react` plugin.
application : Create a React application.
library : Create a React library.
component : Create a React component.
redux : Create a Redux slice for a project.
storybook-configuration : Set up storybook for a React app or library.
component-story : Generate storybook story for a React component
stories : Create stories/specs for all components declared in an app or library.
component-cypress-spec : Create a Cypress spec for a UI component that has a story.
hook : Create a hook.
host : Generate a host react application
remote : Generate a remote react application
cypress-component-configuration : Setup Cypress component testing for a React project
component-test : Generate a Cypress component test for a React component
setup-tailwind : Set up Tailwind configuration for a project.
setup-ssr : Set up SSR configuration for a project.
EXECUTORS/BUILDERS
module-federation-dev-server : Serve a host or remote application.
module-federation-ssr-dev-server : Serve a host application along with it's known remotes.
보다 시각적인 UI를 선호하시나요?
보다 통합된 환경을 원한다면 코드 편집기용 "Nx Console" 확장 프로그램을 설치하면 됩니다. 이 확장 프로그램은 VSCode, IntelliJ를 지원하며 Vim용 LSP를 제공합니다. Nx Console은 Nx 구성 파일에서 자동 완성 기능을 지원하며 제네레이터 탐색 및 실행을 위한 UI를 제공합니다.
자세한 내용은 [에디터와 통합하기 문서](https://nx.dev/core-features/integrate-with-editors)에서 확인할 수 있습니다.
다음 명령을 실행하여 새 "hello-world" 컴포넌트를 생성합니다. 먼저 출력을 확인하기 위해 --dry-run을 추가하는 방법에 유의하세요.
npx nx g @nx/react:component hello-world --dry-run
> NX Generating @nx/react:component
✔ Should this component be exported in the project? (y/N) · false
CREATE src/app/hello-world/hello-world.module.css
CREATE src/app/hello-world/hello-world.spec.tsx
CREATE src/app/hello-world/hello-world.tsx
NOTE: The "dryRun" flag means no changes were made.
보시다시피 App/hello-world/ 폴더에 새 컴포넌트를 생성합니다. 제네레이터를 실제로 실행하려면 --dry-run 플래그를 제거하세요.
// src/app/hello-world/hello-world.tsx
import styles from './hello-world.module.css';
/* eslint-disable-next-line */
export interface HelloWorldProps {}
export function HelloWorld(props: HelloWorldProps) {
return (
<div className={styles['container']}>
<h1>Welcome to HelloWorld!</h1>
</div>
);
}
export default HelloWorld;
준비가 완료되어 애플리케이션을 출시하려는 경우 다음을 사용하여 빌드할 수 있습니다.
npx nx build
vite v4.3.5 building for production...
✓ 33 modules transformed.
dist/myreactapp/index.html 0.48 kB │ gzip: 0.30 kB
dist/myreactapp/assets/index-e3b0c442.css 0.00 kB │ gzip: 0.02 kB
dist/myreactapp/assets/index-378e8124.js 165.64 kB │ gzip: 51.63 kB
✓ built in 496ms
——————————————————————————————————————————————————————————————————————————————————————————————————————————
> NX Successfully ran target build for project reactutorial (1s)
필요한 모든 파일은 dist/myreactapp 폴더에 저장되며 원하는 호스팅 제공업체에 배포할 수 있습니다.
이전 섹션에서는 Nx 사용, 작업 실행 및 Nx 워크스페이스 탐색의 기본 사항에 대해 배웠습니다. 이제 기능을 제공할 준비가 되었습니다!
하지만 아직 배울 것이 더 있습니다. 여기에는 두 가지 가능성이 있습니다:
React 애플리케이션을 개발할 때 일반적으로 모든 로직은 app폴더에 위치합니다. "도메인"을 나타내는 다양한 폴더 이름으로 구분하는 것이 이상적입니다. 하지만 앱이 성장함에 따라 이는 점점 더 단일화됩니다.
└─ myreactapp
├─ ...
├─ src
│ ├─ app
│ │ ├─ products
│ │ ├─ cart
│ │ ├─ ui
│ │ ├─ ...
│ │ └─ app.tsx
│ ├─ ...
│ └─ main.tsx
├─ ...
├─ package.json
├─ ...
Nx를 사용하면 이 로직을 "로컬 라이브러리"로 분리할 수 있습니다. 주요 이점은 다음과 같습니다.
도메인 영역에 products, orders 및 보다 일반적인 디자인 시스템 컴포넌트인 ui가 포함된다고 가정해 봅시다. React 라이브러리 제네레이터를 사용하여 이러한 각 영역에 대한 새 라이브러리를 생성할 수 있습니다:
nx g @nx/react:library products --unitTestRunner=vitest --bundler=none --directory=modules
nx g @nx/react:library orders --unitTestRunner=vitest --bundler=none --directory=modules
nx g @nx/react:library ui --unitTestRunner=vitest --bundler=none --directory=modules/shared
--directory 플래그를 사용하여 라이브러리를 하위 폴더에 배치하는 방법에 주목하세요. 원하는 폴더 구조를 선택할 수 있으며, 모든 폴더를 루트 레벨로 유지할 수도 있습니다.
위의 명령을 실행하면 다음과 같은 디렉토리 구조가 생성됩니다:
└─ myreactapp
├─ ...
├─ modules
│ ├─ products
│ │ ├─ ...
│ │ ├─ project.json
│ │ ├─ src
│ │ │ ├─ index.ts
│ │ │ └─ lib
│ │ │ ├─ modules-products.spec.ts
│ │ │ └─ modules-products.ts
│ │ ├─ tsconfig.json
│ │ ├─ tsconfig.lib.json
│ │ ├─ tsconfig.spec.json
│ │ └─ vite.config.ts
│ ├─ orders
│ │ ├─ ...
│ │ ├─ project.json
│ │ ├─ src
│ │ │ ├─ index.ts
│ │ │ └─ ...
│ │ └─ ...
│ └─ shared
│ └─ ui
│ ├─ ...
│ ├─ project.json
│ ├─ src
│ │ ├─ index.ts
│ │ └─ ...
│ └─ ...
├─ src
│ ├─ app
│ │ ├─ hello-world
│ │ │ ├─ hello-world.module.css
│ │ │ ├─ hello-world.spec.tsx
│ │ │ └─ hello-world.tsx
│ │ └─ ...
│ ├─ ...
│ └─ main.tsx
├─ ...
각 라이브러리들은
우리가 자동으로 생성하는 모든 라이브러리에는 루트 수준의 tsconfig.base.json에 생성된 별칭이 있습니다.
Reference