|
1 | | -# 300 - Building Our Application |
| 1 | +# 300 - Creating a New React Monorepo |
2 | 2 |
|
3 | | -Based on [Building React Apps in an Nx Monorepo](https://nx.dev/getting-started/tutorials/react-monorepo-tutorial). |
| 3 | +Create a new React monorepo with the following command: |
4 | 4 |
|
5 | | -In this tutorial you'll learn how to use React with Nx in a monorepo setup. |
| 5 | +``` |
| 6 | +$ cd hatch-project/src # navigate to the 'hatch-project/src' sub-directory, previously created by hatch |
| 7 | +$ npx create-nx-workspace@latest hatch_project --preset=react-monorepo |
| 8 | +``` |
6 | 9 |
|
7 | | -What will you learn? |
| 10 | +When prompted, provide the following answers: |
8 | 11 |
|
9 | | -- how to create a new React application |
10 | | -- how to run a single task (i.e. serve your app) or run multiple tasks in parallel |
11 | | -- how to leverage code generators to scaffold components |
12 | | -- how to modularize your codebase and impose architectural constraints for better maintainability |
13 | | -- [how to speed up CI with Nx Cloud ⚡](https://nx.dev/getting-started/tutorials/react-monorepo-tutorial#fast-ci) |
| 12 | +``` |
| 13 | +NX Let's create a new workspace [https://nx.dev/getting-started/intro] |
14 | 14 |
|
15 | | -**Note**: this tutorial sets up a repo with applications and libraries in their own subfolders. If you are looking for a React standalone app setup then check out our [React standalone app tutorial](https://nx.dev/getting-started/tutorials/react-standalone-tutorial). |
16 | 15 |
|
17 | | -## 100 - Why Use an Nx Monorepo? |
| 16 | +``` |
18 | 17 |
|
19 | | -See [README.md](./100/README.md) |
| 18 | +This will generate the following file and directory structure underneath the ```/hatch-project/src``` directory: |
20 | 19 |
|
21 | | -## 200 - Video and Example of Final Code |
| 20 | +``` |
| 21 | +└─ hatch-project |
| 22 | + └─ src |
| 23 | + └─ hatch_project |
| 24 | + ├─ ... |
| 25 | + ├─ apps |
| 26 | + │ ├─ hatch_project |
| 27 | + │ │ ├─ public |
| 28 | + │ │ │ └─ ... |
| 29 | + │ │ ├─ src |
| 30 | + │ │ │ ├─ app |
| 31 | + │ │ │ │ ├─ app.module.css |
| 32 | + │ │ │ │ ├─ app.spec.tsx |
| 33 | + │ │ │ │ ├─ app.tsx |
| 34 | + │ │ │ │ └─ nx-welcome.tsx |
| 35 | + │ │ │ ├─ assets |
| 36 | + │ │ │ ├─ main.tsx |
| 37 | + │ │ │ └─ styles.css |
| 38 | + │ │ ├─ index.html |
| 39 | + │ │ ├─ project.json |
| 40 | + │ │ ├─ tsconfig.app.json |
| 41 | + │ │ ├─ tsconfig.json |
| 42 | + │ │ ├─ tsconfig.spec.json |
| 43 | + │ │ └─ vite.config.ts |
| 44 | + │ └─ hatch_project-e2e |
| 45 | + │ └─ ... |
| 46 | + ├─ nx.json |
| 47 | + ├─ tsconfig.base.json |
| 48 | + └─ package.json |
| 49 | +``` |
22 | 50 |
|
23 | | -See [README.md](./200/README.md) |
| 51 | +**Important**: Move all files previously in ```original_hatch_project``` to ```hatch_project``` and delete ```original_hatch_project```! |
24 | 52 |
|
25 | | -## 300 - Creating a New React Monorepo |
| 53 | +### Key Points: |
| 54 | +- **`hatch_project/nx.json`**: Configuration for the Nx workspace. |
| 55 | +- **`hatch_project/package.json`**: Dependencies and scripts specific to the project. |
| 56 | +- **`hatch_project/tsconfig.json`**: TypeScript configuration for the project. |
| 57 | +- **`hatch_project/workspace.json` or `project.json`**: Defines the structure and projects within the workspace. |
26 | 58 |
|
27 | | -See [README.md](./300/README.md) |
| 59 | +**IMPORTANT**: Move **nx.json** to ```hatch-project``` directory so it can connect with Nx Cloud. |
28 | 60 |
|
29 | | -MORE ... |
| 61 | +``` |
| 62 | +└─ hatch-project |
| 63 | + ├─ ... |
| 64 | + ├─ nx.json |
| 65 | + └─ src |
| 66 | + └─ hatch_project |
| 67 | + ├─ ... |
| 68 | +``` |
| 69 | + |
| 70 | +**IMPORTANT**: Modify **nx.json** so it can connect with Nx Cloud. |
| 71 | + |
| 72 | +To support the nested directory structure correctly in your ```/hatch-project/nx.json```, you should adjust the paths to reflect the correct locations within the nested workspace. Here’s a revised example: |
| 73 | + |
| 74 | +```json |
| 75 | +{ |
| 76 | + "$schema": "./node_modules/nx/schemas/nx-schema.json", |
| 77 | + "namedInputs": { |
| 78 | + "default": ["{projectRoot}/**/*", "sharedGlobals"], |
| 79 | + "production": [ |
| 80 | + "default", |
| 81 | + "!{projectRoot}/.eslintrc.json", |
| 82 | + "!{projectRoot}/eslint.config.mjs", |
| 83 | + "!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)", |
| 84 | + "!{projectRoot}/tsconfig.spec.json", |
| 85 | + "!{projectRoot}/jest.config.[jt]s", |
| 86 | + "!{projectRoot}/src/test-setup.[jt]s", |
| 87 | + "!{projectRoot}/test-setup.[jt]s" |
| 88 | + ], |
| 89 | + "sharedGlobals": ["{workspaceRoot}/.github/workflows/ci.yml"] |
| 90 | + }, |
| 91 | + "nxCloudId": "67a3783761d0514ff26bf202", |
| 92 | + "plugins": [ |
| 93 | + { |
| 94 | + "plugin": "@nx/webpack/plugin", |
| 95 | + "options": { |
| 96 | + "buildTargetName": "build", |
| 97 | + "serveTargetName": "serve", |
| 98 | + "previewTargetName": "preview", |
| 99 | + "buildDepsTargetName": "build-deps", |
| 100 | + "watchDepsTargetName": "watch-deps" |
| 101 | + } |
| 102 | + }, |
| 103 | + { |
| 104 | + "plugin": "@nx/eslint/plugin", |
| 105 | + "options": { |
| 106 | + "targetName": "lint" |
| 107 | + } |
| 108 | + }, |
| 109 | + { |
| 110 | + "plugin": "@nx/playwright/plugin", |
| 111 | + "options": { |
| 112 | + "targetName": "e2e" |
| 113 | + } |
| 114 | + }, |
| 115 | + { |
| 116 | + "plugin": "@nx/jest/plugin", |
| 117 | + "options": { |
| 118 | + "targetName": "test" |
| 119 | + } |
| 120 | + } |
| 121 | + ], |
| 122 | + "targetDefaults": { |
| 123 | + "e2e-ci--**/*": { |
| 124 | + "dependsOn": ["^build"] |
| 125 | + } |
| 126 | + }, |
| 127 | + "generators": { |
| 128 | + "@nx/react": { |
| 129 | + "application": { |
| 130 | + "babel": true, |
| 131 | + "style": "tailwind", |
| 132 | + "linter": "eslint", |
| 133 | + "bundler": "webpack" |
| 134 | + }, |
| 135 | + "component": { |
| 136 | + "style": "tailwind" |
| 137 | + }, |
| 138 | + "library": { |
| 139 | + "style": "tailwind", |
| 140 | + "linter": "eslint" |
| 141 | + } |
| 142 | + } |
| 143 | + }, |
| 144 | + "projects": { |
| 145 | + "hatch_project": { |
| 146 | + "root": "src/hatch_project", |
| 147 | + "sourceRoot": "src/hatch_project/src", |
| 148 | + "projectType": "application" |
| 149 | + } |
| 150 | + } |
| 151 | +} |
| 152 | +``` |
| 153 | +/hatch-project/nx.json |
| 154 | + |
| 155 | +### Key Adjustments: |
| 156 | +- **`projects` section**: Explicitly defines the project structure, setting the `root` and `sourceRoot` to the correct paths within the nested directory. |
| 157 | +- Ensure that all paths reflect the actual structure of your workspace. |
| 158 | + |
| 159 | +This configuration will help Nx Cloud properly identify and manage your nested workspace. |
| 160 | + |
| 161 | +Notice that it prepends paths with ```src/``` (e.g., ```"root": "src/hatch_project",```) to allow for our **nested** directory structure. |
| 162 | + |
| 163 | +The path for `root` in the `projects` section should be specified relative to the workspace root, which is typically the directory where your `nx.json` file is located. |
| 164 | + |
| 165 | +Since your `nx.json` is at `repository-name/hatch-project/src/hatch_project/nx.json`, the paths are relative to the `src/hatch_project` directory. Thus: |
| 166 | + |
| 167 | +- **`root`**: Should be `"src/hatch_project"` because it indicates the base directory for the project relative to the workspace's root. |
| 168 | +- **`sourceRoot`**: Should be `"src/hatch_project/src"` for the same reason. |
| 169 | + |
| 170 | +If you were to use the absolute path `hatch-project/src/hatch_project`, it would not be correct in the context of how Nx expects paths to be defined. Nx uses paths relative to the workspace root to maintain consistency across different environments and setups. |
| 171 | + |
| 172 | +### Key Sections: |
| 173 | +- **`npmScope`**: Defines the scope for your packages. |
| 174 | +- **`affected.defaultBase`**: Specifies the default branch for determining affected projects. |
| 175 | +- **`tasksRunnerOptions`**: Configures caching and task running options. |
| 176 | +- **`projects`**: Contains the project configuration, specifying the root and source root paths, project type, and build targets. |
| 177 | + |
| 178 | +Adjust paths and options as necessary to fit your specific project structure. This configuration will help Nx Cloud identify and manage your workspace correctly. |
| 179 | + |
| 180 | +Make sure to run the **build** command from the `/hatch-project/src/hatch_project` directory - which contains the ```nx.json``` file - to ensure it recognizes the workspace correctly: |
| 181 | +``` |
| 182 | +$ cd /hatch-project/src/hatch_project |
| 183 | +$ nx build hatch_project |
| 184 | +``` |
| 185 | + |
| 186 | +**Important**: |
| 187 | + |
| 188 | +If you don't have `workspace.json` or `project.json`, and instead have `tsconfig.base.json`, you can adjust your setup as follows: |
| 189 | + |
| 190 | +* Option: Single Application: **Create a `workspace.json`**: If your project is a single application, you can create a `workspace.json` file in the root of the repository. Here’s a basic example: |
| 191 | + |
| 192 | + ```json |
| 193 | + { |
| 194 | + "version": 1, |
| 195 | + "projects": { |
| 196 | + "hatch_project": { |
| 197 | + "root": "hatch-project/src/hatch_project", |
| 198 | + "sourceRoot": "hatch-project/src/hatch_project/src", |
| 199 | + "projectType": "application" |
| 200 | + } |
| 201 | + } |
| 202 | + } |
| 203 | + ``` |
| 204 | + |
| 205 | +* Option: Multiple Applications: If your Nx workspace contains multiple applications, you should structure your `workspace.json` (or `project.json`) to reflect each application. Here’s how to set it up: |
| 206 | + |
| 207 | +### Example `workspace.json` |
| 208 | + |
| 209 | +Create a `workspace.json` file in the root of the repository with the following structure: |
| 210 | + |
| 211 | +```json |
| 212 | +{ |
| 213 | + "version": 1, |
| 214 | + "projects": { |
| 215 | + "app1": { |
| 216 | + "root": "hatch-project/src/hatch_project/app1", |
| 217 | + "sourceRoot": "hatch-project/src/hatch_project/app1/src", |
| 218 | + "projectType": "application" |
| 219 | + }, |
| 220 | + "app2": { |
| 221 | + "root": "hatch-project/src/hatch_project/app2", |
| 222 | + "sourceRoot": "hatch-project/src/hatch_project/app2/src", |
| 223 | + "projectType": "application" |
| 224 | + }, |
| 225 | + "hatch_project": { |
| 226 | + "root": "hatch-project/src/hatch_project", |
| 227 | + "sourceRoot": "hatch-project/src/hatch_project/src", |
| 228 | + "projectType": "application" |
| 229 | + } |
| 230 | + } |
| 231 | +} |
| 232 | +``` |
| 233 | + |
| 234 | +### Key Points: |
| 235 | +- **Project Names**: Replace `app1`, `app2`, etc., with meaningful names for your applications. |
| 236 | +- **Root and Source Root**: Adjust the `root` and `sourceRoot` paths to match the actual structure of your applications within the `hatch_project` directory. |
| 237 | + |
| 238 | +### Additional Considerations: |
| 239 | +- **Dependencies**: If applications depend on shared libraries or each other, ensure to define those dependencies in the `nx.json` file. |
| 240 | +- **Configuration Files**: Each application may also have its own `tsconfig.json` if needed, or you can use a shared `tsconfig.base.json` for common settings. |
| 241 | + |
| 242 | +### Example Directory Structure |
| 243 | +Your directory structure might look like this: |
| 244 | + |
| 245 | +``` |
| 246 | +/ |
| 247 | +├── hatch-project/ |
| 248 | +| ├── tsconfig.base.json |
| 249 | +│ └── src/ |
| 250 | +│ └── hatch_project/ |
| 251 | +│ ├── REMOVE: nx.json |
| 252 | +│ ├── REMOVE: workspace.json |
| 253 | +│ ├── REMOVE: tsconfig.base.json |
| 254 | +│ ├── app1/ |
| 255 | +│ │ └── src/ |
| 256 | +│ │ └── main.tsx |
| 257 | +│ ├── app2/ |
| 258 | +│ │ └── src/ |
| 259 | +│ │ └── main.tsx |
| 260 | +├── nx.json |
| 261 | +├── workspace.json |
| 262 | +``` |
| 263 | + |
| 264 | +### Running Commands |
| 265 | +After setting up `workspace.json`, you can run commands like: |
| 266 | + |
| 267 | +```bash |
| 268 | +nx build app1 |
| 269 | +nx build app2 |
| 270 | +``` |
| 271 | + |
| 272 | +This structure will help Nx Cloud recognize and manage multiple applications effectively. |
| 273 | + |
| 274 | +This structure should allow Nx Cloud to detect the workspace properly. |
| 275 | + |
| 276 | +Run the command to **connect** your workspace to Nx Cloud from the root of the repository, specifically: |
| 277 | + |
| 278 | +``` |
| 279 | +$ cd /../../../ |
| 280 | +$ npm init -y # If no package.json exists |
| 281 | +# Go through the initialization steps |
| 282 | +$ npm install -g nx@latest # If not already installed |
| 283 | +$ npm install --save-dev nx @nrwl/workspace |
| 284 | +$ npm install --save-dev @nx/webpack |
| 285 | +$ npm install --save-dev webpack-cli |
| 286 | +$ npm install --save-dev @nx/react @nx/eslint @nx/playwright @nx/jest |
| 287 | +``` |
| 288 | + |
| 289 | +Now commit these changes to GitHub repository before continuing! |
| 290 | + |
| 291 | +The command to connect to Nx Cloud is: |
| 292 | + |
| 293 | +``` |
| 294 | +$ nx connect-to-nx-cloud |
| 295 | +``` |
| 296 | + |
| 297 | +This will initiate the configuration process for Nx Cloud within your workspace. |
| 298 | + |
| 299 | +You will be prompted as follows: |
| 300 | + |
| 301 | +``` |
| 302 | + NX ✔ This workspace already has Nx Cloud set up |
| 303 | +
|
| 304 | +If you have not done so already, connect your workspace to your Nx Cloud account with the following URL: |
| 305 | +
|
| 306 | +https://cloud.nx.app/connect/Ehf8PFoDWR |
| 307 | +``` |
| 308 | + |
| 309 | +Finish the CI setup by visiting: https://cloud.nx.app/connect/eXwFUcpdBt # **Note**: the URL will differ per creation. See [Enable GitHub PR Integration](https://nx.dev/ci/recipes/source-control-integration/github) and/or watch [PNPM-CI: Connect Your Workspace to Nx Cloud for Enhanced Collaboration](https://www.youtube.com/watch?v=8mqHXYIl_qI). |
| 310 | + |
| 311 | + |
| 312 | +The message "A workspace has already been assigned to this Nx Cloud connection" means that: |
| 313 | + |
| 314 | +1. Your workspace is already configured with an Nx Cloud ID |
| 315 | +2. That ID is already in use by another workspace |
| 316 | + |
| 317 | +To fix this: |
| 318 | + |
| 319 | +1. Check your current nx.json for the existing nxCloudId: |
| 320 | + - Look for a line like: "nxCloudId": "67a3783761d0514ff26bf202" |
| 321 | + - This ID needs to be unique for each workspace |
| 322 | + |
| 323 | +2. Generate a new connection: |
| 324 | + |
| 325 | +``` |
| 326 | +$ nx generate @nx/workspace:disconnect-cloud |
| 327 | +$ nx connect-to-nx-cloud |
| 328 | +``` |
| 329 | + |
| 330 | +This will: |
| 331 | + - Remove the existing cloud connection |
| 332 | + - Generate a new, unique connection |
| 333 | + - Provide you with a fresh URL to connect |
| 334 | + |
| 335 | + |
| 336 | + |
| 337 | +## Nested app directories |
| 338 | + |
| 339 | +You can have nested folders, no problems. 👍 Here's a [live example](https://github.com/codyslexia/nexa/tree/main/apps/graphql). You can see that apps/graphql/users is a nested directory where users is the actual project. There's also this [other example](https://github.com/nrwl/nx-incremental-large-repo/tree/master/libs/app0/lib1) from the ```nrwl``` family. |
| 340 | + |
| 341 | +## Nx ignore |
| 342 | + |
| 343 | +You can place a ```.nxignore``` in the root of the project directory, here ```/hatch-project/src/hatch_project/.nxignore```. |
| 344 | + |
| 345 | +For example to ignore any files in ```.next```: |
| 346 | + |
| 347 | +``` |
| 348 | +.next |
| 349 | +``` |
| 350 | +.nxignore |
| 351 | + |
| 352 | + |
| 353 | +Now to run a build, run the following command from the root of the repository: |
| 354 | + |
| 355 | +``` |
| 356 | +npx nx run-many -t build |
| 357 | +``` |
| 358 | + |
| 359 | +To run a build for all applications, run the following command from the root of the repository: |
| 360 | + |
| 361 | +``` |
| 362 | +npx nx run-many -t build --all |
| 363 | +``` |
0 commit comments