feat(react): update app and lib generators to support new TS solution setup (#28808)
This PR updates app and lib generators in the following packages such that they will generate files with the TS solution setup if it is detected. - `@nx/react` - `@nx/next` - `@nx/remix` - `@nx/expo` - `@nx/react-native` React apps and libs will be linked using npm/pnpm/yarn/bun workspaces feature rather than through tsconfig paths. This means that local aliases like `@/` will work with Next.js and Remix apps. Note: This will be behind `--workspaces` flag when using `npx create-nx-workspace` and choosing React stack. If you use the None/TS stack then adding plugins like `nx add @nx/react` then generating apps, it will automatically pick up the new TS solution setup. <!-- If this is a particularly complex change or feature addition, you can request a dedicated Nx release for this pull request branch. Mention someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they will confirm if the PR warrants its own release for testing purposes, and generate it for you if appropriate. --> ## Current Behavior React generators are not compatible with TS solution setup (i.e. workspaces + TS project references). ## Expected Behavior React generators work with new TS solution setup (Plain, Next.js, Remix, Expo, React Native). ## Related Issue(s) #28322 --------- Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com> Co-authored-by: Nicholas Cunningham <ndcunningham@gmail.com>
This commit is contained in:
parent
2cb58b937d
commit
ec5a5e6360
@ -28,6 +28,7 @@ Install `create-nx-workspace` globally to invoke the command directly, or use `n
|
|||||||
| `--defaultBase` | string | Default base to use for new projects. (Default: `main`) |
|
| `--defaultBase` | string | Default base to use for new projects. (Default: `main`) |
|
||||||
| `--docker` | boolean | Generate a Dockerfile for the Node API. |
|
| `--docker` | boolean | Generate a Dockerfile for the Node API. |
|
||||||
| `--e2eTestRunner` | `playwright`, `cypress`, `none` | Test runner to use for end to end (E2E) tests. |
|
| `--e2eTestRunner` | `playwright`, `cypress`, `none` | Test runner to use for end to end (E2E) tests. |
|
||||||
|
| `--formatter` | string | Code formatter to use. |
|
||||||
| `--framework` | string | Framework option to be used with certain stacks. |
|
| `--framework` | string | Framework option to be used with certain stacks. |
|
||||||
| `--help` | boolean | Show help. |
|
| `--help` | boolean | Show help. |
|
||||||
| `--interactive` | boolean | Enable interactive mode with presets. (Default: `true`) |
|
| `--interactive` | boolean | Enable interactive mode with presets. (Default: `true`) |
|
||||||
@ -45,6 +46,7 @@ Install `create-nx-workspace` globally to invoke the command directly, or use `n
|
|||||||
| `--style` | string | Stylesheet type to be used with certain stacks. |
|
| `--style` | string | Stylesheet type to be used with certain stacks. |
|
||||||
| `--useGitHub` | boolean | Will you be using GitHub as your git hosting provider? (Default: `false`) |
|
| `--useGitHub` | boolean | Will you be using GitHub as your git hosting provider? (Default: `false`) |
|
||||||
| `--version` | boolean | Show version number. |
|
| `--version` | boolean | Show version number. |
|
||||||
|
| `--workspaces` | boolean | Use package manager workspaces. (Default: `false`) |
|
||||||
| `--workspaceType` | `integrated`, `package-based`, `standalone` | The type of workspace to create. |
|
| `--workspaceType` | `integrated`, `package-based`, `standalone` | The type of workspace to create. |
|
||||||
|
|
||||||
## Presets
|
## Presets
|
||||||
|
|||||||
@ -44,13 +44,15 @@
|
|||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint", "none"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "none"],
|
||||||
"description": "Test runner to use for unit tests",
|
"description": "Test runner to use for unit tests",
|
||||||
"default": "jest"
|
"default": "none",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -71,7 +73,8 @@
|
|||||||
"description": "Adds the specified e2e test runner",
|
"description": "Adds the specified e2e test runner",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["playwright", "cypress", "detox", "none"],
|
"enum": ["playwright", "cypress", "detox", "none"],
|
||||||
"default": "none"
|
"default": "none",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"standaloneConfig": {
|
"standaloneConfig": {
|
||||||
"description": "Split the project configuration into `<projectRoot>/project.json` rather than including it inside `workspace.json`.",
|
"description": "Split the project configuration into `<projectRoot>/project.json` rather than including it inside `workspace.json`.",
|
||||||
|
|||||||
@ -29,13 +29,16 @@
|
|||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint", "none"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "none"],
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"default": "jest"
|
"default": "none",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -63,8 +63,10 @@
|
|||||||
"linter": {
|
"linter": {
|
||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"skipFormat": {
|
"skipFormat": {
|
||||||
"description": "Skip formatting files.",
|
"description": "Skip formatting files.",
|
||||||
@ -76,7 +78,9 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "none"],
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"default": "jest"
|
"default": "none",
|
||||||
|
"x-prompt": "What unit test runner should be used?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"e2eTestRunner": {
|
"e2eTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -56,17 +56,29 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"bundler": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The bundler to use. Choosing 'none' means this library is not buildable.",
|
||||||
|
"enum": ["none", "vite", "rollup"],
|
||||||
|
"default": "none",
|
||||||
|
"x-prompt": "Which bundler would you like to use to build the library? Choose 'none' to skip build setup.",
|
||||||
|
"x-priority": "important"
|
||||||
|
},
|
||||||
"linter": {
|
"linter": {
|
||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["vitest", "jest", "none"],
|
"enum": ["vitest", "jest", "none"],
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"default": "vitest"
|
"default": "none",
|
||||||
|
"x-prompt": "What unit test runner should be used?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -99,7 +111,8 @@
|
|||||||
"buildable": {
|
"buildable": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": "Generate a buildable library."
|
"description": "Generate a buildable library that uses rollup to bundle.",
|
||||||
|
"x-deprecated": "Use the `bundler` option for greater control (none, vite, rollup)."
|
||||||
},
|
},
|
||||||
"importPath": {
|
"importPath": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -28,6 +28,7 @@ Install `create-nx-workspace` globally to invoke the command directly, or use `n
|
|||||||
| `--defaultBase` | string | Default base to use for new projects. (Default: `main`) |
|
| `--defaultBase` | string | Default base to use for new projects. (Default: `main`) |
|
||||||
| `--docker` | boolean | Generate a Dockerfile for the Node API. |
|
| `--docker` | boolean | Generate a Dockerfile for the Node API. |
|
||||||
| `--e2eTestRunner` | `playwright`, `cypress`, `none` | Test runner to use for end to end (E2E) tests. |
|
| `--e2eTestRunner` | `playwright`, `cypress`, `none` | Test runner to use for end to end (E2E) tests. |
|
||||||
|
| `--formatter` | string | Code formatter to use. |
|
||||||
| `--framework` | string | Framework option to be used with certain stacks. |
|
| `--framework` | string | Framework option to be used with certain stacks. |
|
||||||
| `--help` | boolean | Show help. |
|
| `--help` | boolean | Show help. |
|
||||||
| `--interactive` | boolean | Enable interactive mode with presets. (Default: `true`) |
|
| `--interactive` | boolean | Enable interactive mode with presets. (Default: `true`) |
|
||||||
@ -45,6 +46,7 @@ Install `create-nx-workspace` globally to invoke the command directly, or use `n
|
|||||||
| `--style` | string | Stylesheet type to be used with certain stacks. |
|
| `--style` | string | Stylesheet type to be used with certain stacks. |
|
||||||
| `--useGitHub` | boolean | Will you be using GitHub as your git hosting provider? (Default: `false`) |
|
| `--useGitHub` | boolean | Will you be using GitHub as your git hosting provider? (Default: `false`) |
|
||||||
| `--version` | boolean | Show version number. |
|
| `--version` | boolean | Show version number. |
|
||||||
|
| `--workspaces` | boolean | Use package manager workspaces. (Default: `false`) |
|
||||||
| `--workspaceType` | `integrated`, `package-based`, `standalone` | The type of workspace to create. |
|
| `--workspaceType` | `integrated`, `package-based`, `standalone` | The type of workspace to create. |
|
||||||
|
|
||||||
## Presets
|
## Presets
|
||||||
|
|||||||
@ -44,13 +44,15 @@
|
|||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint", "none"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "none"],
|
||||||
"description": "Test runner to use for unit tests",
|
"description": "Test runner to use for unit tests",
|
||||||
"default": "jest"
|
"default": "none",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -71,7 +73,8 @@
|
|||||||
"description": "Adds the specified e2e test runner.",
|
"description": "Adds the specified e2e test runner.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["playwright", "cypress", "detox", "none"],
|
"enum": ["playwright", "cypress", "detox", "none"],
|
||||||
"default": "playwright"
|
"default": "none",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"install": {
|
"install": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
|||||||
@ -32,13 +32,16 @@
|
|||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint", "none"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "none"],
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"default": "jest"
|
"default": "none",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -74,12 +74,6 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"linter": {
|
|
||||||
"description": "The tool to use for running lint checks.",
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["eslint", "none"],
|
|
||||||
"default": "eslint"
|
|
||||||
},
|
|
||||||
"routing": {
|
"routing": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Generate application with routes.",
|
"description": "Generate application with routes.",
|
||||||
@ -98,11 +92,29 @@
|
|||||||
"default": false,
|
"default": false,
|
||||||
"x-priority": "internal"
|
"x-priority": "internal"
|
||||||
},
|
},
|
||||||
|
"bundler": {
|
||||||
|
"description": "The bundler to use.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["vite", "webpack", "rspack"],
|
||||||
|
"x-prompt": "Which bundler do you want to use to build the application?",
|
||||||
|
"default": "vite",
|
||||||
|
"x-priority": "important"
|
||||||
|
},
|
||||||
|
"linter": {
|
||||||
|
"description": "The tool to use for running lint checks.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["eslint", "none"],
|
||||||
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["vitest", "jest", "none"],
|
"enum": ["vitest", "jest", "none"],
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"default": "vitest"
|
"default": "none",
|
||||||
|
"x-prompt": "What unit test runner should be used?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"inSourceTests": {
|
"inSourceTests": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
@ -165,14 +177,6 @@
|
|||||||
"default": false,
|
"default": false,
|
||||||
"hidden": true
|
"hidden": true
|
||||||
},
|
},
|
||||||
"bundler": {
|
|
||||||
"description": "The bundler to use.",
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["vite", "webpack", "rspack"],
|
|
||||||
"x-prompt": "Which bundler do you want to use to build the application?",
|
|
||||||
"default": "vite",
|
|
||||||
"x-priority": "important"
|
|
||||||
},
|
|
||||||
"minimal": {
|
"minimal": {
|
||||||
"description": "Generate a React app with a minimal setup, no separate test files.",
|
"description": "Generate a React app with a minimal setup, no separate test files.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
|||||||
@ -65,18 +65,29 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"bundler": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The bundler to use. Choosing 'none' means this library is not buildable.",
|
||||||
|
"enum": ["none", "vite", "rollup"],
|
||||||
|
"default": "none",
|
||||||
|
"x-prompt": "Which bundler would you like to use to build the library? Choose 'none' to skip build setup.",
|
||||||
|
"x-priority": "important"
|
||||||
|
},
|
||||||
"linter": {
|
"linter": {
|
||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint", "none"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["vitest", "jest", "none"],
|
"enum": ["vitest", "jest", "none"],
|
||||||
"default": "vitest",
|
"default": "none",
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"x-prompt": "What unit test runner should be used?"
|
"x-prompt": "What unit test runner should be used?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"inSourceTests": {
|
"inSourceTests": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
@ -148,14 +159,6 @@
|
|||||||
"description": "Whether or not to configure the ESLint `parserOptions.project` option. We do not do this by default for lint performance reasons.",
|
"description": "Whether or not to configure the ESLint `parserOptions.project` option. We do not do this by default for lint performance reasons.",
|
||||||
"default": false
|
"default": false
|
||||||
},
|
},
|
||||||
"bundler": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The bundler to use. Choosing 'none' means this library is not buildable.",
|
|
||||||
"enum": ["none", "vite", "rollup"],
|
|
||||||
"default": "none",
|
|
||||||
"x-prompt": "Which bundler would you like to use to build the library? Choose 'none' to skip build setup.",
|
|
||||||
"x-priority": "important"
|
|
||||||
},
|
|
||||||
"compiler": {
|
"compiler": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["babel", "swc"],
|
"enum": ["babel", "swc"],
|
||||||
|
|||||||
@ -24,19 +24,22 @@
|
|||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint", "none"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["vitest", "jest", "none"],
|
"enum": ["vitest", "jest", "none"],
|
||||||
"default": "vitest",
|
"default": "none",
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"x-prompt": "What unit test runner should be used?"
|
"x-prompt": "What unit test runner should be used?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"e2eTestRunner": {
|
"e2eTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["playwright", "cypress", "none"],
|
"enum": ["playwright", "cypress", "none"],
|
||||||
"default": "playwright",
|
"default": "none",
|
||||||
"description": "Test runner to use for e2e tests",
|
"description": "Test runner to use for e2e tests",
|
||||||
"x-prompt": "Which E2E test runner would you like to use?"
|
"x-prompt": "Which E2E test runner would you like to use?"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -37,17 +37,29 @@
|
|||||||
"enum": ["none", "css"],
|
"enum": ["none", "css"],
|
||||||
"default": "css"
|
"default": "css"
|
||||||
},
|
},
|
||||||
"buildable": {
|
"bundler": {
|
||||||
"type": "boolean",
|
"type": "string",
|
||||||
"description": "Should the library be buildable?",
|
"description": "The bundler to use. Choosing 'none' means this library is not buildable.",
|
||||||
"default": false
|
"enum": ["none", "vite", "rollup"],
|
||||||
|
"default": "none",
|
||||||
|
"x-prompt": "Which bundler would you like to use to build the library? Choose 'none' to skip build setup.",
|
||||||
|
"x-priority": "important"
|
||||||
|
},
|
||||||
|
"linter": {
|
||||||
|
"description": "The tool to use for running lint checks.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["eslint", "none"],
|
||||||
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["vitest", "jest", "none"],
|
"enum": ["vitest", "jest", "none"],
|
||||||
"description": "Test Runner to use for Unit Tests",
|
"description": "Test Runner to use for Unit Tests",
|
||||||
"x-prompt": "What test runner should be used?",
|
"x-prompt": "What test runner should be used?",
|
||||||
"default": "vitest"
|
"default": "none",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"importPath": {
|
"importPath": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -63,6 +75,12 @@
|
|||||||
"description": "Skip formatting files after generator runs",
|
"description": "Skip formatting files after generator runs",
|
||||||
"default": false,
|
"default": false,
|
||||||
"x-priority": "internal"
|
"x-priority": "internal"
|
||||||
|
},
|
||||||
|
"buildable": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Generate a buildable library that uses rollup to bundle.",
|
||||||
|
"x-deprecated": "Use the `bundler` option for greater control (none, vite, rollup)."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["directory"],
|
"required": ["directory"],
|
||||||
|
|||||||
@ -119,7 +119,7 @@
|
|||||||
"extractLicenses": {
|
"extractLicenses": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Extract all licenses in a separate file.",
|
"description": "Extract all licenses in a separate file.",
|
||||||
"default": true
|
"default": false
|
||||||
},
|
},
|
||||||
"fileReplacements": {
|
"fileReplacements": {
|
||||||
"description": "Replace files with other files in the build.",
|
"description": "Replace files with other files in the build.",
|
||||||
|
|||||||
@ -47,7 +47,7 @@
|
|||||||
"linter": {
|
"linter": {
|
||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "eslint"
|
||||||
},
|
},
|
||||||
"packageManager": {
|
"packageManager": {
|
||||||
@ -89,6 +89,11 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["none", "prettier"],
|
"enum": ["none", "prettier"],
|
||||||
"default": "none"
|
"default": "none"
|
||||||
|
},
|
||||||
|
"workspaces": {
|
||||||
|
"description": "Whether to use package manager workspaces.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": true,
|
"additionalProperties": true,
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
"linter": {
|
"linter": {
|
||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "eslint"
|
||||||
},
|
},
|
||||||
"routing": {
|
"routing": {
|
||||||
@ -100,6 +100,17 @@
|
|||||||
"prefix": {
|
"prefix": {
|
||||||
"description": "The prefix to use for Angular component and directive selectors.",
|
"description": "The prefix to use for Angular component and directive selectors.",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"formatter": {
|
||||||
|
"description": "The tool to use for code formatting.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["none", "prettier"],
|
||||||
|
"default": "none"
|
||||||
|
},
|
||||||
|
"workspaces": {
|
||||||
|
"description": "Whether to use package manager workspaces.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["preset", "name"],
|
"required": ["preset", "name"],
|
||||||
|
|||||||
@ -27,10 +27,13 @@ describe('Linter (legacy)', () => {
|
|||||||
newProject({
|
newProject({
|
||||||
packages: ['@nx/react', '@nx/js', '@nx/eslint'],
|
packages: ['@nx/react', '@nx/js', '@nx/eslint'],
|
||||||
});
|
});
|
||||||
runCLI(`generate @nx/react:app apps/${myapp} --tags=validtag`, {
|
runCLI(
|
||||||
|
`generate @nx/react:app apps/${myapp} --tags=validtag --linter=eslint`,
|
||||||
|
{
|
||||||
env: { NX_ADD_PLUGINS: 'false' },
|
env: { NX_ADD_PLUGINS: 'false' },
|
||||||
});
|
}
|
||||||
runCLI(`generate @nx/js:lib apps/${mylib}`, {
|
);
|
||||||
|
runCLI(`generate @nx/js:lib apps/${mylib} --linter=eslint`, {
|
||||||
env: { NX_ADD_PLUGINS: 'false' },
|
env: { NX_ADD_PLUGINS: 'false' },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -135,10 +138,10 @@ describe('Linter (legacy)', () => {
|
|||||||
bundler: 'vite',
|
bundler: 'vite',
|
||||||
e2eTestRunner: 'none',
|
e2eTestRunner: 'none',
|
||||||
});
|
});
|
||||||
runCLI(`generate @nx/js:lib libs/${mylib}`, {
|
runCLI(`generate @nx/js:lib libs/${mylib} --linter=eslint`, {
|
||||||
env: { NX_ADD_PLUGINS: 'false' },
|
env: { NX_ADD_PLUGINS: 'false' },
|
||||||
});
|
});
|
||||||
runCLI(`generate @nx/js:lib libs/${mylib2}`, {
|
runCLI(`generate @nx/js:lib libs/${mylib2} --linter=eslint`, {
|
||||||
env: { NX_ADD_PLUGINS: 'false' },
|
env: { NX_ADD_PLUGINS: 'false' },
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -190,7 +193,7 @@ describe('Linter (legacy)', () => {
|
|||||||
bundler: 'vite',
|
bundler: 'vite',
|
||||||
e2eTestRunner: 'none',
|
e2eTestRunner: 'none',
|
||||||
});
|
});
|
||||||
runCLI(`generate @nx/js:lib ${mylib}`, {
|
runCLI(`generate @nx/js:lib ${mylib} --linter=eslint`, {
|
||||||
env: { NX_ADD_PLUGINS: 'false' },
|
env: { NX_ADD_PLUGINS: 'false' },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -35,8 +35,10 @@ describe('Linter', () => {
|
|||||||
projScope = newProject({
|
projScope = newProject({
|
||||||
packages: ['@nx/react', '@nx/js', '@nx/eslint'],
|
packages: ['@nx/react', '@nx/js', '@nx/eslint'],
|
||||||
});
|
});
|
||||||
runCLI(`generate @nx/react:app apps/${myapp} --tags=validtag`);
|
runCLI(
|
||||||
runCLI(`generate @nx/js:lib libs/${mylib}`);
|
`generate @nx/react:app apps/${myapp} --tags=validtag --linter eslint --unitTestRunner vitest`
|
||||||
|
);
|
||||||
|
runCLI(`generate @nx/js:lib libs/${mylib} --linter eslint`);
|
||||||
});
|
});
|
||||||
afterAll(() => cleanupProject());
|
afterAll(() => cleanupProject());
|
||||||
|
|
||||||
@ -218,10 +220,14 @@ describe('Linter', () => {
|
|||||||
const invalidtaglib = uniq('invalidtaglib');
|
const invalidtaglib = uniq('invalidtaglib');
|
||||||
const validtaglib = uniq('validtaglib');
|
const validtaglib = uniq('validtaglib');
|
||||||
|
|
||||||
runCLI(`generate @nx/react:app apps/${myapp2}`);
|
runCLI(`generate @nx/react:app apps/${myapp2} --linter eslint`);
|
||||||
runCLI(`generate @nx/react:lib libs/${lazylib}`);
|
runCLI(`generate @nx/react:lib libs/${lazylib} --linter eslint`);
|
||||||
runCLI(`generate @nx/js:lib libs/${invalidtaglib} --tags=invalidtag`);
|
runCLI(
|
||||||
runCLI(`generate @nx/js:lib libs/${validtaglib} --tags=validtag`);
|
`generate @nx/js:lib libs/${invalidtaglib} --linter eslint --tags=invalidtag`
|
||||||
|
);
|
||||||
|
runCLI(
|
||||||
|
`generate @nx/js:lib libs/${validtaglib} --linter eslint --tags=validtag`
|
||||||
|
);
|
||||||
|
|
||||||
const eslint = readJson('.eslintrc.json');
|
const eslint = readJson('.eslintrc.json');
|
||||||
eslint.overrides[0].rules[
|
eslint.overrides[0].rules[
|
||||||
@ -283,9 +289,15 @@ describe('Linter', () => {
|
|||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
// make these libs non-buildable to avoid dep-checks triggering lint errors
|
// make these libs non-buildable to avoid dep-checks triggering lint errors
|
||||||
runCLI(`generate @nx/js:lib libs/${libA} --bundler=none`);
|
runCLI(
|
||||||
runCLI(`generate @nx/js:lib libs/${libB} --bundler=none`);
|
`generate @nx/js:lib libs/${libA} --bundler=none --linter eslint`
|
||||||
runCLI(`generate @nx/js:lib libs/${libC} --bundler=none`);
|
);
|
||||||
|
runCLI(
|
||||||
|
`generate @nx/js:lib libs/${libB} --bundler=none --linter eslint`
|
||||||
|
);
|
||||||
|
runCLI(
|
||||||
|
`generate @nx/js:lib libs/${libC} --bundler=none --linter eslint`
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create tslib-a structure
|
* create tslib-a structure
|
||||||
@ -599,8 +611,8 @@ describe('Linter', () => {
|
|||||||
const reactLib = uniq('react-lib');
|
const reactLib = uniq('react-lib');
|
||||||
const jsLib = uniq('js-lib');
|
const jsLib = uniq('js-lib');
|
||||||
|
|
||||||
runCLI(`generate @nx/react:lib ${reactLib}`);
|
runCLI(`generate @nx/react:lib ${reactLib} --linter eslint`);
|
||||||
runCLI(`generate @nx/js:lib ${jsLib}`);
|
runCLI(`generate @nx/js:lib ${jsLib} --linter eslint`);
|
||||||
|
|
||||||
checkFilesExist(
|
checkFilesExist(
|
||||||
`${reactLib}/eslint.config.js`,
|
`${reactLib}/eslint.config.js`,
|
||||||
@ -687,7 +699,7 @@ describe('Linter', () => {
|
|||||||
const mylib = uniq('mylib');
|
const mylib = uniq('mylib');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:app --name=${myapp} --unitTestRunner=jest --directory="."`
|
`generate @nx/react:app --name=${myapp} --unitTestRunner=jest --linter eslint --directory="."`
|
||||||
);
|
);
|
||||||
verifySuccessfulStandaloneSetup(myapp);
|
verifySuccessfulStandaloneSetup(myapp);
|
||||||
|
|
||||||
@ -701,7 +713,9 @@ describe('Linter', () => {
|
|||||||
let e2eOverrides = JSON.stringify(e2eEslint.overrides);
|
let e2eOverrides = JSON.stringify(e2eEslint.overrides);
|
||||||
expect(e2eOverrides).toContain('plugin:@nx/javascript');
|
expect(e2eOverrides).toContain('plugin:@nx/javascript');
|
||||||
|
|
||||||
runCLI(`generate @nx/js:lib libs/${mylib} --unitTestRunner=jest`);
|
runCLI(
|
||||||
|
`generate @nx/js:lib libs/${mylib} --unitTestRunner=jest --linter eslint`
|
||||||
|
);
|
||||||
verifySuccessfulMigratedSetup(myapp, mylib);
|
verifySuccessfulMigratedSetup(myapp, mylib);
|
||||||
|
|
||||||
appEslint = readJson(`.eslintrc.json`);
|
appEslint = readJson(`.eslintrc.json`);
|
||||||
@ -721,7 +735,7 @@ describe('Linter', () => {
|
|||||||
const mylib = uniq('mylib');
|
const mylib = uniq('mylib');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/angular:app --name=${myapp} --directory="." --no-interactive`
|
`generate @nx/angular:app --name=${myapp} --directory="." --linter eslint --no-interactive`
|
||||||
);
|
);
|
||||||
verifySuccessfulStandaloneSetup(myapp);
|
verifySuccessfulStandaloneSetup(myapp);
|
||||||
|
|
||||||
@ -734,7 +748,9 @@ describe('Linter', () => {
|
|||||||
let e2eOverrides = JSON.stringify(e2eEslint.overrides);
|
let e2eOverrides = JSON.stringify(e2eEslint.overrides);
|
||||||
expect(e2eOverrides).toContain('plugin:@nx/javascript');
|
expect(e2eOverrides).toContain('plugin:@nx/javascript');
|
||||||
|
|
||||||
runCLI(`generate @nx/js:lib libs/${mylib} --no-interactive`);
|
runCLI(
|
||||||
|
`generate @nx/js:lib libs/${mylib} --linter eslint --no-interactive`
|
||||||
|
);
|
||||||
verifySuccessfulMigratedSetup(myapp, mylib);
|
verifySuccessfulMigratedSetup(myapp, mylib);
|
||||||
|
|
||||||
appEslint = readJson(`.eslintrc.json`);
|
appEslint = readJson(`.eslintrc.json`);
|
||||||
@ -752,7 +768,7 @@ describe('Linter', () => {
|
|||||||
const mylib = uniq('mylib');
|
const mylib = uniq('mylib');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/node:app --name=${myapp} --directory="." --no-interactive`
|
`generate @nx/node:app --name=${myapp} --linter eslint --directory="." --no-interactive`
|
||||||
);
|
);
|
||||||
verifySuccessfulStandaloneSetup(myapp);
|
verifySuccessfulStandaloneSetup(myapp);
|
||||||
|
|
||||||
@ -767,7 +783,9 @@ describe('Linter', () => {
|
|||||||
expect(e2eOverrides).toContain('plugin:@nx/javascript');
|
expect(e2eOverrides).toContain('plugin:@nx/javascript');
|
||||||
expect(e2eOverrides).toContain('plugin:@nx/typescript');
|
expect(e2eOverrides).toContain('plugin:@nx/typescript');
|
||||||
|
|
||||||
runCLI(`generate @nx/js:lib libs/${mylib} --no-interactive`);
|
runCLI(
|
||||||
|
`generate @nx/js:lib libs/${mylib} --linter eslint --no-interactive`
|
||||||
|
);
|
||||||
verifySuccessfulMigratedSetup(myapp, mylib);
|
verifySuccessfulMigratedSetup(myapp, mylib);
|
||||||
|
|
||||||
appEslint = readJson(`.eslintrc.json`);
|
appEslint = readJson(`.eslintrc.json`);
|
||||||
|
|||||||
@ -40,10 +40,10 @@ describe('@nx/expo (legacy)', () => {
|
|||||||
return nxJson;
|
return nxJson;
|
||||||
});
|
});
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/expo:application apps/${appName} --e2eTestRunner=cypress --no-interactive`
|
`generate @nx/expo:application apps/${appName} --e2eTestRunner=cypress --no-interactive --unitTestRunner=jest --linter=eslint`
|
||||||
);
|
);
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/expo:library libs/${libName} --buildable --publishable --importPath=${proj}/${libName}`
|
`generate @nx/expo:library libs/${libName} --buildable --publishable --importPath=${proj}/${libName} --unitTestRunner=jest --linter=eslint`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
@ -210,7 +210,9 @@ describe('@nx/expo (legacy)', () => {
|
|||||||
const appName = uniq('app1');
|
const appName = uniq('app1');
|
||||||
const libName = uniq('@my-org/lib1');
|
const libName = uniq('@my-org/lib1');
|
||||||
|
|
||||||
runCLI(`generate @nx/expo:application ${appName} --no-interactive`);
|
runCLI(
|
||||||
|
`generate @nx/expo:application ${appName} --no-interactive --unitTestRunner=jest --linter=eslint`
|
||||||
|
);
|
||||||
|
|
||||||
// check files are generated without the layout directory ("apps/") and
|
// check files are generated without the layout directory ("apps/") and
|
||||||
// using the project name as the directory when no directory is provided
|
// using the project name as the directory when no directory is provided
|
||||||
@ -221,7 +223,9 @@ describe('@nx/expo (legacy)', () => {
|
|||||||
`Successfully ran target test for project ${appName}`
|
`Successfully ran target test for project ${appName}`
|
||||||
);
|
);
|
||||||
|
|
||||||
runCLI(`generate @nx/expo:library ${libName} --buildable`);
|
runCLI(
|
||||||
|
`generate @nx/expo:library ${libName} --buildable --unitTestRunner=jest --linter=eslint`
|
||||||
|
);
|
||||||
|
|
||||||
// check files are generated without the layout directory ("libs/") and
|
// check files are generated without the layout directory ("libs/") and
|
||||||
// using the project name as the directory when no directory is provided
|
// using the project name as the directory when no directory is provided
|
||||||
@ -274,7 +278,7 @@ describe('@nx/expo (legacy)', () => {
|
|||||||
it('should run e2e for playwright', async () => {
|
it('should run e2e for playwright', async () => {
|
||||||
const appName2 = uniq('my-app');
|
const appName2 = uniq('my-app');
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/expo:application ${appName2} --e2eTestRunner=playwright --no-interactive`
|
`generate @nx/expo:application ${appName2} --e2eTestRunner=playwright --no-interactive --unitTestRunner=jest --linter=eslint`
|
||||||
);
|
);
|
||||||
if (runE2ETests()) {
|
if (runE2ETests()) {
|
||||||
const results = runCLI(`e2e ${appName2}-e2e`, { verbose: true });
|
const results = runCLI(`e2e ${appName2}-e2e`, { verbose: true });
|
||||||
|
|||||||
@ -23,7 +23,9 @@ describe('@nx/expo', () => {
|
|||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
newProject();
|
newProject();
|
||||||
appName = uniq('app');
|
appName = uniq('app');
|
||||||
runCLI(`generate @nx/expo:app ${appName} --no-interactive`);
|
runCLI(
|
||||||
|
`generate @nx/expo:app ${appName} --no-interactive --unitTestRunner=jest --linter=eslint`
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(() => cleanupProject());
|
afterAll(() => cleanupProject());
|
||||||
@ -152,7 +154,7 @@ describe('@nx/expo', () => {
|
|||||||
|
|
||||||
it('should create storybook with application', async () => {
|
it('should create storybook with application', async () => {
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:storybook-configuration ${appName} --generateStories --no-interactive`
|
`generate @nx/react:storybook-configuration ${appName} --generateStories --no-interactive --unitTestRunner=jest --linter=eslint`
|
||||||
);
|
);
|
||||||
checkFilesExist(
|
checkFilesExist(
|
||||||
`${appName}/.storybook/main.ts`,
|
`${appName}/.storybook/main.ts`,
|
||||||
|
|||||||
@ -10,7 +10,7 @@ describe('Jest root projects', () => {
|
|||||||
packages: ['@nx/angular'],
|
packages: ['@nx/angular'],
|
||||||
});
|
});
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/angular:app --name=${myapp} --directory . --rootProject --no-interactive`
|
`generate @nx/angular:app --name=${myapp} --directory . --rootProject --no-interactive --unitTestRunner=jest --linter=eslint`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -19,7 +19,9 @@ describe('Jest root projects', () => {
|
|||||||
}, 300_000);
|
}, 300_000);
|
||||||
|
|
||||||
it('should add lib project and tests should still work', async () => {
|
it('should add lib project and tests should still work', async () => {
|
||||||
runCLI(`generate @nx/angular:lib ${mylib} --no-interactive`);
|
runCLI(
|
||||||
|
`generate @nx/angular:lib ${mylib} --no-interactive --unitTestRunner=jest --linter=eslint`
|
||||||
|
);
|
||||||
|
|
||||||
expect(() => runCLI(`test ${mylib}`)).not.toThrow();
|
expect(() => runCLI(`test ${mylib}`)).not.toThrow();
|
||||||
expect(() => runCLI(`test ${myapp}`)).not.toThrow();
|
expect(() => runCLI(`test ${myapp}`)).not.toThrow();
|
||||||
@ -32,7 +34,7 @@ describe('Jest root projects', () => {
|
|||||||
packages: ['@nx/react'],
|
packages: ['@nx/react'],
|
||||||
});
|
});
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:app --name=${myapp} --directory . --rootProject`
|
`generate @nx/react:app --name=${myapp} --directory . --rootProject --unitTestRunner=jest --linter=eslint`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -41,7 +43,9 @@ describe('Jest root projects', () => {
|
|||||||
}, 300_000);
|
}, 300_000);
|
||||||
|
|
||||||
it('should add lib project and tests should still work', async () => {
|
it('should add lib project and tests should still work', async () => {
|
||||||
runCLI(`generate @nx/react:lib ${mylib} --unitTestRunner=jest`);
|
runCLI(
|
||||||
|
`generate @nx/react:lib ${mylib} --unitTestRunner=jest --linter=eslint`
|
||||||
|
);
|
||||||
|
|
||||||
expect(() => runCLI(`test ${mylib}`)).not.toThrow();
|
expect(() => runCLI(`test ${mylib}`)).not.toThrow();
|
||||||
expect(() => runCLI(`test ${myapp}`)).not.toThrow();
|
expect(() => runCLI(`test ${myapp}`)).not.toThrow();
|
||||||
|
|||||||
@ -32,7 +32,7 @@ describe('Next.js Styles', () => {
|
|||||||
const lessApp = uniq('app');
|
const lessApp = uniq('app');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/next:app ${lessApp} --no-interactive --style=less --appDir=false --src=false`
|
`generate @nx/next:app ${lessApp} --no-interactive --style=less --appDir=false --src=false --unitTestRunner=jest --linter=eslint`
|
||||||
);
|
);
|
||||||
|
|
||||||
await checkApp(lessApp, {
|
await checkApp(lessApp, {
|
||||||
@ -44,7 +44,7 @@ describe('Next.js Styles', () => {
|
|||||||
const scApp = uniq('app');
|
const scApp = uniq('app');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/next:app ${scApp} --no-interactive --style=styled-components --appDir=false`
|
`generate @nx/next:app ${scApp} --no-interactive --style=styled-components --appDir=false --unitTestRunner=jest --linter=eslint`
|
||||||
);
|
);
|
||||||
|
|
||||||
await checkApp(scApp, {
|
await checkApp(scApp, {
|
||||||
@ -56,7 +56,7 @@ describe('Next.js Styles', () => {
|
|||||||
const scAppWithAppRouter = uniq('app');
|
const scAppWithAppRouter = uniq('app');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/next:app ${scAppWithAppRouter} --no-interactive --style=styled-components --appDir=true`
|
`generate @nx/next:app ${scAppWithAppRouter} --no-interactive --style=styled-components --appDir=true --unitTestRunner=jest --linter=eslint`
|
||||||
);
|
);
|
||||||
|
|
||||||
await checkApp(scAppWithAppRouter, {
|
await checkApp(scAppWithAppRouter, {
|
||||||
@ -68,7 +68,7 @@ describe('Next.js Styles', () => {
|
|||||||
const emotionApp = uniq('app');
|
const emotionApp = uniq('app');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/next:app ${emotionApp} --no-interactive --style=@emotion/styled --appDir=false`
|
`generate @nx/next:app ${emotionApp} --no-interactive --style=@emotion/styled --appDir=false --unitTestRunner=jest --linter=eslint`
|
||||||
);
|
);
|
||||||
|
|
||||||
await checkApp(emotionApp, {
|
await checkApp(emotionApp, {
|
||||||
@ -83,7 +83,7 @@ describe('Next.js Styles', () => {
|
|||||||
const tailwindApp = uniq('app');
|
const tailwindApp = uniq('app');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/next:app ${tailwindApp} --no-interactive --style=tailwind --appDir=false --src=false`
|
`generate @nx/next:app ${tailwindApp} --no-interactive --style=tailwind --appDir=false --src=false --unitTestRunner=jest --linter=eslint`
|
||||||
);
|
);
|
||||||
|
|
||||||
await checkApp(tailwindApp, {
|
await checkApp(tailwindApp, {
|
||||||
@ -107,7 +107,7 @@ describe('Next.js Styles', () => {
|
|||||||
const tailwindApp = uniq('app');
|
const tailwindApp = uniq('app');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/next:app ${tailwindApp} --no-interactive --style=tailwind --appDir=true --src=false`
|
`generate @nx/next:app ${tailwindApp} --no-interactive --style=tailwind --appDir=true --src=false --unitTestRunner=jest --linter=eslint`
|
||||||
);
|
);
|
||||||
|
|
||||||
await checkApp(tailwindApp, {
|
await checkApp(tailwindApp, {
|
||||||
|
|||||||
@ -37,7 +37,9 @@ describe('Next.js Applications', () => {
|
|||||||
const appName = uniq('app1');
|
const appName = uniq('app1');
|
||||||
const libName = uniq('@my-org/lib1');
|
const libName = uniq('@my-org/lib1');
|
||||||
|
|
||||||
runCLI(`generate @nx/next:app ${appName} --no-interactive`);
|
runCLI(
|
||||||
|
`generate @nx/next:app ${appName} --no-interactive --linter=eslint --unitTestRunner=jest`
|
||||||
|
);
|
||||||
|
|
||||||
// check files are generated without the layout directory ("apps/") and
|
// check files are generated without the layout directory ("apps/") and
|
||||||
// using the project name as the directory when no directory is provided
|
// using the project name as the directory when no directory is provided
|
||||||
@ -52,7 +54,9 @@ describe('Next.js Applications', () => {
|
|||||||
`Successfully ran target test for project ${appName}`
|
`Successfully ran target test for project ${appName}`
|
||||||
);
|
);
|
||||||
|
|
||||||
runCLI(`generate @nx/next:lib ${libName} --buildable --no-interactive`);
|
runCLI(
|
||||||
|
`generate @nx/next:lib ${libName} --buildable --no-interactive --linter=eslint --unitTestRunner=jest`
|
||||||
|
);
|
||||||
|
|
||||||
// check files are generated without the layout directory ("libs/") and
|
// check files are generated without the layout directory ("libs/") and
|
||||||
// using the project name as the directory when no directory is provided
|
// using the project name as the directory when no directory is provided
|
||||||
@ -67,7 +71,7 @@ describe('Next.js Applications', () => {
|
|||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/next:app ${appName} --no-interactive --style=css --appDir=false`
|
`generate @nx/next:app ${appName} --no-interactive --style=css --appDir=false --linter=eslint --unitTestRunner=jest`
|
||||||
);
|
);
|
||||||
|
|
||||||
checkFilesDoNotExist(`${appName}/.next/build-manifest.json`);
|
checkFilesDoNotExist(`${appName}/.next/build-manifest.json`);
|
||||||
@ -82,7 +86,7 @@ describe('Next.js Applications', () => {
|
|||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/next:app ${appName} --no-interactive --js --appDir=false --e2eTestRunner=playwright`
|
`generate @nx/next:app ${appName} --no-interactive --js --appDir=false --e2eTestRunner=playwright --linter=eslint --unitTestRunner=jest`
|
||||||
);
|
);
|
||||||
|
|
||||||
checkFilesExist(`${appName}/src/pages/index.js`);
|
checkFilesExist(`${appName}/src/pages/index.js`);
|
||||||
@ -97,7 +101,7 @@ describe('Next.js Applications', () => {
|
|||||||
const libName = uniq('lib');
|
const libName = uniq('lib');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/next:lib ${libName} --no-interactive --style=none --js`
|
`generate @nx/next:lib ${libName} --no-interactive --style=none --js --linter=eslint --unitTestRunner=jest`
|
||||||
);
|
);
|
||||||
|
|
||||||
const mainPath = `${appName}/src/pages/index.js`;
|
const mainPath = `${appName}/src/pages/index.js`;
|
||||||
@ -133,7 +137,9 @@ describe('Next.js Applications', () => {
|
|||||||
it('should support --no-swc flag', async () => {
|
it('should support --no-swc flag', async () => {
|
||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
|
|
||||||
runCLI(`generate @nx/next:app ${appName} --no-interactive --no-swc`);
|
runCLI(
|
||||||
|
`generate @nx/next:app ${appName} --no-interactive --no-swc --linter=eslint --unitTestRunner=jest`
|
||||||
|
);
|
||||||
|
|
||||||
// Next.js enables SWC when custom .babelrc is not provided.
|
// Next.js enables SWC when custom .babelrc is not provided.
|
||||||
checkFilesExist(`${appName}/.babelrc`);
|
checkFilesExist(`${appName}/.babelrc`);
|
||||||
@ -148,7 +154,9 @@ describe('Next.js Applications', () => {
|
|||||||
it('should support --custom-server flag (swc)', async () => {
|
it('should support --custom-server flag (swc)', async () => {
|
||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
|
|
||||||
runCLI(`generate @nx/next:app ${appName} --no-interactive --custom-server`);
|
runCLI(
|
||||||
|
`generate @nx/next:app ${appName} --no-interactive --custom-server --linter=eslint --unitTestRunner=jest`
|
||||||
|
);
|
||||||
|
|
||||||
checkFilesExist(`${appName}/server/main.ts`);
|
checkFilesExist(`${appName}/server/main.ts`);
|
||||||
|
|
||||||
@ -165,7 +173,7 @@ describe('Next.js Applications', () => {
|
|||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/next:app ${appName} --swc=false --no-interactive --custom-server`
|
`generate @nx/next:app ${appName} --swc=false --no-interactive --custom-server --linter=eslint --unitTestRunner=jest`
|
||||||
);
|
);
|
||||||
|
|
||||||
checkFilesExist(`${appName}/server/main.ts`);
|
checkFilesExist(`${appName}/server/main.ts`);
|
||||||
@ -182,7 +190,9 @@ describe('Next.js Applications', () => {
|
|||||||
it('should run e2e-ci test', async () => {
|
it('should run e2e-ci test', async () => {
|
||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
|
|
||||||
runCLI(`generate @nx/next:app ${appName} --no-interactive --style=css`);
|
runCLI(
|
||||||
|
`generate @nx/next:app ${appName} --no-interactive --style=css --linter=eslint --unitTestRunner=jest`
|
||||||
|
);
|
||||||
|
|
||||||
if (runE2ETests('playwright')) {
|
if (runE2ETests('playwright')) {
|
||||||
const e2eResults = runCLI(`e2e-ci ${appName}-e2e --verbose`, {
|
const e2eResults = runCLI(`e2e-ci ${appName}-e2e --verbose`, {
|
||||||
@ -202,9 +212,11 @@ describe('Next.js Applications', () => {
|
|||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
const pagesAppName = uniq('pages-app');
|
const pagesAppName = uniq('pages-app');
|
||||||
|
|
||||||
runCLI(`generate @nx/next:app ${appName} --style=css --no-interactive`);
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/next:app ${pagesAppName} --appDir=false --style=css --no-interactive`
|
`generate @nx/next:app ${appName} --style=css --no-interactive --linter=eslint --unitTestRunner=jest`
|
||||||
|
);
|
||||||
|
runCLI(
|
||||||
|
`generate @nx/next:app ${pagesAppName} --appDir=false --style=css --no-interactive --linter=eslint --unitTestRunner=jest`
|
||||||
);
|
);
|
||||||
|
|
||||||
const appDirNextEnv = `${appName}/next-env.d.ts`;
|
const appDirNextEnv = `${appName}/next-env.d.ts`;
|
||||||
|
|||||||
@ -19,7 +19,7 @@ describe('@nx/workspace:convert-to-monorepo', () => {
|
|||||||
it('should convert a standalone webpack and jest react project to a monorepo (legacy)', async () => {
|
it('should convert a standalone webpack and jest react project to a monorepo (legacy)', async () => {
|
||||||
const reactApp = uniq('reactapp');
|
const reactApp = uniq('reactapp');
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:app --name=${reactApp} --directory="." --bundler=webpack --unitTestRunner=jest --e2eTestRunner=cypress --no-interactive`,
|
`generate @nx/react:app --name=${reactApp} --directory="." --bundler=webpack --unitTestRunner=jest --e2eTestRunner=cypress --no-interactive --linter=eslint`,
|
||||||
{
|
{
|
||||||
env: {
|
env: {
|
||||||
NX_ADD_PLUGINS: 'false',
|
NX_ADD_PLUGINS: 'false',
|
||||||
|
|||||||
@ -32,7 +32,7 @@ describe('@nx/workspace:infer-targets', () => {
|
|||||||
// default case, everything is generated with crystal, everything should be skipped
|
// default case, everything is generated with crystal, everything should be skipped
|
||||||
const remixApp = uniq('remix');
|
const remixApp = uniq('remix');
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/remix:app apps/${remixApp} --unitTestRunner jest --e2eTestRunner=playwright --no-interactive`
|
`generate @nx/remix:app apps/${remixApp} --linter eslint --unitTestRunner jest --e2eTestRunner=playwright --no-interactive`
|
||||||
);
|
);
|
||||||
|
|
||||||
const output = runCLI(`generate infer-targets --no-interactive --verbose`);
|
const output = runCLI(`generate infer-targets --no-interactive --verbose`);
|
||||||
@ -70,7 +70,7 @@ describe('@nx/workspace:infer-targets', () => {
|
|||||||
// default case, everything is generated with crystal, relevant plugins should be skipped
|
// default case, everything is generated with crystal, relevant plugins should be skipped
|
||||||
const remixApp = uniq('remix');
|
const remixApp = uniq('remix');
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/remix:app apps/${remixApp} --unitTestRunner jest --e2eTestRunner=playwright --no-interactive`
|
`generate @nx/remix:app apps/${remixApp} --linter eslint --unitTestRunner jest --e2eTestRunner=playwright --no-interactive`
|
||||||
);
|
);
|
||||||
|
|
||||||
const output = runCLI(
|
const output = runCLI(
|
||||||
@ -116,7 +116,7 @@ describe('@nx/workspace:infer-targets', () => {
|
|||||||
// even if we make sure there are executors for remix & remix-e2e, only remix conversions will run with --project option
|
// even if we make sure there are executors for remix & remix-e2e, only remix conversions will run with --project option
|
||||||
const remixApp = uniq('remix');
|
const remixApp = uniq('remix');
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/remix:app apps/${remixApp} --unitTestRunner jest --e2eTestRunner=playwright --no-interactive`
|
`generate @nx/remix:app apps/${remixApp} --linter eslint --unitTestRunner jest --e2eTestRunner=playwright --no-interactive`
|
||||||
);
|
);
|
||||||
|
|
||||||
updateJson('nx.json', (json) => {
|
updateJson('nx.json', (json) => {
|
||||||
@ -167,7 +167,7 @@ describe('@nx/workspace:convert-to-monorepo', () => {
|
|||||||
it('should be convert a standalone vite and playwright react project to a monorepo', async () => {
|
it('should be convert a standalone vite and playwright react project to a monorepo', async () => {
|
||||||
const reactApp = uniq('reactapp');
|
const reactApp = uniq('reactapp');
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:app --name=${reactApp} --directory="." --rootProject=true --bundler=vite --unitTestRunner vitest --e2eTestRunner=playwright --no-interactive`
|
`generate @nx/react:app --name=${reactApp} --directory="." --rootProject=true --linter eslint --bundler=vite --unitTestRunner vitest --e2eTestRunner=playwright --no-interactive`
|
||||||
);
|
);
|
||||||
|
|
||||||
runCLI('generate @nx/workspace:convert-to-monorepo --no-interactive');
|
runCLI('generate @nx/workspace:convert-to-monorepo --no-interactive');
|
||||||
|
|||||||
@ -39,10 +39,10 @@ describe('@nx/react-native (legacy)', () => {
|
|||||||
return nxJson;
|
return nxJson;
|
||||||
});
|
});
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react-native:application ${appName} --directory=apps/${appName} --bunlder=webpack --e2eTestRunner=cypress --install=false --no-interactive`
|
`generate @nx/react-native:application ${appName} --directory=apps/${appName} --bundler=webpack --e2eTestRunner=cypress --install=false --no-interactive --unitTestRunner=jest --linter=eslint`
|
||||||
);
|
);
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react-native:library ${libName} --directory=libs/${libName} --buildable --publishable --importPath=${proj}/${libName} --no-interactive`
|
`generate @nx/react-native:library ${libName} --directory=libs/${libName} --buildable --publishable --importPath=${proj}/${libName} --no-interactive --unitTestRunner=jest --linter=eslint`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
@ -265,7 +265,7 @@ describe('@nx/react-native (legacy)', () => {
|
|||||||
const libName = uniq('@my-org/lib1');
|
const libName = uniq('@my-org/lib1');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react-native:application ${appName} --install=false --no-interactive`
|
`generate @nx/react-native:application ${appName} --install=false --no-interactive --unitTestRunner=jest --linter=eslint`
|
||||||
);
|
);
|
||||||
|
|
||||||
// check files are generated without the layout directory ("apps/") and
|
// check files are generated without the layout directory ("apps/") and
|
||||||
@ -274,7 +274,9 @@ describe('@nx/react-native (legacy)', () => {
|
|||||||
// check tests pass
|
// check tests pass
|
||||||
expect(() => runCLI(`test ${appName}`)).not.toThrow();
|
expect(() => runCLI(`test ${appName}`)).not.toThrow();
|
||||||
|
|
||||||
runCLI(`generate @nx/react-native:library ${libName} --buildable`);
|
runCLI(
|
||||||
|
`generate @nx/react-native:library ${libName} --buildable --unitTestRunner=jest --linter=eslint`
|
||||||
|
);
|
||||||
|
|
||||||
// check files are generated without the layout directory ("libs/") and
|
// check files are generated without the layout directory ("libs/") and
|
||||||
// using the project name as the directory when no directory is provided
|
// using the project name as the directory when no directory is provided
|
||||||
@ -286,7 +288,7 @@ describe('@nx/react-native (legacy)', () => {
|
|||||||
it('should run build with vite bundler and e2e with playwright', async () => {
|
it('should run build with vite bundler and e2e with playwright', async () => {
|
||||||
const appName2 = uniq('my-app');
|
const appName2 = uniq('my-app');
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react-native:application ${appName2} --directory=apps/${appName2} --bundler=vite --e2eTestRunner=playwright --install=false --no-interactive`
|
`generate @nx/react-native:application ${appName2} --directory=apps/${appName2} --bundler=vite --e2eTestRunner=playwright --install=false --no-interactive --unitTestRunner=jest --linter=eslint`
|
||||||
);
|
);
|
||||||
expect(() => runCLI(`build ${appName2}`)).not.toThrow();
|
expect(() => runCLI(`build ${appName2}`)).not.toThrow();
|
||||||
if (runE2ETests()) {
|
if (runE2ETests()) {
|
||||||
|
|||||||
@ -18,7 +18,7 @@ describe('@nx/react-native', () => {
|
|||||||
newProject();
|
newProject();
|
||||||
appName = uniq('app');
|
appName = uniq('app');
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react-native:app ${appName} --install=false --no-interactive`
|
`generate @nx/react-native:app ${appName} --install=false --no-interactive --unitTestRunner=jest --linter=eslint`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ describe('@nx/react-native', () => {
|
|||||||
it('should run build with vite bundler and e2e with playwright', async () => {
|
it('should run build with vite bundler and e2e with playwright', async () => {
|
||||||
const appName2 = uniq('my-app');
|
const appName2 = uniq('my-app');
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react-native:application ${appName2} --directory=apps/${appName2} --bundler=vite --e2eTestRunner=playwright --install=false --no-interactive`
|
`generate @nx/react-native:application ${appName2} --directory=apps/${appName2} --bundler=vite --e2eTestRunner=playwright --install=false --no-interactive --unitTestRunner=jest --linter=eslint`
|
||||||
);
|
);
|
||||||
expect(() => runCLI(`build ${appName2}`)).not.toThrow();
|
expect(() => runCLI(`build ${appName2}`)).not.toThrow();
|
||||||
if (runE2ETests()) {
|
if (runE2ETests()) {
|
||||||
|
|||||||
@ -22,7 +22,7 @@ describe('Build React applications and libraries with Vite', () => {
|
|||||||
const viteApp = uniq('viteapp');
|
const viteApp = uniq('viteapp');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:app apps/${viteApp} --bundler=vite --compiler=babel --unitTestRunner=vitest --no-interactive`
|
`generate @nx/react:app apps/${viteApp} --bundler=vite --compiler=babel --unitTestRunner=vitest --no-interactive --linter=eslint`
|
||||||
);
|
);
|
||||||
|
|
||||||
const appTestResults = await runCLIAsync(`test ${viteApp}`);
|
const appTestResults = await runCLIAsync(`test ${viteApp}`);
|
||||||
@ -43,7 +43,7 @@ describe('Build React applications and libraries with Vite', () => {
|
|||||||
const viteApp = uniq('viteapp');
|
const viteApp = uniq('viteapp');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:app apps/${viteApp} --bundler=vite --compiler=swc --unitTestRunner=vitest --no-interactive`
|
`generate @nx/react:app apps/${viteApp} --bundler=vite --compiler=swc --unitTestRunner=vitest --no-interactive --linter=eslint`
|
||||||
);
|
);
|
||||||
|
|
||||||
const appTestResults = await runCLIAsync(`test ${viteApp}`);
|
const appTestResults = await runCLIAsync(`test ${viteApp}`);
|
||||||
@ -65,7 +65,7 @@ describe('Build React applications and libraries with Vite', () => {
|
|||||||
const viteLib = uniq('vitelib');
|
const viteLib = uniq('vitelib');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:app apps/${viteApp} --bundler=vite --unitTestRunner=vitest --inSourceTests --no-interactive`
|
`generate @nx/react:app apps/${viteApp} --bundler=vite --unitTestRunner=vitest --inSourceTests --no-interactive --linter=eslint`
|
||||||
);
|
);
|
||||||
expect(() => {
|
expect(() => {
|
||||||
checkFilesExist(`apps/${viteApp}/src/app/app.spec.tsx`);
|
checkFilesExist(`apps/${viteApp}/src/app/app.spec.tsx`);
|
||||||
@ -85,7 +85,7 @@ describe('Build React applications and libraries with Vite', () => {
|
|||||||
checkFilesExist(`dist/apps/${viteApp}/index.html`);
|
checkFilesExist(`dist/apps/${viteApp}/index.html`);
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:lib libs/${viteLib} --bundler=vite --inSourceTests --unitTestRunner=vitest --no-interactive`
|
`generate @nx/react:lib libs/${viteLib} --bundler=vite --inSourceTests --unitTestRunner=vitest --no-interactive --linter=eslint`
|
||||||
);
|
);
|
||||||
expect(() => {
|
expect(() => {
|
||||||
checkFilesExist(`libs/${viteLib}/src/lib/${viteLib}.spec.tsx`);
|
checkFilesExist(`libs/${viteLib}/src/lib/${viteLib}.spec.tsx`);
|
||||||
@ -125,7 +125,7 @@ describe('Build React applications and libraries with Vite', () => {
|
|||||||
const viteLib = uniq('vitelib');
|
const viteLib = uniq('vitelib');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:lib libs/${viteLib} --bundler=vite --no-interactive --unit-test-runner=none`
|
`generate @nx/react:lib libs/${viteLib} --bundler=vite --no-interactive --unit-test-runner=none --linter=eslint`
|
||||||
);
|
);
|
||||||
|
|
||||||
await runCLIAsync(`build ${viteLib}`);
|
await runCLIAsync(`build ${viteLib}`);
|
||||||
@ -139,7 +139,7 @@ describe('Build React applications and libraries with Vite', () => {
|
|||||||
// Convert non-buildable lib to buildable one
|
// Convert non-buildable lib to buildable one
|
||||||
const nonBuildableLib = uniq('nonbuildablelib');
|
const nonBuildableLib = uniq('nonbuildablelib');
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:lib libs/${nonBuildableLib} --no-interactive --unitTestRunner=jest`
|
`generate @nx/react:lib libs/${nonBuildableLib} --no-interactive --unitTestRunner=jest --linter=eslint`
|
||||||
);
|
);
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/vite:configuration ${nonBuildableLib} --uiFramework=react --no-interactive`
|
`generate @nx/vite:configuration ${nonBuildableLib} --uiFramework=react --no-interactive`
|
||||||
@ -157,7 +157,7 @@ describe('Build React applications and libraries with Vite', () => {
|
|||||||
const viteApp = uniq('viteapp');
|
const viteApp = uniq('viteapp');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:app apps/${viteApp} --bundler=vite --unitTestRunner=jest --no-interactive`
|
`generate @nx/react:app apps/${viteApp} --bundler=vite --unitTestRunner=jest --no-interactive --linter=eslint`
|
||||||
);
|
);
|
||||||
|
|
||||||
const appTestResults = await runCLIAsync(`test ${viteApp}`);
|
const appTestResults = await runCLIAsync(`test ${viteApp}`);
|
||||||
|
|||||||
@ -34,10 +34,10 @@ describe('React Applications', () => {
|
|||||||
const libName = uniq('lib');
|
const libName = uniq('lib');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:app apps/${appName} --name=${appName} --bundler=vite --no-interactive --skipFormat`
|
`generate @nx/react:app apps/${appName} --name=${appName} --bundler=vite --no-interactive --skipFormat --linter=eslint --unitTestRunner=vitest`
|
||||||
);
|
);
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:lib libs/${libName} --bundler=none --no-interactive --unit-test-runner=vitest --skipFormat`
|
`generate @nx/react:lib libs/${libName} --bundler=none --no-interactive --unit-test-runner=vitest --skipFormat --linter=eslint`
|
||||||
);
|
);
|
||||||
|
|
||||||
// Library generated with Vite
|
// Library generated with Vite
|
||||||
@ -68,10 +68,10 @@ describe('React Applications', () => {
|
|||||||
const libName = uniq('lib');
|
const libName = uniq('lib');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:app ${appName} --bundler=rspack --unit-test-runner=vitest --no-interactive --skipFormat`
|
`generate @nx/react:app ${appName} --bundler=rspack --unit-test-runner=vitest --no-interactive --skipFormat --linter=eslint`
|
||||||
);
|
);
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:lib ${libName} --bundler=none --no-interactive --unit-test-runner=vitest --skipFormat`
|
`generate @nx/react:lib ${libName} --bundler=none --no-interactive --unit-test-runner=vitest --skipFormat --linter=eslint`
|
||||||
);
|
);
|
||||||
|
|
||||||
// Library generated with Vite
|
// Library generated with Vite
|
||||||
@ -109,13 +109,13 @@ describe('React Applications', () => {
|
|||||||
const redSvg = `<?xml version="1.0"?><svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny" viewBox="0 0 30 30"><rect x="10" y="10" width="10" height="10" fill="red"/></svg>`;
|
const redSvg = `<?xml version="1.0"?><svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny" viewBox="0 0 30 30"><rect x="10" y="10" width="10" height="10" fill="red"/></svg>`;
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:app apps/${appName} --style=css --bundler=webpack --unit-test-runner=jest --no-interactive --skipFormat`
|
`generate @nx/react:app apps/${appName} --style=css --bundler=webpack --unit-test-runner=jest --no-interactive --skipFormat --linter=eslint`
|
||||||
);
|
);
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:lib libs/${libName} --style=css --no-interactive --unit-test-runner=jest --skipFormat`
|
`generate @nx/react:lib libs/${libName} --style=css --no-interactive --unit-test-runner=jest --skipFormat --linter=eslint`
|
||||||
);
|
);
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:lib libs/${libWithNoComponents} --no-interactive --no-component --unit-test-runner=jest --skipFormat`
|
`generate @nx/react:lib libs/${libWithNoComponents} --no-interactive --no-component --unit-test-runner=jest --skipFormat --linter=eslint`
|
||||||
);
|
);
|
||||||
|
|
||||||
// Libs should not include package.json by default
|
// Libs should not include package.json by default
|
||||||
@ -201,7 +201,7 @@ describe('React Applications', () => {
|
|||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:app apps/${appName} --routing --bundler=webpack --no-interactive --skipFormat`
|
`generate @nx/react:app apps/${appName} --routing --bundler=webpack --no-interactive --skipFormat --linter=eslint --unitTestRunner=jest`
|
||||||
);
|
);
|
||||||
|
|
||||||
runCLI(`build ${appName}`);
|
runCLI(`build ${appName}`);
|
||||||
@ -218,7 +218,7 @@ describe('React Applications', () => {
|
|||||||
const libName = uniq('lib');
|
const libName = uniq('lib');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`g @nx/react:app apps/${appName} --bundler=webpack --no-interactive --skipFormat`
|
`g @nx/react:app apps/${appName} --bundler=webpack --no-interactive --skipFormat --unitTestRunner=jest --linter=eslint`
|
||||||
);
|
);
|
||||||
runCLI(
|
runCLI(
|
||||||
`g @nx/react:redux apps/${appName}/src/app/lemon/lemon --skipFormat`
|
`g @nx/react:redux apps/${appName}/src/app/lemon/lemon --skipFormat`
|
||||||
@ -254,7 +254,7 @@ describe('React Applications', () => {
|
|||||||
const libName = uniq('@my-org/lib1');
|
const libName = uniq('@my-org/lib1');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:app ${appName} --bundler=webpack --no-interactive --skipFormat`
|
`generate @nx/react:app ${appName} --bundler=webpack --no-interactive --skipFormat --linter=eslint --unitTestRunner=jest`
|
||||||
);
|
);
|
||||||
|
|
||||||
// check files are generated without the layout directory ("apps/") and
|
// check files are generated without the layout directory ("apps/") and
|
||||||
@ -271,7 +271,7 @@ describe('React Applications', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:lib ${libName} --unit-test-runner=jest --buildable --no-interactive --skipFormat`
|
`generate @nx/react:lib ${libName} --unit-test-runner=jest --buildable --no-interactive --skipFormat --linter=eslint`
|
||||||
);
|
);
|
||||||
|
|
||||||
// check files are generated without the layout directory ("libs/") and
|
// check files are generated without the layout directory ("libs/") and
|
||||||
@ -293,7 +293,7 @@ describe('React Applications', () => {
|
|||||||
xit('should support styled-jsx', async () => {
|
xit('should support styled-jsx', async () => {
|
||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:app ${appName} --style=styled-jsx --bundler=vite --no-interactive --skipFormat`
|
`generate @nx/react:app ${appName} --style=styled-jsx --bundler=vite --no-interactive --skipFormat --linter=eslint --unitTestRunner=vitest`
|
||||||
);
|
);
|
||||||
|
|
||||||
// update app to use styled-jsx
|
// update app to use styled-jsx
|
||||||
@ -342,7 +342,7 @@ describe('React Applications', () => {
|
|||||||
it('should support tailwind', async () => {
|
it('should support tailwind', async () => {
|
||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:app apps/${appName} --style=tailwind --bundler=vite --no-interactive --skipFormat`
|
`generate @nx/react:app apps/${appName} --style=tailwind --bundler=vite --no-interactive --skipFormat --linter=eslint --unitTestRunner=vitest`
|
||||||
);
|
);
|
||||||
|
|
||||||
// update app to use styled-jsx
|
// update app to use styled-jsx
|
||||||
@ -386,7 +386,7 @@ describe('React Applications', () => {
|
|||||||
it('should be formatted on freshly created apps', async () => {
|
it('should be formatted on freshly created apps', async () => {
|
||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:app ${appName} --bundler=webpack --no-interactive`
|
`generate @nx/react:app ${appName} --bundler=webpack --no-interactive --linter=eslint --unitTestRunner=jest`
|
||||||
);
|
);
|
||||||
|
|
||||||
const stdout = runCLI(`format:check --projects=${appName}`, {
|
const stdout = runCLI(`format:check --projects=${appName}`, {
|
||||||
@ -416,15 +416,15 @@ describe('React Applications', () => {
|
|||||||
const plainJsLib = uniq('jslib');
|
const plainJsLib = uniq('jslib');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:app apps/${appName} --bundler=webpack --unit-test-runner=jest --no-interactive --js --skipFormat`
|
`generate @nx/react:app apps/${appName} --bundler=webpack --unit-test-runner=jest --no-interactive --js --skipFormat --linter=eslint`
|
||||||
);
|
);
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:lib libs/${libName} --no-interactive --js --unit-test-runner=none --skipFormat`
|
`generate @nx/react:lib libs/${libName} --no-interactive --js --unit-test-runner=none --skipFormat --linter=eslint`
|
||||||
);
|
);
|
||||||
// Make sure plain JS libs can be imported as well.
|
// Make sure plain JS libs can be imported as well.
|
||||||
// There was an issue previously: https://github.com/nrwl/nx/issues/10990
|
// There was an issue previously: https://github.com/nrwl/nx/issues/10990
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/js:lib libs/${plainJsLib} --js --unit-test-runner=none --bundler=none --compiler=tsc --no-interactive --skipFormat`
|
`generate @nx/js:lib libs/${plainJsLib} --js --unit-test-runner=none --bundler=none --compiler=tsc --no-interactive --skipFormat --linter=eslint`
|
||||||
);
|
);
|
||||||
|
|
||||||
const mainPath = `apps/${appName}/src/main.js`;
|
const mainPath = `apps/${appName}/src/main.js`;
|
||||||
@ -450,7 +450,7 @@ describe('React Applications', () => {
|
|||||||
`('should support global and css modules', async ({ style }) => {
|
`('should support global and css modules', async ({ style }) => {
|
||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:app apps/${appName} --style=${style} --bundler=webpack --no-interactive --skipFormat`
|
`generate @nx/react:app apps/${appName} --style=${style} --bundler=webpack --no-interactive --skipFormat --linter=eslint --unitTestRunner=jest`
|
||||||
);
|
);
|
||||||
|
|
||||||
// make sure stylePreprocessorOptions works
|
// make sure stylePreprocessorOptions works
|
||||||
|
|||||||
@ -26,7 +26,9 @@ describe('Remix E2E Tests', () => {
|
|||||||
|
|
||||||
it('should not cause peer dependency conflicts', async () => {
|
it('should not cause peer dependency conflicts', async () => {
|
||||||
const plugin = uniq('remix');
|
const plugin = uniq('remix');
|
||||||
runCLI(`generate @nx/remix:app ${plugin}`);
|
runCLI(
|
||||||
|
`generate @nx/remix:app ${plugin} --linter=eslint --unitTestRunner=vitest`
|
||||||
|
);
|
||||||
|
|
||||||
await runCommandAsync('npm install');
|
await runCommandAsync('npm install');
|
||||||
}, 120000);
|
}, 120000);
|
||||||
@ -43,7 +45,9 @@ describe('Remix E2E Tests', () => {
|
|||||||
|
|
||||||
it('should create app', async () => {
|
it('should create app', async () => {
|
||||||
const plugin = uniq('remix');
|
const plugin = uniq('remix');
|
||||||
runCLI(`generate @nx/remix:app ${plugin}`);
|
runCLI(
|
||||||
|
`generate @nx/remix:app ${plugin} --linter=eslint --unitTestRunner=vitest`
|
||||||
|
);
|
||||||
|
|
||||||
const buildResult = runCLI(`build ${plugin}`);
|
const buildResult = runCLI(`build ${plugin}`);
|
||||||
expect(buildResult).toContain('Successfully ran target build');
|
expect(buildResult).toContain('Successfully ran target build');
|
||||||
@ -56,7 +60,7 @@ describe('Remix E2E Tests', () => {
|
|||||||
it('should create src in the specified directory', async () => {
|
it('should create src in the specified directory', async () => {
|
||||||
const plugin = uniq('remix');
|
const plugin = uniq('remix');
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/remix:app --name=${plugin} --directory=subdir --rootProject=false --no-interactive`
|
`generate @nx/remix:app --name=${plugin} --directory=subdir --rootProject=false --no-interactive --linter=eslint --unitTestRunner=vitest`
|
||||||
);
|
);
|
||||||
|
|
||||||
const result = runCLI(`build ${plugin}`);
|
const result = runCLI(`build ${plugin}`);
|
||||||
@ -69,7 +73,7 @@ describe('Remix E2E Tests', () => {
|
|||||||
it('should add tags to the project', async () => {
|
it('should add tags to the project', async () => {
|
||||||
const plugin = uniq('remix');
|
const plugin = uniq('remix');
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/remix:app apps/${plugin} --tags e2etag,e2ePackage`
|
`generate @nx/remix:app apps/${plugin} --tags e2etag,e2ePackage --linter=eslint --unitTestRunner=vitest`
|
||||||
);
|
);
|
||||||
const project = readJson(`apps/${plugin}/project.json`);
|
const project = readJson(`apps/${plugin}/project.json`);
|
||||||
expect(project.tags).toEqual(['e2etag', 'e2ePackage']);
|
expect(project.tags).toEqual(['e2etag', 'e2ePackage']);
|
||||||
@ -79,7 +83,9 @@ describe('Remix E2E Tests', () => {
|
|||||||
describe('--js', () => {
|
describe('--js', () => {
|
||||||
it('should create js app and build correctly', async () => {
|
it('should create js app and build correctly', async () => {
|
||||||
const plugin = uniq('remix');
|
const plugin = uniq('remix');
|
||||||
runCLI(`generate @nx/remix:app ${plugin} --js=true`);
|
runCLI(
|
||||||
|
`generate @nx/remix:app ${plugin} --js=true --linter=eslint --unitTestRunner=vitest`
|
||||||
|
);
|
||||||
|
|
||||||
const result = runCLI(`build ${plugin}`);
|
const result = runCLI(`build ${plugin}`);
|
||||||
expect(result).toContain('Successfully ran target build');
|
expect(result).toContain('Successfully ran target build');
|
||||||
@ -89,7 +95,9 @@ describe('Remix E2E Tests', () => {
|
|||||||
describe('--unitTestRunner', () => {
|
describe('--unitTestRunner', () => {
|
||||||
it('should generate a library with vitest and test correctly', async () => {
|
it('should generate a library with vitest and test correctly', async () => {
|
||||||
const plugin = uniq('remix');
|
const plugin = uniq('remix');
|
||||||
runCLI(`generate @nx/remix:library ${plugin} --unitTestRunner=vitest`);
|
runCLI(
|
||||||
|
`generate @nx/remix:library ${plugin} --unitTestRunner=vitest --linter=eslint`
|
||||||
|
);
|
||||||
|
|
||||||
const result = runCLI(`test ${plugin}`);
|
const result = runCLI(`test ${plugin}`);
|
||||||
expect(result).toContain(`Successfully ran target test`);
|
expect(result).toContain(`Successfully ran target test`);
|
||||||
@ -98,11 +106,11 @@ describe('Remix E2E Tests', () => {
|
|||||||
it('should generate a library with jest and test correctly', async () => {
|
it('should generate a library with jest and test correctly', async () => {
|
||||||
const reactapp = uniq('react');
|
const reactapp = uniq('react');
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:application ${reactapp} --unitTestRunner=jest`
|
`generate @nx/react:application ${reactapp} --unitTestRunner=jest --linter=eslint`
|
||||||
);
|
);
|
||||||
const plugin = uniq('remix');
|
const plugin = uniq('remix');
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/remix:application ${plugin} --unitTestRunner=jest`
|
`generate @nx/remix:application ${plugin} --unitTestRunner=jest --linter=eslint`
|
||||||
);
|
);
|
||||||
|
|
||||||
const result = runCLI(`test ${plugin}`);
|
const result = runCLI(`test ${plugin}`);
|
||||||
@ -118,7 +126,7 @@ describe('Remix E2E Tests', () => {
|
|||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/remix:app apps/${plugin} --tags e2etag,e2ePackage`
|
`generate @nx/remix:app apps/${plugin} --tags e2etag,e2ePackage --linter=eslint --unitTestRunner=vitest`
|
||||||
);
|
);
|
||||||
}, 120000);
|
}, 120000);
|
||||||
|
|
||||||
|
|||||||
@ -67,9 +67,9 @@ describe('rspack e2e', () => {
|
|||||||
// Make sure expected files are present.
|
// Make sure expected files are present.
|
||||||
/**
|
/**
|
||||||
* The files that are generated are:
|
* The files that are generated are:
|
||||||
* ["3rdpartylicenses.txt", "assets", "favicon.ico", "index.html", "main.bf7851e6.js", "runtime.e4294127.js"]
|
* ["assets", "favicon.ico", "index.html", "main.bf7851e6.js", "runtime.e4294127.js"]
|
||||||
*/
|
*/
|
||||||
expect(listFiles(`dist/${project}`)).toHaveLength(6);
|
expect(listFiles(`dist/${project}`)).toHaveLength(5);
|
||||||
|
|
||||||
result = runCLI(`test ${project}`);
|
result = runCLI(`test ${project}`);
|
||||||
expect(result).toContain('Successfully ran target test');
|
expect(result).toContain('Successfully ran target test');
|
||||||
@ -87,7 +87,7 @@ describe('rspack e2e', () => {
|
|||||||
env: { NODE_ENV: 'production' },
|
env: { NODE_ENV: 'production' },
|
||||||
});
|
});
|
||||||
expect(result).toContain('Successfully ran target build');
|
expect(result).toContain('Successfully ran target build');
|
||||||
expect(listFiles(`dist/${project}`)).toHaveLength(6); // same length as before
|
expect(listFiles(`dist/${project}`)).toHaveLength(5); // same length as before
|
||||||
|
|
||||||
// Generate a new app and check that the files are correct
|
// Generate a new app and check that the files are correct
|
||||||
const app2 = uniq('app2');
|
const app2 = uniq('app2');
|
||||||
@ -120,7 +120,7 @@ describe('rspack e2e', () => {
|
|||||||
});
|
});
|
||||||
expect(result).toContain('Successfully ran target build');
|
expect(result).toContain('Successfully ran target build');
|
||||||
// Make sure expected files are present.
|
// Make sure expected files are present.
|
||||||
expect(listFiles(`dist/${app2}`)).toHaveLength(6);
|
expect(listFiles(`dist/${app2}`)).toHaveLength(5);
|
||||||
|
|
||||||
result = runCLI(`test ${app2}`);
|
result = runCLI(`test ${app2}`);
|
||||||
expect(result).toContain('Successfully ran target test');
|
expect(result).toContain('Successfully ran target test');
|
||||||
@ -139,11 +139,11 @@ describe('rspack e2e', () => {
|
|||||||
result = runCLI(`build ${app3}`);
|
result = runCLI(`build ${app3}`);
|
||||||
expect(result).toContain('Successfully ran target build');
|
expect(result).toContain('Successfully ran target build');
|
||||||
// Make sure expected files are present.
|
// Make sure expected files are present.
|
||||||
expect(listFiles(`dist/${app3}`)).toHaveLength(3);
|
expect(listFiles(`dist/${app3}`)).toHaveLength(2);
|
||||||
|
|
||||||
result = runCLI(`build ${app3} --generatePackageJson=true`);
|
result = runCLI(`build ${app3} --generatePackageJson=true`);
|
||||||
expect(result).toContain('Successfully ran target build');
|
expect(result).toContain('Successfully ran target build');
|
||||||
// Make sure expected files are present.
|
// Make sure expected files are present.
|
||||||
expect(listFiles(`dist/${app3}`)).toHaveLength(5);
|
expect(listFiles(`dist/${app3}`)).toHaveLength(4);
|
||||||
}, 200_000);
|
}, 200_000);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -222,6 +222,8 @@ export function runCreateWorkspace(
|
|||||||
docker,
|
docker,
|
||||||
nextAppDir,
|
nextAppDir,
|
||||||
nextSrcDir,
|
nextSrcDir,
|
||||||
|
linter = 'eslint',
|
||||||
|
formatter = 'prettier',
|
||||||
e2eTestRunner,
|
e2eTestRunner,
|
||||||
ssr,
|
ssr,
|
||||||
framework,
|
framework,
|
||||||
@ -241,7 +243,9 @@ export function runCreateWorkspace(
|
|||||||
docker?: boolean;
|
docker?: boolean;
|
||||||
nextAppDir?: boolean;
|
nextAppDir?: boolean;
|
||||||
nextSrcDir?: boolean;
|
nextSrcDir?: boolean;
|
||||||
|
linter?: 'none' | 'eslint';
|
||||||
e2eTestRunner?: 'cypress' | 'playwright' | 'jest' | 'detox' | 'none';
|
e2eTestRunner?: 'cypress' | 'playwright' | 'jest' | 'detox' | 'none';
|
||||||
|
formatter?: 'prettier' | 'none';
|
||||||
ssr?: boolean;
|
ssr?: boolean;
|
||||||
framework?: string;
|
framework?: string;
|
||||||
prefix?: string;
|
prefix?: string;
|
||||||
@ -291,6 +295,14 @@ export function runCreateWorkspace(
|
|||||||
command += ` --package-manager=${packageManager}`;
|
command += ` --package-manager=${packageManager}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (linter) {
|
||||||
|
command += ` --linter=${linter}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (formatter) {
|
||||||
|
command += ` --formatter=${formatter}`;
|
||||||
|
}
|
||||||
|
|
||||||
if (e2eTestRunner) {
|
if (e2eTestRunner) {
|
||||||
command += ` --e2eTestRunner=${e2eTestRunner}`;
|
command += ` --e2eTestRunner=${e2eTestRunner}`;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,7 +48,9 @@ describe('Vite Plugin', () => {
|
|||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
myApp = uniq('my-app');
|
myApp = uniq('my-app');
|
||||||
runCLI(`generate @nx/react:app ${myApp} --bundler=vite`);
|
runCLI(
|
||||||
|
`generate @nx/react:app ${myApp} --bundler=vite --unitTestRunner=vitest`
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@ -95,7 +97,7 @@ describe('Vite Plugin', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
myApp = uniq('my-app');
|
myApp = uniq('my-app');
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/web:app ${myApp} --bundler=vite --directory=${myApp}`
|
`generate @nx/web:app ${myApp} --bundler=vite --unitTestRunner=vitest --directory=${myApp}`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('should build application', async () => {
|
it('should build application', async () => {
|
||||||
@ -187,7 +189,7 @@ describe('Vite Plugin', () => {
|
|||||||
packages: ['@nx/react'],
|
packages: ['@nx/react'],
|
||||||
});
|
});
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:app ${app} --bundler=vite --no-interactive --directory=${app}`
|
`generate @nx/react:app ${app} --bundler=vite --unitTestRunner=vitest --no-interactive --directory=${app}`
|
||||||
);
|
);
|
||||||
|
|
||||||
// only this project will be directly used from dist
|
// only this project will be directly used from dist
|
||||||
|
|||||||
@ -24,10 +24,10 @@ describe('Webpack Plugin (legacy)', () => {
|
|||||||
packages: ['@nx/react'],
|
packages: ['@nx/react'],
|
||||||
});
|
});
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:app ${appName} --bundler webpack --e2eTestRunner=cypress --rootProject --no-interactive`
|
`generate @nx/react:app ${appName} --bundler webpack --e2eTestRunner=cypress --rootProject --no-interactive --unitTestRunner=jest --linter=eslint`
|
||||||
);
|
);
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:lib ${libName} --unitTestRunner jest --no-interactive`
|
`generate @nx/react:lib ${libName} --unitTestRunner jest --no-interactive --linter=eslint`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -72,7 +72,9 @@ describe('Webpack Plugin (legacy)', () => {
|
|||||||
// Issue: https://github.com/nrwl/nx/issues/20179
|
// Issue: https://github.com/nrwl/nx/issues/20179
|
||||||
it('should allow main/styles entries to be spread within composePlugins() function (#20179)', () => {
|
it('should allow main/styles entries to be spread within composePlugins() function (#20179)', () => {
|
||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
runCLI(`generate @nx/web:app ${appName} --bundler webpack`);
|
runCLI(
|
||||||
|
`generate @nx/web:app ${appName} --bundler webpack --unitTestRunner=jest --linter=eslint`
|
||||||
|
);
|
||||||
|
|
||||||
checkFilesExist(`${appName}/src/main.ts`);
|
checkFilesExist(`${appName}/src/main.ts`);
|
||||||
updateFile(`${appName}/src/main.ts`, `console.log('Hello');\n`);
|
updateFile(`${appName}/src/main.ts`, `console.log('Hello');\n`);
|
||||||
@ -109,7 +111,7 @@ describe('Webpack Plugin (legacy)', () => {
|
|||||||
it('should support standard webpack config with executors', () => {
|
it('should support standard webpack config with executors', () => {
|
||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/web:app ${appName} --bundler webpack --e2eTestRunner=playwright`
|
`generate @nx/web:app ${appName} --bundler webpack --e2eTestRunner=playwright --unitTestRunner=jest --linter=eslint`
|
||||||
);
|
);
|
||||||
updateFile(
|
updateFile(
|
||||||
`${appName}/src/main.ts`,
|
`${appName}/src/main.ts`,
|
||||||
@ -153,7 +155,7 @@ describe('Webpack Plugin (legacy)', () => {
|
|||||||
it('should convert withNx webpack config to a standard config using NxWebpackPlugin', () => {
|
it('should convert withNx webpack config to a standard config using NxWebpackPlugin', () => {
|
||||||
const appName = 'app3224373'; // Needs to be reserved so that the snapshot projectName matches
|
const appName = 'app3224373'; // Needs to be reserved so that the snapshot projectName matches
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/web:app ${appName} --bundler webpack --e2eTestRunner=playwright`
|
`generate @nx/web:app ${appName} --bundler webpack --e2eTestRunner=playwright --unitTestRunner=vitest --linter=eslint`
|
||||||
);
|
);
|
||||||
updateFile(
|
updateFile(
|
||||||
`${appName}/src/main.ts`,
|
`${appName}/src/main.ts`,
|
||||||
|
|||||||
@ -52,6 +52,9 @@ interface ReactArguments extends BaseArguments {
|
|||||||
nextAppDir: boolean;
|
nextAppDir: boolean;
|
||||||
nextSrcDir: boolean;
|
nextSrcDir: boolean;
|
||||||
e2eTestRunner: 'none' | 'cypress' | 'playwright';
|
e2eTestRunner: 'none' | 'cypress' | 'playwright';
|
||||||
|
linter?: 'none' | 'eslint';
|
||||||
|
formatter?: 'none' | 'prettier';
|
||||||
|
workspaces?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AngularArguments extends BaseArguments {
|
interface AngularArguments extends BaseArguments {
|
||||||
@ -157,6 +160,15 @@ export const commandsObject: yargs.Argv<Arguments> = yargs
|
|||||||
describe: chalk.dim`Bundler to be used to build the app.`,
|
describe: chalk.dim`Bundler to be used to build the app.`,
|
||||||
type: 'string',
|
type: 'string',
|
||||||
})
|
})
|
||||||
|
.option('workspaces', {
|
||||||
|
describe: chalk.dim`Use package manager workspaces.`,
|
||||||
|
type: 'boolean',
|
||||||
|
default: false,
|
||||||
|
})
|
||||||
|
.option('formatter', {
|
||||||
|
describe: chalk.dim`Code formatter to use.`,
|
||||||
|
type: 'string',
|
||||||
|
})
|
||||||
.option('framework', {
|
.option('framework', {
|
||||||
describe: chalk.dim`Framework option to be used with certain stacks.`,
|
describe: chalk.dim`Framework option to be used with certain stacks.`,
|
||||||
type: 'string',
|
type: 'string',
|
||||||
@ -440,14 +452,11 @@ async function determinePresetOptions(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function determineNoneOptions(
|
async function determineFormatterOptions(args: {
|
||||||
parsedArgs: yargs.Arguments<NoneArguments>
|
formatter?: 'none' | 'prettier';
|
||||||
): Promise<Partial<NoneArguments>> {
|
interactive?: boolean;
|
||||||
if (
|
}) {
|
||||||
(!parsedArgs.preset || parsedArgs.preset === Preset.TS) &&
|
if (args.formatter) return args.formatter;
|
||||||
process.env.NX_ADD_PLUGINS !== 'false' &&
|
|
||||||
process.env.NX_ADD_TS_PLUGIN !== 'false'
|
|
||||||
) {
|
|
||||||
const reply = await enquirer.prompt<{ prettier: 'Yes' | 'No' }>([
|
const reply = await enquirer.prompt<{ prettier: 'Yes' | 'No' }>([
|
||||||
{
|
{
|
||||||
name: 'prettier',
|
name: 'prettier',
|
||||||
@ -462,12 +471,44 @@ async function determineNoneOptions(
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
initial: 1,
|
initial: 1,
|
||||||
skip: !parsedArgs.interactive || isCI(),
|
skip: !args.interactive || isCI(),
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
return reply.prettier === 'Yes' ? 'prettier' : 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
async function determineLinterOptions(args: { interactive?: boolean }) {
|
||||||
|
const reply = await enquirer.prompt<{ eslint: 'Yes' | 'No' }>([
|
||||||
|
{
|
||||||
|
name: 'eslint',
|
||||||
|
message: `Would you like to use ESLint?`,
|
||||||
|
type: 'autocomplete',
|
||||||
|
choices: [
|
||||||
|
{
|
||||||
|
name: 'Yes',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'No',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
initial: 1,
|
||||||
|
skip: !args.interactive || isCI(),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
return reply.eslint === 'Yes' ? 'eslint' : 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
async function determineNoneOptions(
|
||||||
|
parsedArgs: yargs.Arguments<NoneArguments>
|
||||||
|
): Promise<Partial<NoneArguments>> {
|
||||||
|
if (
|
||||||
|
(!parsedArgs.preset || parsedArgs.preset === Preset.TS) &&
|
||||||
|
process.env.NX_ADD_PLUGINS !== 'false' &&
|
||||||
|
process.env.NX_ADD_TS_PLUGIN !== 'false'
|
||||||
|
) {
|
||||||
return {
|
return {
|
||||||
preset: Preset.TS,
|
preset: Preset.TS,
|
||||||
formatter: reply.prettier === 'Yes' ? 'prettier' : 'none',
|
formatter: await determineFormatterOptions(parsedArgs),
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
let preset: Preset;
|
let preset: Preset;
|
||||||
@ -535,6 +576,10 @@ async function determineReactOptions(
|
|||||||
let e2eTestRunner: undefined | 'none' | 'cypress' | 'playwright' = undefined;
|
let e2eTestRunner: undefined | 'none' | 'cypress' | 'playwright' = undefined;
|
||||||
let nextAppDir = false;
|
let nextAppDir = false;
|
||||||
let nextSrcDir = false;
|
let nextSrcDir = false;
|
||||||
|
let linter: undefined | 'none' | 'eslint';
|
||||||
|
let formatter: undefined | 'none' | 'prettier';
|
||||||
|
|
||||||
|
const workspaces = parsedArgs.workspaces ?? false;
|
||||||
|
|
||||||
if (parsedArgs.preset && parsedArgs.preset !== Preset.React) {
|
if (parsedArgs.preset && parsedArgs.preset !== Preset.React) {
|
||||||
preset = parsedArgs.preset;
|
preset = parsedArgs.preset;
|
||||||
@ -550,27 +595,25 @@ async function determineReactOptions(
|
|||||||
} else {
|
} else {
|
||||||
const framework = await determineReactFramework(parsedArgs);
|
const framework = await determineReactFramework(parsedArgs);
|
||||||
|
|
||||||
// React Native and Expo only support integrated monorepos for now.
|
const isStandalone =
|
||||||
// TODO(jack): Add standalone support for React Native and Expo.
|
workspaces || framework === 'react-native' || framework === 'expo'
|
||||||
const workspaceType =
|
? false
|
||||||
framework === 'react-native' || framework === 'expo'
|
: (await determineStandaloneOrMonorepo()) === 'standalone';
|
||||||
? 'integrated'
|
|
||||||
: await determineStandaloneOrMonorepo();
|
|
||||||
|
|
||||||
if (workspaceType === 'standalone') {
|
if (isStandalone) {
|
||||||
appName = parsedArgs.name;
|
appName = parsedArgs.name;
|
||||||
} else {
|
} else {
|
||||||
appName = await determineAppName(parsedArgs);
|
appName = await determineAppName(parsedArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (framework === 'nextjs') {
|
if (framework === 'nextjs') {
|
||||||
if (workspaceType === 'standalone') {
|
if (isStandalone) {
|
||||||
preset = Preset.NextJsStandalone;
|
preset = Preset.NextJsStandalone;
|
||||||
} else {
|
} else {
|
||||||
preset = Preset.NextJs;
|
preset = Preset.NextJs;
|
||||||
}
|
}
|
||||||
} else if (framework === 'remix') {
|
} else if (framework === 'remix') {
|
||||||
if (workspaceType === 'standalone') {
|
if (isStandalone) {
|
||||||
preset = Preset.RemixStandalone;
|
preset = Preset.RemixStandalone;
|
||||||
} else {
|
} else {
|
||||||
preset = Preset.RemixMonorepo;
|
preset = Preset.RemixMonorepo;
|
||||||
@ -580,7 +623,7 @@ async function determineReactOptions(
|
|||||||
} else if (framework === 'expo') {
|
} else if (framework === 'expo') {
|
||||||
preset = Preset.Expo;
|
preset = Preset.Expo;
|
||||||
} else {
|
} else {
|
||||||
if (workspaceType === 'standalone') {
|
if (isStandalone) {
|
||||||
preset = Preset.ReactStandalone;
|
preset = Preset.ReactStandalone;
|
||||||
} else {
|
} else {
|
||||||
preset = Preset.ReactMonorepo;
|
preset = Preset.ReactMonorepo;
|
||||||
@ -657,6 +700,14 @@ async function determineReactOptions(
|
|||||||
style = reply.style;
|
style = reply.style;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (workspaces) {
|
||||||
|
linter = await determineLinterOptions(parsedArgs);
|
||||||
|
formatter = await determineFormatterOptions(parsedArgs);
|
||||||
|
} else {
|
||||||
|
linter = 'eslint';
|
||||||
|
formatter = 'prettier';
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
preset,
|
preset,
|
||||||
style,
|
style,
|
||||||
@ -665,6 +716,9 @@ async function determineReactOptions(
|
|||||||
nextAppDir,
|
nextAppDir,
|
||||||
nextSrcDir,
|
nextSrcDir,
|
||||||
e2eTestRunner,
|
e2eTestRunner,
|
||||||
|
linter,
|
||||||
|
formatter,
|
||||||
|
workspaces,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import { setupCI } from './utils/ci/setup-ci';
|
|||||||
import { initializeGitRepo } from './utils/git/git';
|
import { initializeGitRepo } from './utils/git/git';
|
||||||
import { getPackageNameFromThirdPartyPreset } from './utils/preset/get-third-party-preset';
|
import { getPackageNameFromThirdPartyPreset } from './utils/preset/get-third-party-preset';
|
||||||
import { mapErrorToBodyLines } from './utils/error-utils';
|
import { mapErrorToBodyLines } from './utils/error-utils';
|
||||||
|
import { Preset } from './utils/preset/preset';
|
||||||
|
|
||||||
export async function createWorkspace<T extends CreateWorkspaceOptions>(
|
export async function createWorkspace<T extends CreateWorkspaceOptions>(
|
||||||
preset: string,
|
preset: string,
|
||||||
@ -30,12 +31,14 @@ export async function createWorkspace<T extends CreateWorkspaceOptions>(
|
|||||||
|
|
||||||
const tmpDir = await createSandbox(packageManager);
|
const tmpDir = await createSandbox(packageManager);
|
||||||
|
|
||||||
|
const workspaceGlobs = getWorkspaceGlobsFromPreset(preset);
|
||||||
|
|
||||||
// nx new requires a preset currently. We should probably make it optional.
|
// nx new requires a preset currently. We should probably make it optional.
|
||||||
const directory = await createEmptyWorkspace<T>(
|
const directory = await createEmptyWorkspace<T>(
|
||||||
tmpDir,
|
tmpDir,
|
||||||
name,
|
name,
|
||||||
packageManager,
|
packageManager,
|
||||||
{ ...options, preset }
|
{ ...options, preset, workspaceGlobs }
|
||||||
);
|
);
|
||||||
|
|
||||||
// If the preset is a third-party preset, we need to call createPreset to install it
|
// If the preset is a third-party preset, we need to call createPreset to install it
|
||||||
@ -96,3 +99,24 @@ export function extractConnectUrl(text: string): string | null {
|
|||||||
const match = text.match(urlPattern);
|
const match = text.match(urlPattern);
|
||||||
return match ? match[0] : null;
|
return match ? match[0] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getWorkspaceGlobsFromPreset(preset: string): string[] {
|
||||||
|
// Should match how apps are created in `packages/workspace/src/generators/preset/preset.ts`.
|
||||||
|
switch (preset) {
|
||||||
|
case Preset.AngularMonorepo:
|
||||||
|
case Preset.Expo:
|
||||||
|
case Preset.Express:
|
||||||
|
case Preset.Nest:
|
||||||
|
case Preset.NextJs:
|
||||||
|
case Preset.NodeMonorepo:
|
||||||
|
case Preset.Nuxt:
|
||||||
|
case Preset.ReactNative:
|
||||||
|
case Preset.ReactMonorepo:
|
||||||
|
case Preset.RemixMonorepo:
|
||||||
|
case Preset.VueMonorepo:
|
||||||
|
case Preset.WebComponents:
|
||||||
|
return ['apps/**', 'packages/**'];
|
||||||
|
default:
|
||||||
|
return ['packages/**'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -16,5 +16,6 @@
|
|||||||
"<%= offsetFromProjectRoot %>**/*.cy.js",
|
"<%= offsetFromProjectRoot %>**/*.cy.js",
|
||||||
<%_ if (jsx) { _%>"<%= offsetFromProjectRoot %>**/*.cy.jsx",<%_ } _%>
|
<%_ if (jsx) { _%>"<%= offsetFromProjectRoot %>**/*.cy.jsx",<%_ } _%>
|
||||||
"<%= offsetFromProjectRoot %>**/*.d.ts"
|
"<%= offsetFromProjectRoot %>**/*.d.ts"
|
||||||
]
|
],
|
||||||
|
"exclude": ["dist"<% if (linter === 'eslint') { %>, "eslint.config.js"<% } %>]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -105,6 +105,26 @@ export async function configurationGeneratorInternal(
|
|||||||
addTarget(tree, opts, projectGraph);
|
addTarget(tree, opts, projectGraph);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const projectTsConfigPath = joinPathFragments(
|
||||||
|
opts.projectRoot,
|
||||||
|
'tsconfig.json'
|
||||||
|
);
|
||||||
|
if (tree.exists(projectTsConfigPath)) {
|
||||||
|
updateJson(tree, projectTsConfigPath, (json) => {
|
||||||
|
// Cypress uses commonjs, unless the project is also using commonjs (or does not set "module" i.e. uses default of commonjs),
|
||||||
|
// then we need to set the moduleResolution to node10 or else Cypress will fail with TS5095 error.
|
||||||
|
// See: https://github.com/cypress-io/cypress/issues/27731
|
||||||
|
if (
|
||||||
|
(json.compilerOptions?.module ||
|
||||||
|
json.compilerOptions?.module !== 'commonjs') &&
|
||||||
|
json.compilerOptions?.moduleResolution
|
||||||
|
) {
|
||||||
|
json.compilerOptions.moduleResolution = 'node10';
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const { root: projectRoot } = readProjectConfiguration(tree, options.project);
|
const { root: projectRoot } = readProjectConfiguration(tree, options.project);
|
||||||
const isTsSolutionSetup = isUsingTsSolutionSetup(tree);
|
const isTsSolutionSetup = isUsingTsSolutionSetup(tree);
|
||||||
if (isTsSolutionSetup) {
|
if (isTsSolutionSetup) {
|
||||||
@ -201,6 +221,7 @@ In this case you need to provide a devServerTarget,'<projectName>:<targetName>[:
|
|||||||
return {
|
return {
|
||||||
...options,
|
...options,
|
||||||
bundler: options.bundler ?? 'webpack',
|
bundler: options.bundler ?? 'webpack',
|
||||||
|
projectRoot: projectConfig.root,
|
||||||
rootProject: options.rootProject ?? projectConfig.root === '.',
|
rootProject: options.rootProject ?? projectConfig.root === '.',
|
||||||
linter,
|
linter,
|
||||||
devServerTarget,
|
devServerTarget,
|
||||||
@ -408,6 +429,9 @@ function createPackageJson(tree: Tree, options: NormalizedSchema) {
|
|||||||
name: importPath,
|
name: importPath,
|
||||||
version: '0.0.1',
|
version: '0.0.1',
|
||||||
private: true,
|
private: true,
|
||||||
|
nx: {
|
||||||
|
name: options.project,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
writeJson(tree, packageJsonPath, packageJson);
|
writeJson(tree, packageJsonPath, packageJson);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { formatFiles, runTasksInSerial, Tree } from '@nx/devkit';
|
import { formatFiles, runTasksInSerial, Tree } from '@nx/devkit';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
import { initGenerator as jsInitGenerator } from '@nx/js';
|
||||||
|
|
||||||
import detoxInitGenerator from '../init/init';
|
import detoxInitGenerator from '../init/init';
|
||||||
import { addGitIgnoreEntry } from './lib/add-git-ignore-entry';
|
import { addGitIgnoreEntry } from './lib/add-git-ignore-entry';
|
||||||
@ -21,7 +21,9 @@ export async function detoxApplicationGeneratorInternal(
|
|||||||
host: Tree,
|
host: Tree,
|
||||||
schema: Schema
|
schema: Schema
|
||||||
) {
|
) {
|
||||||
assertNotUsingTsSolutionSetup(host, 'detox', 'application');
|
const jsInitTask = await jsInitGenerator(host, {
|
||||||
|
skipFormat: true,
|
||||||
|
});
|
||||||
|
|
||||||
const options = await normalizeOptions(host, schema);
|
const options = await normalizeOptions(host, schema);
|
||||||
|
|
||||||
@ -40,7 +42,7 @@ export async function detoxApplicationGeneratorInternal(
|
|||||||
await formatFiles(host);
|
await formatFiles(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
return runTasksInSerial(initTask, lintingTask, depsTask);
|
return runTasksInSerial(jsInitTask, initTask, lintingTask, depsTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default detoxApplicationGenerator;
|
export default detoxApplicationGenerator;
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import {
|
import {
|
||||||
addProjectConfiguration,
|
addProjectConfiguration,
|
||||||
|
joinPathFragments,
|
||||||
readNxJson,
|
readNxJson,
|
||||||
TargetConfiguration,
|
TargetConfiguration,
|
||||||
Tree,
|
Tree,
|
||||||
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import {
|
import {
|
||||||
expoBuildTarget,
|
expoBuildTarget,
|
||||||
@ -11,6 +13,7 @@ import {
|
|||||||
reactNativeTestTarget,
|
reactNativeTestTarget,
|
||||||
} from './get-targets';
|
} from './get-targets';
|
||||||
import { NormalizedSchema } from './normalize-options';
|
import { NormalizedSchema } from './normalize-options';
|
||||||
|
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
|
||||||
export function addProject(host: Tree, options: NormalizedSchema) {
|
export function addProject(host: Tree, options: NormalizedSchema) {
|
||||||
const nxJson = readNxJson(host);
|
const nxJson = readNxJson(host);
|
||||||
@ -20,6 +23,19 @@ export function addProject(host: Tree, options: NormalizedSchema) {
|
|||||||
: p.plugin === '@nx/detox/plugin'
|
: p.plugin === '@nx/detox/plugin'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (isUsingTsSolutionSetup(host)) {
|
||||||
|
writeJson(host, joinPathFragments(options.e2eProjectRoot, 'package.json'), {
|
||||||
|
name: options.e2eProjectName,
|
||||||
|
version: '0.0.1',
|
||||||
|
private: true,
|
||||||
|
nx: {
|
||||||
|
sourceRoot: `${options.e2eProjectRoot}/src`,
|
||||||
|
projectType: 'application',
|
||||||
|
targets: hasPlugin ? undefined : getTargets(options),
|
||||||
|
implicitDependencies: [options.appProject],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
addProjectConfiguration(host, options.e2eProjectName, {
|
addProjectConfiguration(host, options.e2eProjectName, {
|
||||||
root: options.e2eProjectRoot,
|
root: options.e2eProjectRoot,
|
||||||
sourceRoot: `${options.e2eProjectRoot}/src`,
|
sourceRoot: `${options.e2eProjectRoot}/src`,
|
||||||
@ -28,6 +44,7 @@ export function addProject(host: Tree, options: NormalizedSchema) {
|
|||||||
tags: [],
|
tags: [],
|
||||||
implicitDependencies: [options.appProject],
|
implicitDependencies: [options.appProject],
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTargets(options: NormalizedSchema) {
|
function getTargets(options: NormalizedSchema) {
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import {
|
|||||||
Tree,
|
Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { addPluginV1 } from '@nx/devkit/src/utils/add-plugin';
|
import { addPluginV1 } from '@nx/devkit/src/utils/add-plugin';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
|
||||||
import { createNodes } from '../../plugins/plugin';
|
import { createNodes } from '../../plugins/plugin';
|
||||||
import { detoxVersion, nxVersion } from '../../utils/versions';
|
import { detoxVersion, nxVersion } from '../../utils/versions';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
@ -19,8 +18,6 @@ export function detoxInitGenerator(host: Tree, schema: Schema) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function detoxInitGeneratorInternal(host: Tree, schema: Schema) {
|
export async function detoxInitGeneratorInternal(host: Tree, schema: Schema) {
|
||||||
assertNotUsingTsSolutionSetup(host, 'detox', 'init');
|
|
||||||
|
|
||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
|
|
||||||
const nxJson = readNxJson(host);
|
const nxJson = readNxJson(host);
|
||||||
|
|||||||
@ -90,6 +90,7 @@ export async function lintWorkspaceRulesProjectGenerator(
|
|||||||
join(workspaceLintPluginDir, 'tsconfig.spec.json'),
|
join(workspaceLintPluginDir, 'tsconfig.spec.json'),
|
||||||
(json) => {
|
(json) => {
|
||||||
delete json.compilerOptions?.module;
|
delete json.compilerOptions?.module;
|
||||||
|
delete json.compilerOptions?.moduleResolution;
|
||||||
|
|
||||||
if (json.include) {
|
if (json.include) {
|
||||||
json.include = json.include.map((v) => {
|
json.include = json.include.map((v) => {
|
||||||
|
|||||||
@ -6,6 +6,8 @@ import {
|
|||||||
readNxJson,
|
readNxJson,
|
||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
Tree,
|
Tree,
|
||||||
|
updateJson,
|
||||||
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||||
import { Linter } from '@nx/eslint';
|
import { Linter } from '@nx/eslint';
|
||||||
@ -327,4 +329,147 @@ describe('app', () => {
|
|||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('TS solution setup', () => {
|
||||||
|
it('should add project references when using TS solution', async () => {
|
||||||
|
const tree = createTreeWithEmptyWorkspace();
|
||||||
|
tree.write('.gitignore', '');
|
||||||
|
updateJson(tree, 'package.json', (json) => {
|
||||||
|
json.workspaces = ['packages/*', 'apps/*'];
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
writeJson(tree, 'tsconfig.base.json', {
|
||||||
|
compilerOptions: {
|
||||||
|
composite: true,
|
||||||
|
declaration: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
writeJson(tree, 'tsconfig.json', {
|
||||||
|
extends: './tsconfig.base.json',
|
||||||
|
files: [],
|
||||||
|
references: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
await expoApplicationGenerator(tree, {
|
||||||
|
directory: 'my-app',
|
||||||
|
displayName: 'myApp',
|
||||||
|
linter: Linter.EsLint,
|
||||||
|
e2eTestRunner: 'none',
|
||||||
|
skipFormat: false,
|
||||||
|
js: false,
|
||||||
|
unitTestRunner: 'jest',
|
||||||
|
addPlugin: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(readJson(tree, 'tsconfig.json').references).toMatchInlineSnapshot(`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"path": "./my-app",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'my-app/tsconfig.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"declaration": true,
|
||||||
|
"jsx": "react-native",
|
||||||
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"esnext",
|
||||||
|
],
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"strict": true,
|
||||||
|
},
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"files": [],
|
||||||
|
"include": [],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.app.json",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.spec.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'my-app/tsconfig.app.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"noUnusedLocals": false,
|
||||||
|
"outDir": "out-tsc/my-app",
|
||||||
|
"rootDir": "src",
|
||||||
|
"types": [
|
||||||
|
"node",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"dist",
|
||||||
|
"jest.config.ts",
|
||||||
|
"**/*.spec.ts",
|
||||||
|
"**/*.spec.tsx",
|
||||||
|
"src/test-setup.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"eslint.config.js",
|
||||||
|
"eslint.config.cjs",
|
||||||
|
"eslint.config.mjs",
|
||||||
|
],
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"files": [
|
||||||
|
"../node_modules/@nx/expo/typings/svg.d.ts",
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.tsx",
|
||||||
|
"**/*.js",
|
||||||
|
"**/*.jsx",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'my-app/tsconfig.spec.json'))
|
||||||
|
.toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"noUnusedLocals": false,
|
||||||
|
"outDir": "./out-tsc/jest",
|
||||||
|
"types": [
|
||||||
|
"jest",
|
||||||
|
"node",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"files": [
|
||||||
|
"src/test-setup.ts",
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"jest.config.ts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.test.tsx",
|
||||||
|
"src/**/*.spec.tsx",
|
||||||
|
"src/**/*.test.js",
|
||||||
|
"src/**/*.spec.js",
|
||||||
|
"src/**/*.test.jsx",
|
||||||
|
"src/**/*.spec.jsx",
|
||||||
|
"src/**/*.d.ts",
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.app.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import {
|
|||||||
Tree,
|
Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { initGenerator as jsInitGenerator } from '@nx/js';
|
import { initGenerator as jsInitGenerator } from '@nx/js';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
import { updateTsconfigFiles } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
|
||||||
import { addLinting } from '../../utils/add-linting';
|
import { addLinting } from '../../utils/add-linting';
|
||||||
import { addJest } from '../../utils/add-jest';
|
import { addJest } from '../../utils/add-jest';
|
||||||
@ -36,16 +36,16 @@ export async function expoApplicationGeneratorInternal(
|
|||||||
host: Tree,
|
host: Tree,
|
||||||
schema: Schema
|
schema: Schema
|
||||||
): Promise<GeneratorCallback> {
|
): Promise<GeneratorCallback> {
|
||||||
assertNotUsingTsSolutionSetup(host, 'expo', 'application');
|
|
||||||
|
|
||||||
const options = await normalizeOptions(host, schema);
|
|
||||||
|
|
||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
const jsInitTask = await jsInitGenerator(host, {
|
const jsInitTask = await jsInitGenerator(host, {
|
||||||
...schema,
|
...schema,
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
|
addTsPlugin: schema.useTsSolution,
|
||||||
|
formatter: schema.formatter,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const options = await normalizeOptions(host, schema);
|
||||||
|
|
||||||
tasks.push(jsInitTask);
|
tasks.push(jsInitTask);
|
||||||
const initTask = await initGenerator(host, { ...options, skipFormat: true });
|
const initTask = await initGenerator(host, { ...options, skipFormat: true });
|
||||||
tasks.push(initTask);
|
tasks.push(initTask);
|
||||||
@ -80,6 +80,21 @@ export async function expoApplicationGeneratorInternal(
|
|||||||
tasks.push(e2eTask);
|
tasks.push(e2eTask);
|
||||||
addEasScripts(host);
|
addEasScripts(host);
|
||||||
|
|
||||||
|
updateTsconfigFiles(
|
||||||
|
host,
|
||||||
|
options.appProjectRoot,
|
||||||
|
'tsconfig.app.json',
|
||||||
|
{
|
||||||
|
jsx: 'react-jsx',
|
||||||
|
module: 'esnext',
|
||||||
|
moduleResolution: 'bundler',
|
||||||
|
noUnusedLocals: false,
|
||||||
|
},
|
||||||
|
options.linter === 'eslint'
|
||||||
|
? ['eslint.config.js', 'eslint.config.cjs', 'eslint.config.mjs']
|
||||||
|
: undefined
|
||||||
|
);
|
||||||
|
|
||||||
if (!options.skipFormat) {
|
if (!options.skipFormat) {
|
||||||
await formatFiles(host);
|
await formatFiles(host);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
import { GeneratorCallback, Tree } from '@nx/devkit';
|
|
||||||
import {
|
import {
|
||||||
addProjectConfiguration,
|
addProjectConfiguration,
|
||||||
ensurePackage,
|
ensurePackage,
|
||||||
getPackageManagerCommand,
|
GeneratorCallback,
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
readNxJson,
|
readNxJson,
|
||||||
|
Tree,
|
||||||
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { webStaticServeGenerator } from '@nx/web';
|
import { webStaticServeGenerator } from '@nx/web';
|
||||||
|
|
||||||
@ -14,6 +15,7 @@ import { NormalizedSchema } from './normalize-options';
|
|||||||
import { addE2eCiTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
import { addE2eCiTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
||||||
import { findPluginForConfigFile } from '@nx/devkit/src/utils/find-plugin-for-config-file';
|
import { findPluginForConfigFile } from '@nx/devkit/src/utils/find-plugin-for-config-file';
|
||||||
import { getE2EWebServerInfo } from '@nx/devkit/src/generators/e2e-web-server-info-utils';
|
import { getE2EWebServerInfo } from '@nx/devkit/src/generators/e2e-web-server-info-utils';
|
||||||
|
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
|
||||||
export async function addE2e(
|
export async function addE2e(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
@ -40,6 +42,22 @@ export async function addE2e(
|
|||||||
typeof import('@nx/cypress')
|
typeof import('@nx/cypress')
|
||||||
>('@nx/cypress', nxVersion);
|
>('@nx/cypress', nxVersion);
|
||||||
|
|
||||||
|
if (isUsingTsSolutionSetup(tree)) {
|
||||||
|
writeJson(
|
||||||
|
tree,
|
||||||
|
joinPathFragments(options.e2eProjectRoot, 'package.json'),
|
||||||
|
{
|
||||||
|
name: options.e2eProjectName,
|
||||||
|
version: '0.0.1',
|
||||||
|
private: true,
|
||||||
|
nx: {
|
||||||
|
projectType: 'application',
|
||||||
|
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
||||||
|
implicitDependencies: [options.projectName],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
addProjectConfiguration(tree, options.e2eProjectName, {
|
addProjectConfiguration(tree, options.e2eProjectName, {
|
||||||
projectType: 'application',
|
projectType: 'application',
|
||||||
root: options.e2eProjectRoot,
|
root: options.e2eProjectRoot,
|
||||||
@ -48,6 +66,7 @@ export async function addE2e(
|
|||||||
implicitDependencies: [options.projectName],
|
implicitDependencies: [options.projectName],
|
||||||
tags: [],
|
tags: [],
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const e2eTask = await configurationGenerator(tree, {
|
const e2eTask = await configurationGenerator(tree, {
|
||||||
...options,
|
...options,
|
||||||
@ -106,6 +125,22 @@ export async function addE2e(
|
|||||||
const { configurationGenerator } = ensurePackage<
|
const { configurationGenerator } = ensurePackage<
|
||||||
typeof import('@nx/playwright')
|
typeof import('@nx/playwright')
|
||||||
>('@nx/playwright', nxVersion);
|
>('@nx/playwright', nxVersion);
|
||||||
|
if (isUsingTsSolutionSetup(tree)) {
|
||||||
|
writeJson(
|
||||||
|
tree,
|
||||||
|
joinPathFragments(options.e2eProjectRoot, 'package.json'),
|
||||||
|
{
|
||||||
|
name: options.e2eProjectName,
|
||||||
|
version: '0.0.1',
|
||||||
|
private: true,
|
||||||
|
nx: {
|
||||||
|
projectType: 'application',
|
||||||
|
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
||||||
|
implicitDependencies: [options.projectName],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
addProjectConfiguration(tree, options.e2eProjectName, {
|
addProjectConfiguration(tree, options.e2eProjectName, {
|
||||||
projectType: 'application',
|
projectType: 'application',
|
||||||
root: options.e2eProjectRoot,
|
root: options.e2eProjectRoot,
|
||||||
@ -113,6 +148,7 @@ export async function addE2e(
|
|||||||
targets: {},
|
targets: {},
|
||||||
implicitDependencies: [options.projectName],
|
implicitDependencies: [options.projectName],
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const e2eTask = await configurationGenerator(tree, {
|
const e2eTask = await configurationGenerator(tree, {
|
||||||
project: options.e2eProjectName,
|
project: options.e2eProjectName,
|
||||||
|
|||||||
@ -1,14 +1,18 @@
|
|||||||
import {
|
import {
|
||||||
addProjectConfiguration,
|
addProjectConfiguration,
|
||||||
|
joinPathFragments,
|
||||||
ProjectConfiguration,
|
ProjectConfiguration,
|
||||||
readNxJson,
|
readNxJson,
|
||||||
TargetConfiguration,
|
TargetConfiguration,
|
||||||
Tree,
|
Tree,
|
||||||
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
|
|
||||||
import { hasExpoPlugin } from '../../../utils/has-expo-plugin';
|
import { hasExpoPlugin } from '../../../utils/has-expo-plugin';
|
||||||
import { NormalizedSchema } from './normalize-options';
|
import { NormalizedSchema } from './normalize-options';
|
||||||
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
||||||
|
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||||
|
|
||||||
export function addProject(host: Tree, options: NormalizedSchema) {
|
export function addProject(host: Tree, options: NormalizedSchema) {
|
||||||
const nxJson = readNxJson(host);
|
const nxJson = readNxJson(host);
|
||||||
@ -26,12 +30,28 @@ export function addProject(host: Tree, options: NormalizedSchema) {
|
|||||||
tags: options.parsedTags,
|
tags: options.parsedTags,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (isUsingTsSolutionSetup(host)) {
|
||||||
|
const packageName = getImportPath(host, options.name);
|
||||||
|
writeJson(host, joinPathFragments(options.appProjectRoot, 'package.json'), {
|
||||||
|
name: packageName,
|
||||||
|
version: '0.0.1',
|
||||||
|
private: true,
|
||||||
|
nx: {
|
||||||
|
name: packageName === options.name ? undefined : options.name,
|
||||||
|
projectType: 'application',
|
||||||
|
sourceRoot: `${options.appProjectRoot}/src`,
|
||||||
|
targets: hasPlugin ? undefined : getTargets(options),
|
||||||
|
tags: options.parsedTags?.length ? options.parsedTags : undefined,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
addProjectConfiguration(
|
addProjectConfiguration(
|
||||||
host,
|
host,
|
||||||
options.projectName,
|
options.projectName,
|
||||||
projectConfiguration,
|
projectConfiguration,
|
||||||
options.standaloneConfig
|
options.standaloneConfig
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTargets(options: NormalizedSchema) {
|
function getTargets(options: NormalizedSchema) {
|
||||||
|
|||||||
@ -15,6 +15,9 @@ export interface Schema {
|
|||||||
e2eTestRunner: 'cypress' | 'playwright' | 'detox' | 'none'; // default is none
|
e2eTestRunner: 'cypress' | 'playwright' | 'detox' | 'none'; // default is none
|
||||||
standaloneConfig?: boolean;
|
standaloneConfig?: boolean;
|
||||||
skipPackageJson?: boolean; // default is false
|
skipPackageJson?: boolean; // default is false
|
||||||
|
// Internal options
|
||||||
addPlugin?: boolean;
|
addPlugin?: boolean;
|
||||||
nxCloudToken?: string;
|
nxCloudToken?: string;
|
||||||
|
useTsSolution?: boolean;
|
||||||
|
formatter?: 'prettier' | 'none';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,13 +44,15 @@
|
|||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint", "none"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "none"],
|
||||||
"description": "Test runner to use for unit tests",
|
"description": "Test runner to use for unit tests",
|
||||||
"default": "jest"
|
"default": "none",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -71,7 +73,8 @@
|
|||||||
"description": "Adds the specified e2e test runner",
|
"description": "Adds the specified e2e test runner",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["playwright", "cypress", "detox", "none"],
|
"enum": ["playwright", "cypress", "detox", "none"],
|
||||||
"default": "none"
|
"default": "none",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"standaloneConfig": {
|
"standaloneConfig": {
|
||||||
"description": "Split the project configuration into `<projectRoot>/project.json` rather than including it inside `workspace.json`.",
|
"description": "Split the project configuration into `<projectRoot>/project.json` rather than including it inside `workspace.json`.",
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import {
|
|||||||
Tree,
|
Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { addPluginV1 } from '@nx/devkit/src/utils/add-plugin';
|
import { addPluginV1 } from '@nx/devkit/src/utils/add-plugin';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
|
||||||
import { createNodes } from '../../../plugins/plugin';
|
import { createNodes } from '../../../plugins/plugin';
|
||||||
import {
|
import {
|
||||||
expoCliVersion,
|
expoCliVersion,
|
||||||
@ -28,8 +27,6 @@ export function expoInitGenerator(tree: Tree, schema: Schema) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function expoInitGeneratorInternal(host: Tree, schema: Schema) {
|
export async function expoInitGeneratorInternal(host: Tree, schema: Schema) {
|
||||||
assertNotUsingTsSolutionSetup(host, 'expo', 'init');
|
|
||||||
|
|
||||||
const nxJson = readNxJson(host);
|
const nxJson = readNxJson(host);
|
||||||
const addPluginDefault =
|
const addPluginDefault =
|
||||||
process.env.NX_ADD_PLUGINS !== 'false' &&
|
process.env.NX_ADD_PLUGINS !== 'false' &&
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import {
|
|||||||
ensureProjectName,
|
ensureProjectName,
|
||||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||||
import { Schema } from '../schema';
|
import { Schema } from '../schema';
|
||||||
|
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
|
||||||
export interface NormalizedSchema extends Schema {
|
export interface NormalizedSchema extends Schema {
|
||||||
name: string;
|
name: string;
|
||||||
@ -12,6 +13,7 @@ export interface NormalizedSchema extends Schema {
|
|||||||
routePath: string;
|
routePath: string;
|
||||||
parsedTags: string[];
|
parsedTags: string[];
|
||||||
appMain: string;
|
appMain: string;
|
||||||
|
isUsingTsSolutionConfig: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function normalizeOptions(
|
export async function normalizeOptions(
|
||||||
@ -50,6 +52,7 @@ export async function normalizeOptions(
|
|||||||
parsedTags,
|
parsedTags,
|
||||||
importPath,
|
importPath,
|
||||||
appMain,
|
appMain,
|
||||||
|
isUsingTsSolutionConfig: isUsingTsSolutionSetup(host),
|
||||||
};
|
};
|
||||||
|
|
||||||
return normalized;
|
return normalized;
|
||||||
|
|||||||
@ -233,6 +233,8 @@ describe('lib', () => {
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "../dist/out-tsc",
|
"outDir": "../dist/out-tsc",
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
|
"moduleResolution": "node10",
|
||||||
|
"jsx": "react-jsx",
|
||||||
"types": ["jest", "node"]
|
"types": ["jest", "node"]
|
||||||
},
|
},
|
||||||
"files": ["src/test-setup.ts"],
|
"files": ["src/test-setup.ts"],
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import {
|
|||||||
formatFiles,
|
formatFiles,
|
||||||
generateFiles,
|
generateFiles,
|
||||||
GeneratorCallback,
|
GeneratorCallback,
|
||||||
|
installPackagesTask,
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
names,
|
names,
|
||||||
offsetFromRoot,
|
offsetFromRoot,
|
||||||
@ -13,6 +14,7 @@ import {
|
|||||||
Tree,
|
Tree,
|
||||||
updateJson,
|
updateJson,
|
||||||
updateProjectConfiguration,
|
updateProjectConfiguration,
|
||||||
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -20,7 +22,6 @@ import {
|
|||||||
getRelativePathToRootTsConfig,
|
getRelativePathToRootTsConfig,
|
||||||
initGenerator as jsInitGenerator,
|
initGenerator as jsInitGenerator,
|
||||||
} from '@nx/js';
|
} from '@nx/js';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
|
||||||
import init from '../init/init';
|
import init from '../init/init';
|
||||||
import { addLinting } from '../../utils/add-linting';
|
import { addLinting } from '../../utils/add-linting';
|
||||||
import { addJest } from '../../utils/add-jest';
|
import { addJest } from '../../utils/add-jest';
|
||||||
@ -35,6 +36,8 @@ import { ensureDependencies } from '../../utils/ensure-dependencies';
|
|||||||
import { initRootBabelConfig } from '../../utils/init-root-babel-config';
|
import { initRootBabelConfig } from '../../utils/init-root-babel-config';
|
||||||
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
||||||
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
|
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
|
||||||
|
import { updateTsconfigFiles } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||||
|
|
||||||
export async function expoLibraryGenerator(
|
export async function expoLibraryGenerator(
|
||||||
host: Tree,
|
host: Tree,
|
||||||
@ -50,7 +53,13 @@ export async function expoLibraryGeneratorInternal(
|
|||||||
host: Tree,
|
host: Tree,
|
||||||
schema: Schema
|
schema: Schema
|
||||||
): Promise<GeneratorCallback> {
|
): Promise<GeneratorCallback> {
|
||||||
assertNotUsingTsSolutionSetup(host, 'expo', 'library');
|
const tasks: GeneratorCallback[] = [];
|
||||||
|
|
||||||
|
const jsInitTask = await jsInitGenerator(host, {
|
||||||
|
...schema,
|
||||||
|
skipFormat: true,
|
||||||
|
});
|
||||||
|
tasks.push(jsInitTask);
|
||||||
|
|
||||||
const options = await normalizeOptions(host, schema);
|
const options = await normalizeOptions(host, schema);
|
||||||
if (options.publishable === true && !schema.importPath) {
|
if (options.publishable === true && !schema.importPath) {
|
||||||
@ -59,13 +68,6 @@ export async function expoLibraryGeneratorInternal(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const tasks: GeneratorCallback[] = [];
|
|
||||||
|
|
||||||
const jsInitTask = await jsInitGenerator(host, {
|
|
||||||
...schema,
|
|
||||||
skipFormat: true,
|
|
||||||
});
|
|
||||||
tasks.push(jsInitTask);
|
|
||||||
const initTask = await init(host, { ...options, skipFormat: true });
|
const initTask = await init(host, { ...options, skipFormat: true });
|
||||||
tasks.push(initTask);
|
tasks.push(initTask);
|
||||||
if (!options.skipPackageJson) {
|
if (!options.skipPackageJson) {
|
||||||
@ -114,10 +116,29 @@ export async function expoLibraryGeneratorInternal(
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateTsconfigFiles(
|
||||||
|
host,
|
||||||
|
options.projectRoot,
|
||||||
|
'tsconfig.lib.json',
|
||||||
|
{
|
||||||
|
jsx: 'react-jsx',
|
||||||
|
module: 'esnext',
|
||||||
|
moduleResolution: 'bundler',
|
||||||
|
},
|
||||||
|
options.linter === 'eslint'
|
||||||
|
? ['eslint.config.js', 'eslint.config.cjs', 'eslint.config.mjs']
|
||||||
|
: undefined
|
||||||
|
);
|
||||||
|
|
||||||
if (!options.skipFormat) {
|
if (!options.skipFormat) {
|
||||||
await formatFiles(host);
|
await formatFiles(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Always run install to link packages.
|
||||||
|
if (options.isUsingTsSolutionConfig) {
|
||||||
|
tasks.push(() => installPackagesTask(host));
|
||||||
|
}
|
||||||
|
|
||||||
tasks.push(() => {
|
tasks.push(() => {
|
||||||
logShowProjectCommand(options.name);
|
logShowProjectCommand(options.name);
|
||||||
});
|
});
|
||||||
@ -136,7 +157,29 @@ async function addProject(
|
|||||||
tags: options.parsedTags,
|
tags: options.parsedTags,
|
||||||
targets: {},
|
targets: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (options.isUsingTsSolutionConfig) {
|
||||||
|
const packageName = getImportPath(host, options.name);
|
||||||
|
const sourceEntry = !options.buildable
|
||||||
|
? options.js
|
||||||
|
? './src/index.js'
|
||||||
|
: './src/index.ts'
|
||||||
|
: undefined;
|
||||||
|
writeJson(host, joinPathFragments(options.projectRoot, 'package.json'), {
|
||||||
|
name: packageName,
|
||||||
|
version: '0.0.1',
|
||||||
|
main: sourceEntry,
|
||||||
|
types: sourceEntry,
|
||||||
|
nx: {
|
||||||
|
name: packageName === options.name ? undefined : options.name,
|
||||||
|
projectType: 'library',
|
||||||
|
sourceRoot: joinPathFragments(options.projectRoot, 'src'),
|
||||||
|
tags: options.parsedTags?.length ? options.parsedTags : undefined,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
addProjectConfiguration(host, options.name, project);
|
addProjectConfiguration(host, options.name, project);
|
||||||
|
}
|
||||||
|
|
||||||
if (!options.publishable && !options.buildable) {
|
if (!options.publishable && !options.buildable) {
|
||||||
return () => {};
|
return () => {};
|
||||||
|
|||||||
@ -29,13 +29,16 @@
|
|||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint", "none"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "none"],
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"default": "jest"
|
"default": "none",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -2,8 +2,9 @@
|
|||||||
"extends": "<%= extendedConfig %>",
|
"extends": "<%= extendedConfig %>",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "<%= outDir %>",<% if (module) { %>
|
"outDir": "<%= outDir %>",<% if (module) { %>
|
||||||
"module": "<%= module %>",<% } %>
|
"module": "<%= module %>",<% } if (module === 'commonjs') { %>
|
||||||
"types": ["jest", "node"]
|
"moduleResolution": "node10",<% } if (supportTsx) { %>
|
||||||
|
"jsx": "react-jsx",<% } %>"types": ["jest", "node"]
|
||||||
},<% if(setupFile !== 'none') { %>
|
},<% if(setupFile !== 'none') { %>
|
||||||
"files": ["src/test-setup.ts"],<% } %>
|
"files": ["src/test-setup.ts"],<% } %>
|
||||||
"include": [
|
"include": [
|
||||||
|
|||||||
@ -4,10 +4,10 @@ import {
|
|||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
Tree,
|
Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import type { JestPresetExtension } from '../../../utils/config/config-file';
|
import type { JestPresetExtension } from '../../../utils/config/config-file';
|
||||||
import { NormalizedJestProjectSchema } from '../schema';
|
import { NormalizedJestProjectSchema } from '../schema';
|
||||||
|
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
|
||||||
export function createFiles(
|
export function createFiles(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import {
|
|||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
Tree,
|
Tree,
|
||||||
updateJson,
|
updateJson,
|
||||||
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||||
import { libraryGenerator } from './library';
|
import { libraryGenerator } from './library';
|
||||||
@ -1611,4 +1612,64 @@ describe('lib', () => {
|
|||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('TS solution setup', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
tree = createTreeWithEmptyWorkspace();
|
||||||
|
updateJson(tree, 'package.json', (json) => {
|
||||||
|
json.workspaces = ['packages/*', 'apps/*'];
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
writeJson(tree, 'tsconfig.base.json', {
|
||||||
|
compilerOptions: {
|
||||||
|
composite: true,
|
||||||
|
declaration: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
writeJson(tree, 'tsconfig.json', {
|
||||||
|
extends: './tsconfig.base.json',
|
||||||
|
files: [],
|
||||||
|
references: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should map non-buildable libraries to source', async () => {
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
...defaultOptions,
|
||||||
|
directory: 'my-ts-lib',
|
||||||
|
bundler: 'none',
|
||||||
|
unitTestRunner: 'none',
|
||||||
|
linter: 'none',
|
||||||
|
});
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
...defaultOptions,
|
||||||
|
directory: 'my-js-lib',
|
||||||
|
js: true,
|
||||||
|
bundler: 'none',
|
||||||
|
unitTestRunner: 'none',
|
||||||
|
linter: 'none',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(readJson(tree, 'my-ts-lib/package.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"dependencies": {},
|
||||||
|
"main": "./src/index.ts",
|
||||||
|
"name": "@proj/my-ts-lib",
|
||||||
|
"private": true,
|
||||||
|
"types": "./src/index.ts",
|
||||||
|
"version": "0.0.1",
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'my-js-lib/package.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"dependencies": {},
|
||||||
|
"main": "./src/index.js",
|
||||||
|
"name": "@proj/my-js-lib",
|
||||||
|
"private": true,
|
||||||
|
"types": "./src/index.js",
|
||||||
|
"version": "0.0.1",
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
addDependenciesToPackageJson,
|
addDependenciesToPackageJson,
|
||||||
|
installPackagesTask,
|
||||||
addProjectConfiguration,
|
addProjectConfiguration,
|
||||||
ensurePackage,
|
ensurePackage,
|
||||||
formatFiles,
|
formatFiles,
|
||||||
@ -234,6 +235,11 @@ export async function libraryGeneratorInternal(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Always run install to link packages.
|
||||||
|
if (options.isUsingTsSolutionConfig) {
|
||||||
|
tasks.push(() => installPackagesTask(tree));
|
||||||
|
}
|
||||||
|
|
||||||
tasks.push(() => {
|
tasks.push(() => {
|
||||||
logShowProjectCommand(options.name);
|
logShowProjectCommand(options.name);
|
||||||
});
|
});
|
||||||
@ -1125,6 +1131,17 @@ function determineEntryFields(
|
|||||||
// Safest option is to not set a type field.
|
// Safest option is to not set a type field.
|
||||||
// Allow the user to decide which module format their library is using
|
// Allow the user to decide which module format their library is using
|
||||||
type: undefined,
|
type: undefined,
|
||||||
|
// For non-buildable libraries, point to source so we can still use them in apps via bundlers like Vite.
|
||||||
|
main: options.isUsingTsSolutionConfig
|
||||||
|
? options.js
|
||||||
|
? './src/index.js'
|
||||||
|
: './src/index.ts'
|
||||||
|
: undefined,
|
||||||
|
types: options.isUsingTsSolutionConfig
|
||||||
|
? options.js
|
||||||
|
? './src/index.js'
|
||||||
|
: './src/index.ts'
|
||||||
|
: undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -268,7 +268,7 @@ describe(`Plugin: ${PLUGIN_NAME}`, () => {
|
|||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not invoke tsc with `--emitDeclarationOnly` when `noEmit` is set in the tsconfig.json file', async () => {
|
it('should not invoke `tsc --build` when `noEmit` is set in the tsconfig.json file', async () => {
|
||||||
// set directly in tsconfig.json file
|
// set directly in tsconfig.json file
|
||||||
await applyFilesToTempFsAndContext(tempFs, context, {
|
await applyFilesToTempFsAndContext(tempFs, context, {
|
||||||
'libs/my-lib/tsconfig.json': JSON.stringify({
|
'libs/my-lib/tsconfig.json': JSON.stringify({
|
||||||
@ -285,7 +285,7 @@ describe(`Plugin: ${PLUGIN_NAME}`, () => {
|
|||||||
"targets": {
|
"targets": {
|
||||||
"typecheck": {
|
"typecheck": {
|
||||||
"cache": true,
|
"cache": true,
|
||||||
"command": "tsc --build --pretty --verbose",
|
"command": "echo "The 'typecheck' target is disabled because one or more project references set 'noEmit: true' in their tsconfig. Remove this property to resolve this issue."",
|
||||||
"dependsOn": [
|
"dependsOn": [
|
||||||
"^typecheck",
|
"^typecheck",
|
||||||
],
|
],
|
||||||
@ -345,7 +345,7 @@ describe(`Plugin: ${PLUGIN_NAME}`, () => {
|
|||||||
"targets": {
|
"targets": {
|
||||||
"typecheck": {
|
"typecheck": {
|
||||||
"cache": true,
|
"cache": true,
|
||||||
"command": "tsc --build --pretty --verbose",
|
"command": "echo "The 'typecheck' target is disabled because one or more project references set 'noEmit: true' in their tsconfig. Remove this property to resolve this issue."",
|
||||||
"dependsOn": [
|
"dependsOn": [
|
||||||
"^typecheck",
|
"^typecheck",
|
||||||
],
|
],
|
||||||
@ -387,7 +387,7 @@ describe(`Plugin: ${PLUGIN_NAME}`, () => {
|
|||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not invoke tsc with `--emitDeclarationOnly` when `noEmit` is set in any of the referenced tsconfig.json files', async () => {
|
it('should not invoke `tsc --build` when `noEmit` is set in any of the referenced tsconfig.json files', async () => {
|
||||||
await applyFilesToTempFsAndContext(tempFs, context, {
|
await applyFilesToTempFsAndContext(tempFs, context, {
|
||||||
'libs/my-lib/tsconfig.json': JSON.stringify({
|
'libs/my-lib/tsconfig.json': JSON.stringify({
|
||||||
files: [],
|
files: [],
|
||||||
@ -407,7 +407,7 @@ describe(`Plugin: ${PLUGIN_NAME}`, () => {
|
|||||||
"targets": {
|
"targets": {
|
||||||
"typecheck": {
|
"typecheck": {
|
||||||
"cache": true,
|
"cache": true,
|
||||||
"command": "tsc --build --pretty --verbose",
|
"command": "echo "The 'typecheck' target is disabled because one or more project references set 'noEmit: true' in their tsconfig. Remove this property to resolve this issue."",
|
||||||
"dependsOn": [
|
"dependsOn": [
|
||||||
"^typecheck",
|
"^typecheck",
|
||||||
],
|
],
|
||||||
|
|||||||
@ -168,12 +168,23 @@ async function createNodesInternal(
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Do not create project for Next.js projects since they are not compatible with
|
||||||
|
// project references and typecheck will fail.
|
||||||
|
if (
|
||||||
|
siblingFiles.includes('next.config.js') ||
|
||||||
|
siblingFiles.includes('next.config.cjs') ||
|
||||||
|
siblingFiles.includes('next.config.mjs') ||
|
||||||
|
siblingFiles.includes('next.config.ts')
|
||||||
|
) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The cache key is composed by:
|
* The cache key is composed by:
|
||||||
* - hashes of the content of the relevant files that can affect what's inferred by the plugin:
|
* - hashes of the content of the relevant files that can affect what's inferred by the plugin:
|
||||||
* - current config file
|
* - current config file
|
||||||
* - config files extended by the current config file (recursively up to the root config file)
|
* - config files extended by the current config file (recursively up to the root config file)
|
||||||
* - referenced config files that are internal to the owning Nx project of the current config file
|
* - referenced config files that are internal to the owning Nx project of the current config file, or is a shallow external reference of the owning Nx project
|
||||||
* - lock file
|
* - lock file
|
||||||
* - hash of the plugin options
|
* - hash of the plugin options
|
||||||
* - current config file path
|
* - current config file path
|
||||||
@ -185,11 +196,17 @@ async function createNodesInternal(
|
|||||||
context.workspaceRoot,
|
context.workspaceRoot,
|
||||||
projectRoot
|
projectRoot
|
||||||
);
|
);
|
||||||
|
const externalProjectReferences = resolveShallowExternalProjectReferences(
|
||||||
|
tsConfig,
|
||||||
|
context.workspaceRoot,
|
||||||
|
projectRoot
|
||||||
|
);
|
||||||
const nodeHash = hashArray([
|
const nodeHash = hashArray([
|
||||||
...[
|
...[
|
||||||
fullConfigPath,
|
fullConfigPath,
|
||||||
...extendedConfigFiles.files,
|
...extendedConfigFiles.files,
|
||||||
...Object.keys(internalReferencedFiles),
|
...Object.keys(internalReferencedFiles),
|
||||||
|
...Object.keys(externalProjectReferences),
|
||||||
join(context.workspaceRoot, lockFileName),
|
join(context.workspaceRoot, lockFileName),
|
||||||
].map(hashFile),
|
].map(hashFile),
|
||||||
hashObject(options),
|
hashObject(options),
|
||||||
@ -239,6 +256,11 @@ function buildTscTargets(
|
|||||||
context.workspaceRoot,
|
context.workspaceRoot,
|
||||||
projectRoot
|
projectRoot
|
||||||
);
|
);
|
||||||
|
const externalProjectReferences = resolveShallowExternalProjectReferences(
|
||||||
|
tsConfig,
|
||||||
|
context.workspaceRoot,
|
||||||
|
projectRoot
|
||||||
|
);
|
||||||
const targetName = options.typecheck.targetName;
|
const targetName = options.typecheck.targetName;
|
||||||
if (!targets[targetName]) {
|
if (!targets[targetName]) {
|
||||||
let command = `tsc --build --emitDeclarationOnly --pretty --verbose`;
|
let command = `tsc --build --emitDeclarationOnly --pretty --verbose`;
|
||||||
@ -246,11 +268,13 @@ function buildTscTargets(
|
|||||||
tsConfig.options.noEmit ||
|
tsConfig.options.noEmit ||
|
||||||
Object.values(internalProjectReferences).some(
|
Object.values(internalProjectReferences).some(
|
||||||
(ref) => ref.options.noEmit
|
(ref) => ref.options.noEmit
|
||||||
|
) ||
|
||||||
|
Object.values(externalProjectReferences).some(
|
||||||
|
(ref) => ref.options.noEmit
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
// `--emitDeclarationOnly` and `--noEmit` are mutually exclusive, so
|
// `tsc --build` does not work with `noEmit: true`
|
||||||
// we remove `--emitDeclarationOnly` if `--noEmit` is set.
|
command = `echo "The 'typecheck' target is disabled because one or more project references set 'noEmit: true' in their tsconfig. Remove this property to resolve this issue."`;
|
||||||
command = `tsc --build --pretty --verbose`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
targets[targetName] = {
|
targets[targetName] = {
|
||||||
@ -607,6 +631,48 @@ function resolveInternalProjectReferences(
|
|||||||
workspaceRoot: string,
|
workspaceRoot: string,
|
||||||
projectRoot: string,
|
projectRoot: string,
|
||||||
projectReferences: Record<string, ParsedCommandLine> = {}
|
projectReferences: Record<string, ParsedCommandLine> = {}
|
||||||
|
): Record<string, ParsedCommandLine> {
|
||||||
|
walkProjectReferences(
|
||||||
|
tsConfig,
|
||||||
|
workspaceRoot,
|
||||||
|
projectRoot,
|
||||||
|
(configPath, config) => {
|
||||||
|
if (isExternalProjectReference(configPath, workspaceRoot, projectRoot)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
projectReferences[configPath] = config;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return projectReferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveShallowExternalProjectReferences(
|
||||||
|
tsConfig: ParsedCommandLine,
|
||||||
|
workspaceRoot: string,
|
||||||
|
projectRoot: string,
|
||||||
|
projectReferences: Record<string, ParsedCommandLine> = {}
|
||||||
|
): Record<string, ParsedCommandLine> {
|
||||||
|
walkProjectReferences(
|
||||||
|
tsConfig,
|
||||||
|
workspaceRoot,
|
||||||
|
projectRoot,
|
||||||
|
(configPath, config) => {
|
||||||
|
if (isExternalProjectReference(configPath, workspaceRoot, projectRoot)) {
|
||||||
|
projectReferences[configPath] = config;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return projectReferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
function walkProjectReferences(
|
||||||
|
tsConfig: ParsedCommandLine,
|
||||||
|
workspaceRoot: string,
|
||||||
|
projectRoot: string,
|
||||||
|
visitor: (configPath: string, config: ParsedCommandLine) => void | false, // false stops recursion
|
||||||
|
projectReferences: Record<string, ParsedCommandLine> = {}
|
||||||
): Record<string, ParsedCommandLine> {
|
): Record<string, ParsedCommandLine> {
|
||||||
if (!tsConfig.projectReferences?.length) {
|
if (!tsConfig.projectReferences?.length) {
|
||||||
return projectReferences;
|
return projectReferences;
|
||||||
@ -624,22 +690,14 @@ function resolveInternalProjectReferences(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isExternalProjectReference(refConfigPath, workspaceRoot, projectRoot)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!refConfigPath.endsWith('.json')) {
|
if (!refConfigPath.endsWith('.json')) {
|
||||||
refConfigPath = join(refConfigPath, 'tsconfig.json');
|
refConfigPath = join(refConfigPath, 'tsconfig.json');
|
||||||
}
|
}
|
||||||
const refTsConfig = readCachedTsConfig(refConfigPath);
|
const refTsConfig = readCachedTsConfig(refConfigPath);
|
||||||
projectReferences[refConfigPath] = refTsConfig;
|
const result = visitor(refConfigPath, refTsConfig);
|
||||||
|
if (result !== false) {
|
||||||
resolveInternalProjectReferences(
|
walkProjectReferences(refTsConfig, workspaceRoot, projectRoot, visitor);
|
||||||
refTsConfig,
|
}
|
||||||
workspaceRoot,
|
|
||||||
projectRoot,
|
|
||||||
projectReferences
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return projectReferences;
|
return projectReferences;
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
detectPackageManager,
|
detectPackageManager,
|
||||||
getPackageManagerVersion,
|
getPackageManagerVersion,
|
||||||
isWorkspacesEnabled,
|
|
||||||
output,
|
output,
|
||||||
readJson,
|
readJson,
|
||||||
type GeneratorCallback,
|
type GeneratorCallback,
|
||||||
@ -10,6 +9,7 @@ import {
|
|||||||
import { minimatch } from 'minimatch';
|
import { minimatch } from 'minimatch';
|
||||||
import { join } from 'node:path/posix';
|
import { join } from 'node:path/posix';
|
||||||
import { getGlobPatternsFromPackageManagerWorkspaces } from 'nx/src/plugins/package-json';
|
import { getGlobPatternsFromPackageManagerWorkspaces } from 'nx/src/plugins/package-json';
|
||||||
|
import { PackageJson } from 'nx/src/utils/package-json';
|
||||||
import { lt } from 'semver';
|
import { lt } from 'semver';
|
||||||
|
|
||||||
export type ProjectPackageManagerWorkspaceState =
|
export type ProjectPackageManagerWorkspaceState =
|
||||||
@ -37,7 +37,22 @@ export function getProjectPackageManagerWorkspaceState(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function isUsingPackageManagerWorkspaces(tree: Tree): boolean {
|
export function isUsingPackageManagerWorkspaces(tree: Tree): boolean {
|
||||||
return isWorkspacesEnabled(detectPackageManager(tree.root), tree.root);
|
return isWorkspacesEnabled(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isWorkspacesEnabled(
|
||||||
|
tree: Tree
|
||||||
|
// packageManager: PackageManager = detectPackageManager(),
|
||||||
|
// root: string = workspaceRoot
|
||||||
|
): boolean {
|
||||||
|
const packageManager = detectPackageManager(tree.root);
|
||||||
|
if (packageManager === 'pnpm') {
|
||||||
|
return tree.exists('pnpm-workspace.yaml');
|
||||||
|
}
|
||||||
|
|
||||||
|
// yarn and npm both use the same 'workspaces' property in package.json
|
||||||
|
const packageJson = readJson<PackageJson>(tree, 'package.json');
|
||||||
|
return !!packageJson?.workspaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getProjectPackageManagerWorkspaceStateWarningTask(
|
export function getProjectPackageManagerWorkspaceStateWarningTask(
|
||||||
|
|||||||
@ -1,12 +1,16 @@
|
|||||||
import {
|
import {
|
||||||
|
joinPathFragments,
|
||||||
|
offsetFromRoot,
|
||||||
output,
|
output,
|
||||||
readJson,
|
readJson,
|
||||||
readNxJson,
|
readNxJson,
|
||||||
workspaceRoot,
|
|
||||||
type Tree,
|
type Tree,
|
||||||
|
updateJson,
|
||||||
|
workspaceRoot,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { FsTree } from 'nx/src/generators/tree';
|
import { FsTree } from 'nx/src/generators/tree';
|
||||||
import { isUsingPackageManagerWorkspaces } from '../package-manager-workspaces';
|
import { isUsingPackageManagerWorkspaces } from '../package-manager-workspaces';
|
||||||
|
import { relative } from 'node:path/posix';
|
||||||
|
|
||||||
export function isUsingTypeScriptPlugin(tree: Tree): boolean {
|
export function isUsingTypeScriptPlugin(tree: Tree): boolean {
|
||||||
const nxJson = readNxJson(tree);
|
const nxJson = readNxJson(tree);
|
||||||
@ -96,3 +100,78 @@ export function assertNotUsingTsSolutionSetup(
|
|||||||
|
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function updateTsconfigFiles(
|
||||||
|
tree: Tree,
|
||||||
|
projectRoot: string,
|
||||||
|
runtimeTsconfigFileName: string,
|
||||||
|
compilerOptions: Record<string, string | boolean | string[]>,
|
||||||
|
exclude: string[] = [],
|
||||||
|
rootDir = 'src'
|
||||||
|
) {
|
||||||
|
if (!isUsingTsSolutionSetup(tree)) return;
|
||||||
|
|
||||||
|
const offset = offsetFromRoot(projectRoot);
|
||||||
|
const tsconfig = `${projectRoot}/${runtimeTsconfigFileName}`;
|
||||||
|
const tsconfigSpec = `${projectRoot}/tsconfig.spec.json`;
|
||||||
|
const e2eRoot = `${projectRoot}-e2e`;
|
||||||
|
const tsconfigE2E = `${e2eRoot}/tsconfig.json`;
|
||||||
|
|
||||||
|
if (tree.exists(tsconfig)) {
|
||||||
|
updateJson(tree, tsconfig, (json) => {
|
||||||
|
json.extends = joinPathFragments(offset, 'tsconfig.base.json');
|
||||||
|
|
||||||
|
json.compilerOptions = {
|
||||||
|
...json.compilerOptions,
|
||||||
|
// Make sure d.ts files from typecheck does not conflict with bundlers.
|
||||||
|
// Other tooling like jest write to "out-tsc/jest" to we just default to "out-tsc/<project-name>".
|
||||||
|
outDir: joinPathFragments('out-tsc', projectRoot.split('/').at(-1)),
|
||||||
|
rootDir,
|
||||||
|
...compilerOptions,
|
||||||
|
};
|
||||||
|
|
||||||
|
const excludeSet: Set<string> = json.exclude
|
||||||
|
? new Set(['dist', ...json.exclude, ...exclude])
|
||||||
|
: new Set(exclude);
|
||||||
|
json.exclude = Array.from(excludeSet);
|
||||||
|
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tree.exists(tsconfigSpec)) {
|
||||||
|
updateJson(tree, tsconfigSpec, (json) => {
|
||||||
|
json.extends = joinPathFragments(offset, 'tsconfig.base.json');
|
||||||
|
json.compilerOptions = {
|
||||||
|
...json.compilerOptions,
|
||||||
|
...compilerOptions,
|
||||||
|
};
|
||||||
|
const runtimePath = `./${runtimeTsconfigFileName}`;
|
||||||
|
json.references ??= [];
|
||||||
|
if (!json.references.some((x) => x.path === runtimePath))
|
||||||
|
json.references.push({ path: runtimePath });
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tree.exists(tsconfigE2E)) {
|
||||||
|
// tsconfig.json for e2e projects need to have references array
|
||||||
|
updateJson(tree, tsconfigE2E, (json) => {
|
||||||
|
json.references ??= [];
|
||||||
|
const projectPath = relative(e2eRoot, projectRoot);
|
||||||
|
if (!json.references.some((x) => x.path === projectPath))
|
||||||
|
json.references.push({ path: projectPath });
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tree.exists('tsconfig.json')) {
|
||||||
|
updateJson(tree, 'tsconfig.json', (json) => {
|
||||||
|
const projectPath = './' + projectRoot;
|
||||||
|
json.references ??= [];
|
||||||
|
if (!json.references.some((x) => x.path === projectPath))
|
||||||
|
json.references.push({ path: projectPath });
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -5,6 +5,8 @@ import {
|
|||||||
readNxJson,
|
readNxJson,
|
||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
Tree,
|
Tree,
|
||||||
|
updateJson,
|
||||||
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
|
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
@ -174,23 +176,22 @@ describe('app', () => {
|
|||||||
|
|
||||||
describe('--style scss', () => {
|
describe('--style scss', () => {
|
||||||
it('should generate scss styles', async () => {
|
it('should generate scss styles', async () => {
|
||||||
const name = uniq();
|
|
||||||
await applicationGenerator(tree, {
|
await applicationGenerator(tree, {
|
||||||
directory: name,
|
directory: 'myapp',
|
||||||
style: 'scss',
|
style: 'scss',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(tree.exists(`${name}/src/app/page.module.scss`)).toBeTruthy();
|
expect(tree.exists(`myapp/src/app/page.module.scss`)).toBeTruthy();
|
||||||
expect(tree.exists(`${name}/src/app/global.css`)).toBeTruthy();
|
expect(tree.exists(`myapp/src/app/global.css`)).toBeTruthy();
|
||||||
|
|
||||||
const indexContent = tree.read(`${name}/src/app/page.tsx`, 'utf-8');
|
const indexContent = tree.read(`myapp/src/app/page.tsx`, 'utf-8');
|
||||||
expect(indexContent).toContain(`import styles from './page.module.scss'`);
|
expect(indexContent).toContain(`import styles from './page.module.scss'`);
|
||||||
expect(tree.read(`${name}/src/app/layout.tsx`, 'utf-8'))
|
expect(tree.read(`myapp/src/app/layout.tsx`, 'utf-8'))
|
||||||
.toMatchInlineSnapshot(`
|
.toMatchInlineSnapshot(`
|
||||||
"import './global.css';
|
"import './global.css';
|
||||||
|
|
||||||
export const metadata = {
|
export const metadata = {
|
||||||
title: 'Welcome to ${name}',
|
title: 'Welcome to myapp',
|
||||||
description: 'Generated by create-nx-workspace',
|
description: 'Generated by create-nx-workspace',
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -212,23 +213,22 @@ describe('app', () => {
|
|||||||
|
|
||||||
describe('--style less', () => {
|
describe('--style less', () => {
|
||||||
it('should generate less styles', async () => {
|
it('should generate less styles', async () => {
|
||||||
const name = uniq();
|
|
||||||
await applicationGenerator(tree, {
|
await applicationGenerator(tree, {
|
||||||
directory: name,
|
directory: 'myapp',
|
||||||
style: 'less',
|
style: 'less',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(tree.exists(`${name}/src/app/page.module.less`)).toBeTruthy();
|
expect(tree.exists(`myapp/src/app/page.module.less`)).toBeTruthy();
|
||||||
expect(tree.exists(`${name}/src/app/global.less`)).toBeTruthy();
|
expect(tree.exists(`myapp/src/app/global.less`)).toBeTruthy();
|
||||||
|
|
||||||
const indexContent = tree.read(`${name}/src/app/page.tsx`, 'utf-8');
|
const indexContent = tree.read(`myapp/src/app/page.tsx`, 'utf-8');
|
||||||
expect(indexContent).toContain(`import styles from './page.module.less'`);
|
expect(indexContent).toContain(`import styles from './page.module.less'`);
|
||||||
expect(tree.read(`${name}/src/app/layout.tsx`, 'utf-8'))
|
expect(tree.read(`myapp/src/app/layout.tsx`, 'utf-8'))
|
||||||
.toMatchInlineSnapshot(`
|
.toMatchInlineSnapshot(`
|
||||||
"import './global.less';
|
"import './global.less';
|
||||||
|
|
||||||
export const metadata = {
|
export const metadata = {
|
||||||
title: 'Welcome to ${name}',
|
title: 'Welcome to myapp',
|
||||||
description: 'Generated by create-nx-workspace',
|
description: 'Generated by create-nx-workspace',
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -616,10 +616,8 @@ describe('app', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should add .eslintrc.json and dependencies', async () => {
|
it('should add .eslintrc.json and dependencies', async () => {
|
||||||
const name = uniq();
|
|
||||||
|
|
||||||
await applicationGenerator(tree, {
|
await applicationGenerator(tree, {
|
||||||
directory: name,
|
directory: 'myapp',
|
||||||
style: 'css',
|
style: 'css',
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -631,7 +629,7 @@ describe('app', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const eslintJson = readJson(tree, `${name}/.eslintrc.json`);
|
const eslintJson = readJson(tree, `myapp/.eslintrc.json`);
|
||||||
expect(eslintJson).toMatchInlineSnapshot(`
|
expect(eslintJson).toMatchInlineSnapshot(`
|
||||||
{
|
{
|
||||||
"extends": [
|
"extends": [
|
||||||
@ -655,7 +653,7 @@ describe('app', () => {
|
|||||||
"rules": {
|
"rules": {
|
||||||
"@next/next/no-html-link-for-pages": [
|
"@next/next/no-html-link-for-pages": [
|
||||||
"error",
|
"error",
|
||||||
"${name}/pages",
|
"myapp/pages",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -838,6 +836,172 @@ describe('app (legacy)', () => {
|
|||||||
expect(projectConfiguration.targets.build).toBeDefined();
|
expect(projectConfiguration.targets.build).toBeDefined();
|
||||||
expect(projectConfiguration.targets.serve).toBeDefined();
|
expect(projectConfiguration.targets.serve).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('TS solution setup', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
tree = createTreeWithEmptyWorkspace();
|
||||||
|
updateJson(tree, 'package.json', (json) => {
|
||||||
|
json.workspaces = ['packages/*', 'apps/*'];
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
writeJson(tree, 'tsconfig.base.json', {
|
||||||
|
compilerOptions: {
|
||||||
|
composite: true,
|
||||||
|
declaration: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
writeJson(tree, 'tsconfig.json', {
|
||||||
|
extends: './tsconfig.base.json',
|
||||||
|
files: [],
|
||||||
|
references: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add project references when using TS solution', async () => {
|
||||||
|
await applicationGenerator(tree, {
|
||||||
|
...schema,
|
||||||
|
addPlugin: true,
|
||||||
|
directory: 'myapp',
|
||||||
|
name: 'myapp',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(readJson(tree, 'tsconfig.json').references).toMatchInlineSnapshot(`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"path": "./myapp-e2e",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./myapp",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'myapp/tsconfig.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"allowJs": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"incremental": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"esnext",
|
||||||
|
],
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"noEmit": true,
|
||||||
|
"outDir": "out-tsc/myapp",
|
||||||
|
"paths": {
|
||||||
|
"@/*": [
|
||||||
|
"./src/*",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"name": "next",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"rootDir": "src",
|
||||||
|
"strict": true,
|
||||||
|
"types": [
|
||||||
|
"jest",
|
||||||
|
"node",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"dist",
|
||||||
|
"node_modules",
|
||||||
|
"jest.config.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
".next",
|
||||||
|
"eslint.config.js",
|
||||||
|
"eslint.config.cjs",
|
||||||
|
"eslint.config.mjs",
|
||||||
|
],
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts",
|
||||||
|
"src/**/*.tsx",
|
||||||
|
"src/**/*.js",
|
||||||
|
"src/**/*.jsx",
|
||||||
|
"../myapp/.next/types/**/*.ts",
|
||||||
|
"../dist/myapp/.next/types/**/*.ts",
|
||||||
|
"next-env.d.ts",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'myapp/tsconfig.spec.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"jsx": "preserve",
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"outDir": "./out-tsc/jest",
|
||||||
|
"types": [
|
||||||
|
"jest",
|
||||||
|
"node",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
"jest.config.ts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.test.tsx",
|
||||||
|
"src/**/*.spec.tsx",
|
||||||
|
"src/**/*.test.js",
|
||||||
|
"src/**/*.spec.js",
|
||||||
|
"src/**/*.test.jsx",
|
||||||
|
"src/**/*.spec.jsx",
|
||||||
|
"src/**/*.d.ts",
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'myapp-e2e/tsconfig.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"allowJs": true,
|
||||||
|
"outDir": "dist",
|
||||||
|
"sourceMap": false,
|
||||||
|
"tsBuildInfoFile": "dist/tsconfig.tsbuildinfo",
|
||||||
|
"types": [
|
||||||
|
"cypress",
|
||||||
|
"node",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"dist",
|
||||||
|
],
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.js",
|
||||||
|
"cypress.config.ts",
|
||||||
|
"**/*.cy.ts",
|
||||||
|
"**/*.cy.tsx",
|
||||||
|
"**/*.cy.js",
|
||||||
|
"**/*.cy.jsx",
|
||||||
|
"**/*.d.ts",
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "../myapp",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function uniq() {
|
function uniq() {
|
||||||
|
|||||||
@ -7,7 +7,6 @@ import {
|
|||||||
Tree,
|
Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { initGenerator as jsInitGenerator } from '@nx/js';
|
import { initGenerator as jsInitGenerator } from '@nx/js';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
|
||||||
import { setupTailwindGenerator } from '@nx/react';
|
import { setupTailwindGenerator } from '@nx/react';
|
||||||
import {
|
import {
|
||||||
testingLibraryReactVersion,
|
testingLibraryReactVersion,
|
||||||
@ -31,6 +30,7 @@ import { updateCypressTsConfig } from './lib/update-cypress-tsconfig';
|
|||||||
import { showPossibleWarnings } from './lib/show-possible-warnings';
|
import { showPossibleWarnings } from './lib/show-possible-warnings';
|
||||||
import { tsLibVersion } from '../../utils/versions';
|
import { tsLibVersion } from '../../utils/versions';
|
||||||
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
|
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
|
||||||
|
import { updateTsconfigFiles } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
|
||||||
export async function applicationGenerator(host: Tree, schema: Schema) {
|
export async function applicationGenerator(host: Tree, schema: Schema) {
|
||||||
return await applicationGeneratorInternal(host, {
|
return await applicationGeneratorInternal(host, {
|
||||||
@ -40,8 +40,6 @@ export async function applicationGenerator(host: Tree, schema: Schema) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function applicationGeneratorInternal(host: Tree, schema: Schema) {
|
export async function applicationGeneratorInternal(host: Tree, schema: Schema) {
|
||||||
assertNotUsingTsSolutionSetup(host, 'next', 'application');
|
|
||||||
|
|
||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
const options = await normalizeOptions(host, schema);
|
const options = await normalizeOptions(host, schema);
|
||||||
|
|
||||||
@ -51,6 +49,8 @@ export async function applicationGeneratorInternal(host: Tree, schema: Schema) {
|
|||||||
js: options.js,
|
js: options.js,
|
||||||
skipPackageJson: options.skipPackageJson,
|
skipPackageJson: options.skipPackageJson,
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
|
addTsPlugin: schema.useTsSolution,
|
||||||
|
formatter: schema.formatter,
|
||||||
});
|
});
|
||||||
tasks.push(jsInitTask);
|
tasks.push(jsInitTask);
|
||||||
|
|
||||||
@ -117,6 +117,21 @@ export async function applicationGeneratorInternal(host: Tree, schema: Schema) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateTsconfigFiles(
|
||||||
|
host,
|
||||||
|
options.appProjectRoot,
|
||||||
|
'tsconfig.json',
|
||||||
|
{
|
||||||
|
jsx: 'preserve',
|
||||||
|
module: 'esnext',
|
||||||
|
moduleResolution: 'bundler',
|
||||||
|
},
|
||||||
|
options.linter === 'eslint'
|
||||||
|
? ['.next', 'eslint.config.js', 'eslint.config.cjs', 'eslint.config.mjs']
|
||||||
|
: ['.next'],
|
||||||
|
options.src ? 'src' : '.'
|
||||||
|
);
|
||||||
|
|
||||||
if (!options.skipFormat) {
|
if (!options.skipFormat) {
|
||||||
await formatFiles(host);
|
await formatFiles(host);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,16 +3,22 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
<% if (style === '@emotion/styled') { %>"jsxImportSource": "@emotion/react",<% } %>
|
<% if (style === '@emotion/styled') { %>"jsxImportSource": "@emotion/react",<% } %>
|
||||||
"allowJs": true,
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"allowSyntheticDefaultImports": true,
|
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"forceConsistentCasingInFileNames": true,
|
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
|
"allowJs": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
"incremental": true,
|
"incremental": true,
|
||||||
"plugins": [{ "name": "next" }]
|
"plugins": [{ "name": "next" }]<% if (isUsingTsSolutionSetup) { %>,
|
||||||
|
"paths": {
|
||||||
|
"@/*": [<% if (src) { %>"./src/*"<% } else { %>"./*"<% } %>]
|
||||||
|
}<% } %>
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"<%= rootPath %>**/*.ts",
|
"<%= rootPath %>**/*.ts",
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import {
|
import {
|
||||||
addProjectConfiguration,
|
addProjectConfiguration,
|
||||||
ensurePackage,
|
ensurePackage,
|
||||||
getPackageManagerCommand,
|
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
readNxJson,
|
readNxJson,
|
||||||
Tree,
|
Tree,
|
||||||
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { Linter } from '@nx/eslint';
|
import { Linter } from '@nx/eslint';
|
||||||
|
|
||||||
@ -14,6 +14,7 @@ import { webStaticServeGenerator } from '@nx/web';
|
|||||||
import { findPluginForConfigFile } from '@nx/devkit/src/utils/find-plugin-for-config-file';
|
import { findPluginForConfigFile } from '@nx/devkit/src/utils/find-plugin-for-config-file';
|
||||||
import { addE2eCiTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
import { addE2eCiTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
||||||
import { getE2EWebServerInfo } from '@nx/devkit/src/generators/e2e-web-server-info-utils';
|
import { getE2EWebServerInfo } from '@nx/devkit/src/generators/e2e-web-server-info-utils';
|
||||||
|
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
|
||||||
export async function addE2e(host: Tree, options: NormalizedSchema) {
|
export async function addE2e(host: Tree, options: NormalizedSchema) {
|
||||||
const nxJson = readNxJson(host);
|
const nxJson = readNxJson(host);
|
||||||
@ -44,13 +45,31 @@ export async function addE2e(host: Tree, options: NormalizedSchema) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isUsingTsSolutionSetup(host)) {
|
||||||
|
writeJson(
|
||||||
|
host,
|
||||||
|
joinPathFragments(options.e2eProjectRoot, 'package.json'),
|
||||||
|
{
|
||||||
|
name: options.e2eProjectName,
|
||||||
|
version: '0.0.1',
|
||||||
|
private: true,
|
||||||
|
nx: {
|
||||||
|
projectType: 'application',
|
||||||
|
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
||||||
|
implicitDependencies: [options.projectName],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
addProjectConfiguration(host, options.e2eProjectName, {
|
addProjectConfiguration(host, options.e2eProjectName, {
|
||||||
root: options.e2eProjectRoot,
|
root: options.e2eProjectRoot,
|
||||||
|
projectType: 'application',
|
||||||
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
||||||
targets: {},
|
targets: {},
|
||||||
tags: [],
|
tags: [],
|
||||||
implicitDependencies: [options.projectName],
|
implicitDependencies: [options.projectName],
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const e2eTask = await configurationGenerator(host, {
|
const e2eTask = await configurationGenerator(host, {
|
||||||
...options,
|
...options,
|
||||||
@ -107,13 +126,32 @@ export async function addE2e(host: Tree, options: NormalizedSchema) {
|
|||||||
const { configurationGenerator } = ensurePackage<
|
const { configurationGenerator } = ensurePackage<
|
||||||
typeof import('@nx/playwright')
|
typeof import('@nx/playwright')
|
||||||
>('@nx/playwright', nxVersion);
|
>('@nx/playwright', nxVersion);
|
||||||
|
if (isUsingTsSolutionSetup(host)) {
|
||||||
|
writeJson(
|
||||||
|
host,
|
||||||
|
joinPathFragments(options.e2eProjectRoot, 'package.json'),
|
||||||
|
{
|
||||||
|
name: options.e2eProjectName,
|
||||||
|
version: '0.0.1',
|
||||||
|
private: true,
|
||||||
|
nx: {
|
||||||
|
projectType: 'application',
|
||||||
|
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
||||||
|
implicitDependencies: [options.projectName],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
addProjectConfiguration(host, options.e2eProjectName, {
|
addProjectConfiguration(host, options.e2eProjectName, {
|
||||||
root: options.e2eProjectRoot,
|
root: options.e2eProjectRoot,
|
||||||
|
projectType: 'application',
|
||||||
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
||||||
targets: {},
|
targets: {},
|
||||||
tags: [],
|
tags: [],
|
||||||
implicitDependencies: [options.projectName],
|
implicitDependencies: [options.projectName],
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const e2eTask = await configurationGenerator(host, {
|
const e2eTask = await configurationGenerator(host, {
|
||||||
rootProject: options.rootProject,
|
rootProject: options.rootProject,
|
||||||
project: options.e2eProjectName,
|
project: options.e2eProjectName,
|
||||||
|
|||||||
@ -22,6 +22,8 @@ export async function addLinting(
|
|||||||
host: Tree,
|
host: Tree,
|
||||||
options: NormalizedSchema
|
options: NormalizedSchema
|
||||||
): Promise<GeneratorCallback> {
|
): Promise<GeneratorCallback> {
|
||||||
|
if (options.linter !== 'eslint') return () => {};
|
||||||
|
|
||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
|
|
||||||
tasks.push(
|
tasks.push(
|
||||||
|
|||||||
@ -1,11 +1,17 @@
|
|||||||
import { NormalizedSchema } from './normalize-options';
|
import { NormalizedSchema } from './normalize-options';
|
||||||
import {
|
import {
|
||||||
addProjectConfiguration,
|
addProjectConfiguration,
|
||||||
|
joinPathFragments,
|
||||||
ProjectConfiguration,
|
ProjectConfiguration,
|
||||||
readNxJson,
|
readNxJson,
|
||||||
Tree,
|
Tree,
|
||||||
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
||||||
|
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||||
|
import { nextVersion } from '../../../utils/versions';
|
||||||
|
import { reactDomVersion, reactVersion } from '@nx/react';
|
||||||
|
|
||||||
export function addProject(host: Tree, options: NormalizedSchema) {
|
export function addProject(host: Tree, options: NormalizedSchema) {
|
||||||
const targets: Record<string, any> = {};
|
const targets: Record<string, any> = {};
|
||||||
@ -66,7 +72,26 @@ export function addProject(host: Tree, options: NormalizedSchema) {
|
|||||||
tags: options.parsedTags,
|
tags: options.parsedTags,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (isUsingTsSolutionSetup(host)) {
|
||||||
|
writeJson(host, joinPathFragments(options.appProjectRoot, 'package.json'), {
|
||||||
|
name: getImportPath(host, options.name),
|
||||||
|
version: '0.0.1',
|
||||||
|
private: true,
|
||||||
|
dependencies: {
|
||||||
|
next: nextVersion,
|
||||||
|
react: reactVersion,
|
||||||
|
'react-dom': reactDomVersion,
|
||||||
|
},
|
||||||
|
nx: {
|
||||||
|
name: options.name,
|
||||||
|
projectType: 'application',
|
||||||
|
sourceRoot: options.appProjectRoot,
|
||||||
|
tags: options.parsedTags?.length ? options.parsedTags : undefined,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
addProjectConfiguration(host, options.projectName, {
|
addProjectConfiguration(host, options.projectName, {
|
||||||
...project,
|
...project,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import {
|
|||||||
createAppJsx,
|
createAppJsx,
|
||||||
createStyleRules,
|
createStyleRules,
|
||||||
} from './create-application-files.helpers';
|
} from './create-application-files.helpers';
|
||||||
|
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
|
||||||
export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
|
export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
|
||||||
const offsetFromRoot = _offsetFromRoot(options.appProjectRoot);
|
const offsetFromRoot = _offsetFromRoot(options.appProjectRoot);
|
||||||
@ -30,14 +31,15 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
|
|||||||
'.next/types/**/*.ts'
|
'.next/types/**/*.ts'
|
||||||
);
|
);
|
||||||
|
|
||||||
// scope tsconfig to the project directory so that it doesn't include other projects/libs
|
const rootPath =
|
||||||
const rootPath = options.rootProject
|
options.rootProject || isUsingTsSolutionSetup(host)
|
||||||
? options.src
|
? options.src
|
||||||
? 'src/'
|
? 'src/'
|
||||||
: options.appDir
|
: options.appDir
|
||||||
? 'app/'
|
? 'app/'
|
||||||
: 'pages/'
|
: 'pages/'
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
const templateVariables = {
|
const templateVariables = {
|
||||||
...names(options.name),
|
...names(options.name),
|
||||||
...options,
|
...options,
|
||||||
@ -55,8 +57,8 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
|
|||||||
appContent: createAppJsx(options.projectName),
|
appContent: createAppJsx(options.projectName),
|
||||||
styleContent: createStyleRules(),
|
styleContent: createStyleRules(),
|
||||||
pageStyleContent: `.page {}`,
|
pageStyleContent: `.page {}`,
|
||||||
|
|
||||||
stylesExt: options.style === 'less' ? options.style : 'css',
|
stylesExt: options.style === 'less' ? options.style : 'css',
|
||||||
|
isUsingTsSolutionSetup: isUsingTsSolutionSetup(host),
|
||||||
};
|
};
|
||||||
|
|
||||||
const generatedAppFilePath = options.src
|
const generatedAppFilePath = options.src
|
||||||
|
|||||||
@ -17,6 +17,9 @@ export interface Schema {
|
|||||||
skipPackageJson?: boolean;
|
skipPackageJson?: boolean;
|
||||||
appDir?: boolean;
|
appDir?: boolean;
|
||||||
src?: boolean;
|
src?: boolean;
|
||||||
|
// Internal options
|
||||||
rootProject?: boolean;
|
rootProject?: boolean;
|
||||||
addPlugin?: boolean;
|
addPlugin?: boolean;
|
||||||
|
useTsSolution?: boolean;
|
||||||
|
formatter?: 'prettier' | 'none';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -69,8 +69,10 @@
|
|||||||
"linter": {
|
"linter": {
|
||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"skipFormat": {
|
"skipFormat": {
|
||||||
"description": "Skip formatting files.",
|
"description": "Skip formatting files.",
|
||||||
@ -82,7 +84,9 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "none"],
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"default": "jest"
|
"default": "none",
|
||||||
|
"x-prompt": "What unit test runner should be used?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"e2eTestRunner": {
|
"e2eTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import type { Tree } from '@nx/devkit';
|
import { joinPathFragments, Tree } from '@nx/devkit';
|
||||||
import {
|
import {
|
||||||
updateJson,
|
updateJson,
|
||||||
generateFiles,
|
generateFiles,
|
||||||
@ -11,6 +11,7 @@ import {
|
|||||||
import { CustomServerSchema } from './schema';
|
import { CustomServerSchema } from './schema';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { configureForSwc } from '../../utils/add-swc-to-custom-server';
|
import { configureForSwc } from '../../utils/add-swc-to-custom-server';
|
||||||
|
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
|
||||||
export async function customServerGenerator(
|
export async function customServerGenerator(
|
||||||
host: Tree,
|
host: Tree,
|
||||||
@ -71,12 +72,18 @@ export async function customServerGenerator(
|
|||||||
project.root
|
project.root
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
|
const offset = offsetFromRoot(project.root);
|
||||||
|
const isTsSolution = isUsingTsSolutionSetup(host);
|
||||||
|
|
||||||
generateFiles(host, join(__dirname, 'files'), project.root, {
|
generateFiles(host, join(__dirname, 'files'), project.root, {
|
||||||
...options,
|
...options,
|
||||||
hasPlugin,
|
hasPlugin,
|
||||||
projectPathFromDist,
|
projectPathFromDist,
|
||||||
offsetFromRoot: offsetFromRoot(project.root),
|
offsetFromRoot: offset,
|
||||||
projectRoot: project.root,
|
projectRoot: project.root,
|
||||||
|
baseTsConfigPath: isTsSolution
|
||||||
|
? joinPathFragments(offset, 'tsconfig.base.json')
|
||||||
|
: './tsconfig.json',
|
||||||
tmpl: '',
|
tmpl: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
{
|
{
|
||||||
"extends": "./tsconfig.json",
|
"extends": "<%= baseTsConfigPath %>",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"module": "commonjs",
|
"module": "nodenext",
|
||||||
|
"moduleResolution": "nodenext",
|
||||||
"noEmit": false,
|
"noEmit": false,
|
||||||
"incremental": true,
|
"incremental": true,
|
||||||
<% if(hasPlugin && compiler === 'tsc') { %>
|
<% if(hasPlugin && compiler === 'tsc') { %>
|
||||||
|
|||||||
@ -8,7 +8,6 @@ import {
|
|||||||
createProjectGraphAsync,
|
createProjectGraphAsync,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { addPlugin } from '@nx/devkit/src/utils/add-plugin';
|
import { addPlugin } from '@nx/devkit/src/utils/add-plugin';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
|
||||||
import { reactDomVersion, reactVersion } from '@nx/react/src/utils/versions';
|
import { reactDomVersion, reactVersion } from '@nx/react/src/utils/versions';
|
||||||
import { addGitIgnoreEntry } from '../../utils/add-gitignore-entry';
|
import { addGitIgnoreEntry } from '../../utils/add-gitignore-entry';
|
||||||
import { nextVersion, nxVersion } from '../../utils/versions';
|
import { nextVersion, nxVersion } from '../../utils/versions';
|
||||||
@ -46,8 +45,6 @@ export async function nextInitGeneratorInternal(
|
|||||||
host: Tree,
|
host: Tree,
|
||||||
schema: InitSchema
|
schema: InitSchema
|
||||||
) {
|
) {
|
||||||
assertNotUsingTsSolutionSetup(host, 'next', 'init');
|
|
||||||
|
|
||||||
const nxJson = readNxJson(host);
|
const nxJson = readNxJson(host);
|
||||||
const addPluginDefault =
|
const addPluginDefault =
|
||||||
process.env.NX_ADD_PLUGINS !== 'false' &&
|
process.env.NX_ADD_PLUGINS !== 'false' &&
|
||||||
|
|||||||
@ -9,13 +9,13 @@ import {
|
|||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { libraryGenerator as reactLibraryGenerator } from '@nx/react/src/generators/library/library';
|
import { libraryGenerator as reactLibraryGenerator } from '@nx/react/src/generators/library/library';
|
||||||
import { addTsConfigPath, initGenerator as jsInitGenerator } from '@nx/js';
|
import { addTsConfigPath, initGenerator as jsInitGenerator } from '@nx/js';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
|
||||||
import { testingLibraryReactVersion } from '@nx/react/src/utils/versions';
|
import { testingLibraryReactVersion } from '@nx/react/src/utils/versions';
|
||||||
|
|
||||||
import { nextInitGenerator } from '../init/init';
|
import { nextInitGenerator } from '../init/init';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
import { normalizeOptions } from './lib/normalize-options';
|
import { normalizeOptions } from './lib/normalize-options';
|
||||||
import { eslintConfigNextVersion, tsLibVersion } from '../../utils/versions';
|
import { eslintConfigNextVersion, tsLibVersion } from '../../utils/versions';
|
||||||
|
import { updateTsconfigFiles } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
|
||||||
export async function libraryGenerator(host: Tree, rawOptions: Schema) {
|
export async function libraryGenerator(host: Tree, rawOptions: Schema) {
|
||||||
return await libraryGeneratorInternal(host, {
|
return await libraryGeneratorInternal(host, {
|
||||||
@ -25,8 +25,6 @@ export async function libraryGenerator(host: Tree, rawOptions: Schema) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function libraryGeneratorInternal(host: Tree, rawOptions: Schema) {
|
export async function libraryGeneratorInternal(host: Tree, rawOptions: Schema) {
|
||||||
assertNotUsingTsSolutionSetup(host, 'next', 'library');
|
|
||||||
|
|
||||||
const options = await normalizeOptions(host, rawOptions);
|
const options = await normalizeOptions(host, rawOptions);
|
||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
|
|
||||||
@ -45,7 +43,7 @@ export async function libraryGeneratorInternal(host: Tree, rawOptions: Schema) {
|
|||||||
|
|
||||||
const libTask = await reactLibraryGenerator(host, {
|
const libTask = await reactLibraryGenerator(host, {
|
||||||
...options,
|
...options,
|
||||||
compiler: 'swc',
|
bundler: 'none',
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
});
|
});
|
||||||
tasks.push(libTask);
|
tasks.push(libTask);
|
||||||
@ -142,6 +140,20 @@ export async function libraryGeneratorInternal(host: Tree, rawOptions: Schema) {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
updateTsconfigFiles(
|
||||||
|
host,
|
||||||
|
options.projectRoot,
|
||||||
|
'tsconfig.lib.json',
|
||||||
|
{
|
||||||
|
jsx: 'react-jsx',
|
||||||
|
module: 'esnext',
|
||||||
|
moduleResolution: 'bundler',
|
||||||
|
},
|
||||||
|
options.linter === 'eslint'
|
||||||
|
? ['eslint.config.js', 'eslint.config.cjs', 'eslint.config.mjs']
|
||||||
|
: undefined
|
||||||
|
);
|
||||||
|
|
||||||
if (!options.skipFormat) {
|
if (!options.skipFormat) {
|
||||||
await formatFiles(host);
|
await formatFiles(host);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,9 @@ export interface Schema {
|
|||||||
linter: Linter | LinterType;
|
linter: Linter | LinterType;
|
||||||
component?: boolean;
|
component?: boolean;
|
||||||
publishable?: boolean;
|
publishable?: boolean;
|
||||||
|
/** @deprecated Use bundler instead. */
|
||||||
buildable?: boolean;
|
buildable?: boolean;
|
||||||
|
bundler?: 'none' | 'vite' | 'rollup';
|
||||||
importPath?: string;
|
importPath?: string;
|
||||||
js?: boolean;
|
js?: boolean;
|
||||||
globalCss?: boolean;
|
globalCss?: boolean;
|
||||||
|
|||||||
@ -62,17 +62,29 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"bundler": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The bundler to use. Choosing 'none' means this library is not buildable.",
|
||||||
|
"enum": ["none", "vite", "rollup"],
|
||||||
|
"default": "none",
|
||||||
|
"x-prompt": "Which bundler would you like to use to build the library? Choose 'none' to skip build setup.",
|
||||||
|
"x-priority": "important"
|
||||||
|
},
|
||||||
"linter": {
|
"linter": {
|
||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["vitest", "jest", "none"],
|
"enum": ["vitest", "jest", "none"],
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"default": "vitest"
|
"default": "none",
|
||||||
|
"x-prompt": "What unit test runner should be used?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -105,7 +117,8 @@
|
|||||||
"buildable": {
|
"buildable": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": "Generate a buildable library."
|
"description": "Generate a buildable library that uses rollup to bundle.",
|
||||||
|
"x-deprecated": "Use the `bundler` option for greater control (none, vite, rollup)."
|
||||||
},
|
},
|
||||||
"importPath": {
|
"importPath": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -95,12 +95,17 @@ export async function configurationGeneratorInternal(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (isTsSolutionSetup) {
|
if (isTsSolutionSetup) {
|
||||||
|
// skip eslint from typechecking since it extends from root file that is outside rootDir
|
||||||
|
if (options.linter === 'eslint') {
|
||||||
|
tsconfig.exclude = ['dist', 'eslint.config.js'];
|
||||||
|
}
|
||||||
|
|
||||||
tsconfig.compilerOptions.outDir = 'dist';
|
tsconfig.compilerOptions.outDir = 'dist';
|
||||||
tsconfig.compilerOptions.tsBuildInfoFile = 'dist/tsconfig.tsbuildinfo';
|
tsconfig.compilerOptions.tsBuildInfoFile = 'dist/tsconfig.tsbuildinfo';
|
||||||
|
|
||||||
if (!options.rootProject) {
|
if (!options.rootProject) {
|
||||||
// add the project tsconfog to the workspace root tsconfig.json references
|
|
||||||
updateJson(tree, 'tsconfig.json', (json) => {
|
updateJson(tree, 'tsconfig.json', (json) => {
|
||||||
|
// add the project tsconfig to the workspace root tsconfig.json references
|
||||||
json.references ??= [];
|
json.references ??= [];
|
||||||
json.references.push({ path: './' + projectConfig.root });
|
json.references.push({ path: './' + projectConfig.root });
|
||||||
return json;
|
return json;
|
||||||
@ -130,6 +135,9 @@ export async function configurationGeneratorInternal(
|
|||||||
name: importPath,
|
name: importPath,
|
||||||
version: '0.0.1',
|
version: '0.0.1',
|
||||||
private: true,
|
private: true,
|
||||||
|
nx: {
|
||||||
|
name: options.project,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
writeJson(tree, packageJsonPath, packageJson);
|
writeJson(tree, packageJsonPath, packageJson);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,8 @@ import {
|
|||||||
getProjects,
|
getProjects,
|
||||||
readJson,
|
readJson,
|
||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
|
updateJson,
|
||||||
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||||
import { Linter } from '@nx/eslint';
|
import { Linter } from '@nx/eslint';
|
||||||
@ -249,4 +251,152 @@ describe('app', () => {
|
|||||||
expect(readJson(appTree, 'package.json')).toEqual(packageJsonBefore);
|
expect(readJson(appTree, 'package.json')).toEqual(packageJsonBefore);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('TS solution setup', () => {
|
||||||
|
it('should add project references when using TS solution', async () => {
|
||||||
|
const tree = createTreeWithEmptyWorkspace();
|
||||||
|
tree.write('.gitignore', '');
|
||||||
|
updateJson(tree, 'package.json', (json) => {
|
||||||
|
json.workspaces = ['packages/*', 'apps/*'];
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
writeJson(tree, 'tsconfig.base.json', {
|
||||||
|
compilerOptions: {
|
||||||
|
composite: true,
|
||||||
|
declaration: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
writeJson(tree, 'tsconfig.json', {
|
||||||
|
extends: './tsconfig.base.json',
|
||||||
|
files: [],
|
||||||
|
references: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
await reactNativeApplicationGenerator(tree, {
|
||||||
|
directory: 'my-app',
|
||||||
|
displayName: 'myApp',
|
||||||
|
tags: 'one,two',
|
||||||
|
linter: Linter.EsLint,
|
||||||
|
e2eTestRunner: 'none',
|
||||||
|
install: false,
|
||||||
|
unitTestRunner: 'jest',
|
||||||
|
bundler: 'vite',
|
||||||
|
addPlugin: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(readJson(tree, 'tsconfig.json').references).toMatchInlineSnapshot(`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"path": "./my-app",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'my-app/tsconfig.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"declaration": true,
|
||||||
|
"jsx": "react-native",
|
||||||
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"esnext",
|
||||||
|
],
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
},
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"files": [],
|
||||||
|
"include": [],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.app.json",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.spec.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'my-app/tsconfig.app.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
],
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"noUnusedLocals": false,
|
||||||
|
"outDir": "out-tsc/my-app",
|
||||||
|
"rootDir": "src",
|
||||||
|
"types": [
|
||||||
|
"node",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"dist",
|
||||||
|
"jest.config.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.spec.tsx",
|
||||||
|
"src/test-setup.ts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"eslint.config.js",
|
||||||
|
"eslint.config.cjs",
|
||||||
|
"eslint.config.mjs",
|
||||||
|
],
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"files": [
|
||||||
|
"../node_modules/@nx/react-native/typings/svg.d.ts",
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts",
|
||||||
|
"src/**/*.tsx",
|
||||||
|
"src/**/*.js",
|
||||||
|
"src/**/*.jsx",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'my-app/tsconfig.spec.json'))
|
||||||
|
.toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
],
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"noUnusedLocals": false,
|
||||||
|
"outDir": "./out-tsc/jest",
|
||||||
|
"types": [
|
||||||
|
"jest",
|
||||||
|
"node",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"files": [
|
||||||
|
"src/test-setup.ts",
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"jest.config.ts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.test.tsx",
|
||||||
|
"src/**/*.spec.tsx",
|
||||||
|
"src/**/*.test.js",
|
||||||
|
"src/**/*.spec.js",
|
||||||
|
"src/**/*.test.jsx",
|
||||||
|
"src/**/*.spec.jsx",
|
||||||
|
"src/**/*.d.ts",
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.app.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import {
|
|||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { initGenerator as jsInitGenerator } from '@nx/js';
|
import { initGenerator as jsInitGenerator } from '@nx/js';
|
||||||
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
|
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
|
||||||
|
|
||||||
import { addLinting } from '../../utils/add-linting';
|
import { addLinting } from '../../utils/add-linting';
|
||||||
import { addJest } from '../../utils/add-jest';
|
import { addJest } from '../../utils/add-jest';
|
||||||
@ -26,6 +25,7 @@ import { Schema } from './schema';
|
|||||||
import { ensureDependencies } from '../../utils/ensure-dependencies';
|
import { ensureDependencies } from '../../utils/ensure-dependencies';
|
||||||
import { syncDeps } from '../../executors/sync-deps/sync-deps.impl';
|
import { syncDeps } from '../../executors/sync-deps/sync-deps.impl';
|
||||||
import { PackageJson } from 'nx/src/utils/package-json';
|
import { PackageJson } from 'nx/src/utils/package-json';
|
||||||
|
import { updateTsconfigFiles } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
|
||||||
export async function reactNativeApplicationGenerator(
|
export async function reactNativeApplicationGenerator(
|
||||||
host: Tree,
|
host: Tree,
|
||||||
@ -41,16 +41,16 @@ export async function reactNativeApplicationGeneratorInternal(
|
|||||||
host: Tree,
|
host: Tree,
|
||||||
schema: Schema
|
schema: Schema
|
||||||
): Promise<GeneratorCallback> {
|
): Promise<GeneratorCallback> {
|
||||||
assertNotUsingTsSolutionSetup(host, 'react-native', 'application');
|
|
||||||
|
|
||||||
const options = await normalizeOptions(host, schema);
|
|
||||||
|
|
||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
const jsInitTask = await jsInitGenerator(host, {
|
const jsInitTask = await jsInitGenerator(host, {
|
||||||
...schema,
|
...schema,
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
|
addTsPlugin: schema.useTsSolution,
|
||||||
|
formatter: schema.formatter,
|
||||||
});
|
});
|
||||||
tasks.push(jsInitTask);
|
tasks.push(jsInitTask);
|
||||||
|
|
||||||
|
const options = await normalizeOptions(host, schema);
|
||||||
const initTask = await initGenerator(host, { ...options, skipFormat: true });
|
const initTask = await initGenerator(host, { ...options, skipFormat: true });
|
||||||
tasks.push(initTask);
|
tasks.push(initTask);
|
||||||
|
|
||||||
@ -127,6 +127,22 @@ export async function reactNativeApplicationGeneratorInternal(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateTsconfigFiles(
|
||||||
|
host,
|
||||||
|
options.appProjectRoot,
|
||||||
|
'tsconfig.app.json',
|
||||||
|
{
|
||||||
|
jsx: 'react-jsx',
|
||||||
|
module: 'esnext',
|
||||||
|
moduleResolution: 'bundler',
|
||||||
|
noUnusedLocals: false,
|
||||||
|
lib: ['dom'],
|
||||||
|
},
|
||||||
|
options.linter === 'eslint'
|
||||||
|
? ['eslint.config.js', 'eslint.config.cjs', 'eslint.config.mjs']
|
||||||
|
: undefined
|
||||||
|
);
|
||||||
|
|
||||||
if (!options.skipFormat) {
|
if (!options.skipFormat) {
|
||||||
await formatFiles(host);
|
await formatFiles(host);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,15 @@
|
|||||||
import {
|
import {
|
||||||
addProjectConfiguration,
|
addProjectConfiguration,
|
||||||
|
joinPathFragments,
|
||||||
ProjectConfiguration,
|
ProjectConfiguration,
|
||||||
readNxJson,
|
readNxJson,
|
||||||
TargetConfiguration,
|
TargetConfiguration,
|
||||||
Tree,
|
Tree,
|
||||||
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { NormalizedSchema } from './normalize-options';
|
import { NormalizedSchema } from './normalize-options';
|
||||||
|
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||||
|
|
||||||
export function addProject(host: Tree, options: NormalizedSchema) {
|
export function addProject(host: Tree, options: NormalizedSchema) {
|
||||||
const nxJson = readNxJson(host);
|
const nxJson = readNxJson(host);
|
||||||
@ -23,9 +27,24 @@ export function addProject(host: Tree, options: NormalizedSchema) {
|
|||||||
tags: options.parsedTags,
|
tags: options.parsedTags,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (isUsingTsSolutionSetup(host)) {
|
||||||
|
writeJson(host, joinPathFragments(options.appProjectRoot, 'package.json'), {
|
||||||
|
name: getImportPath(host, options.name),
|
||||||
|
version: '0.0.1',
|
||||||
|
private: true,
|
||||||
|
nx: {
|
||||||
|
name: options.name,
|
||||||
|
projectType: 'application',
|
||||||
|
sourceRoot: `${options.appProjectRoot}/src`,
|
||||||
|
targets: hasPlugin ? {} : getTargets(options),
|
||||||
|
tags: options.parsedTags?.length ? options.parsedTags : undefined,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
addProjectConfiguration(host, options.projectName, {
|
addProjectConfiguration(host, options.projectName, {
|
||||||
...project,
|
...project,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTargets(options: NormalizedSchema) {
|
function getTargets(options: NormalizedSchema) {
|
||||||
|
|||||||
@ -16,6 +16,9 @@ export interface Schema {
|
|||||||
bundler: 'webpack' | 'vite'; // default is webpack
|
bundler: 'webpack' | 'vite'; // default is webpack
|
||||||
install: boolean; // default is true
|
install: boolean; // default is true
|
||||||
skipPackageJson?: boolean; //default is false
|
skipPackageJson?: boolean; //default is false
|
||||||
|
// Internal options
|
||||||
addPlugin?: boolean;
|
addPlugin?: boolean;
|
||||||
nxCloudToken?: string;
|
nxCloudToken?: string;
|
||||||
|
useTsSolution?: boolean;
|
||||||
|
formatter?: 'prettier' | 'none';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,13 +44,15 @@
|
|||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint", "none"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "none"],
|
||||||
"description": "Test runner to use for unit tests",
|
"description": "Test runner to use for unit tests",
|
||||||
"default": "jest"
|
"default": "none",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -71,7 +73,8 @@
|
|||||||
"description": "Adds the specified e2e test runner.",
|
"description": "Adds the specified e2e test runner.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["playwright", "cypress", "detox", "none"],
|
"enum": ["playwright", "cypress", "detox", "none"],
|
||||||
"default": "playwright"
|
"default": "none",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"install": {
|
"install": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import {
|
|||||||
Tree,
|
Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { addPluginV1 } from '@nx/devkit/src/utils/add-plugin';
|
import { addPluginV1 } from '@nx/devkit/src/utils/add-plugin';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
|
||||||
import { createNodes } from '../../../plugins/plugin';
|
import { createNodes } from '../../../plugins/plugin';
|
||||||
import {
|
import {
|
||||||
nxVersion,
|
nxVersion,
|
||||||
@ -31,8 +30,6 @@ export async function reactNativeInitGeneratorInternal(
|
|||||||
host: Tree,
|
host: Tree,
|
||||||
schema: Schema
|
schema: Schema
|
||||||
) {
|
) {
|
||||||
assertNotUsingTsSolutionSetup(host, 'react-native', 'init');
|
|
||||||
|
|
||||||
addGitIgnoreEntry(host);
|
addGitIgnoreEntry(host);
|
||||||
|
|
||||||
const nxJson = readNxJson(host);
|
const nxJson = readNxJson(host);
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import {
|
|||||||
ensureProjectName,
|
ensureProjectName,
|
||||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||||
import { Schema } from '../schema';
|
import { Schema } from '../schema';
|
||||||
|
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
|
||||||
export interface NormalizedSchema extends Schema {
|
export interface NormalizedSchema extends Schema {
|
||||||
name: string;
|
name: string;
|
||||||
@ -13,6 +14,7 @@ export interface NormalizedSchema extends Schema {
|
|||||||
parsedTags: string[];
|
parsedTags: string[];
|
||||||
appMain?: string;
|
appMain?: string;
|
||||||
appSourceRoot?: string;
|
appSourceRoot?: string;
|
||||||
|
isUsingTsSolutionConfig: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function normalizeOptions(
|
export async function normalizeOptions(
|
||||||
@ -50,6 +52,7 @@ export async function normalizeOptions(
|
|||||||
projectRoot,
|
projectRoot,
|
||||||
parsedTags,
|
parsedTags,
|
||||||
importPath,
|
importPath,
|
||||||
|
isUsingTsSolutionConfig: isUsingTsSolutionSetup(host),
|
||||||
};
|
};
|
||||||
|
|
||||||
return normalized;
|
return normalized;
|
||||||
|
|||||||
@ -227,6 +227,8 @@ describe('lib', () => {
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "../dist/out-tsc",
|
"outDir": "../dist/out-tsc",
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
|
"moduleResolution": "node10",
|
||||||
|
"jsx": "react-jsx",
|
||||||
"types": ["jest", "node"]
|
"types": ["jest", "node"]
|
||||||
},
|
},
|
||||||
"files": ["src/test-setup.ts"],
|
"files": ["src/test-setup.ts"],
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import {
|
|||||||
formatFiles,
|
formatFiles,
|
||||||
generateFiles,
|
generateFiles,
|
||||||
GeneratorCallback,
|
GeneratorCallback,
|
||||||
|
installPackagesTask,
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
names,
|
names,
|
||||||
offsetFromRoot,
|
offsetFromRoot,
|
||||||
@ -13,6 +14,7 @@ import {
|
|||||||
Tree,
|
Tree,
|
||||||
updateJson,
|
updateJson,
|
||||||
updateProjectConfiguration,
|
updateProjectConfiguration,
|
||||||
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -32,7 +34,11 @@ import { NormalizedSchema, normalizeOptions } from './lib/normalize-options';
|
|||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
import { ensureDependencies } from '../../utils/ensure-dependencies';
|
import { ensureDependencies } from '../../utils/ensure-dependencies';
|
||||||
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
|
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
import {
|
||||||
|
isUsingTsSolutionSetup,
|
||||||
|
updateTsconfigFiles,
|
||||||
|
} from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||||
|
|
||||||
export async function reactNativeLibraryGenerator(
|
export async function reactNativeLibraryGenerator(
|
||||||
host: Tree,
|
host: Tree,
|
||||||
@ -48,7 +54,13 @@ export async function reactNativeLibraryGeneratorInternal(
|
|||||||
host: Tree,
|
host: Tree,
|
||||||
schema: Schema
|
schema: Schema
|
||||||
): Promise<GeneratorCallback> {
|
): Promise<GeneratorCallback> {
|
||||||
assertNotUsingTsSolutionSetup(host, 'react-native', 'library');
|
const tasks: GeneratorCallback[] = [];
|
||||||
|
|
||||||
|
const jsInitTask = await jsInitGenerator(host, {
|
||||||
|
...schema,
|
||||||
|
skipFormat: true,
|
||||||
|
});
|
||||||
|
tasks.push(jsInitTask);
|
||||||
|
|
||||||
const options = await normalizeOptions(host, schema);
|
const options = await normalizeOptions(host, schema);
|
||||||
if (options.publishable === true && !schema.importPath) {
|
if (options.publishable === true && !schema.importPath) {
|
||||||
@ -57,13 +69,6 @@ export async function reactNativeLibraryGeneratorInternal(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const tasks: GeneratorCallback[] = [];
|
|
||||||
|
|
||||||
const jsInitTask = await jsInitGenerator(host, {
|
|
||||||
...schema,
|
|
||||||
skipFormat: true,
|
|
||||||
});
|
|
||||||
tasks.push(jsInitTask);
|
|
||||||
const initTask = await init(host, { ...options, skipFormat: true });
|
const initTask = await init(host, { ...options, skipFormat: true });
|
||||||
tasks.push(initTask);
|
tasks.push(initTask);
|
||||||
|
|
||||||
@ -111,11 +116,29 @@ export async function reactNativeLibraryGeneratorInternal(
|
|||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
updateTsconfigFiles(
|
||||||
|
host,
|
||||||
|
options.projectRoot,
|
||||||
|
'tsconfig.lib.json',
|
||||||
|
{
|
||||||
|
jsx: 'react-jsx',
|
||||||
|
module: 'esnext',
|
||||||
|
moduleResolution: 'bundler',
|
||||||
|
},
|
||||||
|
options.linter === 'eslint'
|
||||||
|
? ['eslint.config.js', 'eslint.config.cjs', 'eslint.config.mjs']
|
||||||
|
: undefined
|
||||||
|
);
|
||||||
|
|
||||||
if (!options.skipFormat) {
|
if (!options.skipFormat) {
|
||||||
await formatFiles(host);
|
await formatFiles(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Always run install to link packages.
|
||||||
|
if (options.isUsingTsSolutionConfig) {
|
||||||
|
tasks.push(() => installPackagesTask(host));
|
||||||
|
}
|
||||||
|
|
||||||
tasks.push(() => {
|
tasks.push(() => {
|
||||||
logShowProjectCommand(options.name);
|
logShowProjectCommand(options.name);
|
||||||
});
|
});
|
||||||
@ -135,7 +158,27 @@ async function addProject(
|
|||||||
targets: {},
|
targets: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (options.isUsingTsSolutionConfig) {
|
||||||
|
const sourceEntry = !options.buildable
|
||||||
|
? options.js
|
||||||
|
? './src/index.js'
|
||||||
|
: './src/index.ts'
|
||||||
|
: undefined;
|
||||||
|
writeJson(host, joinPathFragments(options.projectRoot, 'package.json'), {
|
||||||
|
name: getImportPath(host, options.name),
|
||||||
|
version: '0.0.1',
|
||||||
|
main: sourceEntry,
|
||||||
|
types: sourceEntry,
|
||||||
|
nx: {
|
||||||
|
name: options.name,
|
||||||
|
sourceRoot: joinPathFragments(options.projectRoot, 'src'),
|
||||||
|
projectType: 'library',
|
||||||
|
tags: options.parsedTags?.length ? options.parsedTags : undefined,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
addProjectConfiguration(host, options.name, project);
|
addProjectConfiguration(host, options.name, project);
|
||||||
|
}
|
||||||
|
|
||||||
if (!options.publishable && !options.buildable) {
|
if (!options.publishable && !options.buildable) {
|
||||||
return () => {};
|
return () => {};
|
||||||
|
|||||||
@ -32,13 +32,16 @@
|
|||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint", "none"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "none"],
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"default": "jest"
|
"default": "none",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -12,7 +12,11 @@ import {
|
|||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { hasWebpackPlugin } from '@nx/react/src/utils/has-webpack-plugin';
|
import { hasWebpackPlugin } from '@nx/react/src/utils/has-webpack-plugin';
|
||||||
|
|
||||||
import { nxVersion, reactNativeWebVersion } from '../../utils/versions';
|
import {
|
||||||
|
nxVersion,
|
||||||
|
reactNativeWebVersion,
|
||||||
|
typesReactDomVersion,
|
||||||
|
} from '../../utils/versions';
|
||||||
import { NormalizedSchema, normalizeSchema } from './lib/normalize-schema';
|
import { NormalizedSchema, normalizeSchema } from './lib/normalize-schema';
|
||||||
import {
|
import {
|
||||||
createBuildTarget,
|
createBuildTarget,
|
||||||
@ -77,6 +81,18 @@ export async function webConfigurationGenerator(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!options.skipPackageJson) {
|
||||||
|
tasks.push(
|
||||||
|
addDependenciesToPackageJson(
|
||||||
|
tree,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
'@types/react-dom': typesReactDomVersion,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!options.skipFormat) {
|
if (!options.skipFormat) {
|
||||||
await formatFiles(tree);
|
await formatFiles(tree);
|
||||||
}
|
}
|
||||||
@ -103,6 +119,7 @@ async function addBundlerConfiguration(
|
|||||||
project: normalizedSchema.project,
|
project: normalizedSchema.project,
|
||||||
newProject: true,
|
newProject: true,
|
||||||
includeVitest: false,
|
includeVitest: false,
|
||||||
|
projectType: 'application',
|
||||||
compiler: 'babel',
|
compiler: 'babel',
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -14,6 +14,7 @@ export const reactVersion = '18.2.0';
|
|||||||
export const reactDomVersion = '18.2.0';
|
export const reactDomVersion = '18.2.0';
|
||||||
export const reactTestRendererVersion = '18.2.0';
|
export const reactTestRendererVersion = '18.2.0';
|
||||||
export const typesReactVersion = '~18.2.45';
|
export const typesReactVersion = '~18.2.45';
|
||||||
|
export const typesReactDomVersion = '18.3.0';
|
||||||
|
|
||||||
export const testingLibraryReactNativeVersion = '~12.5.0';
|
export const testingLibraryReactNativeVersion = '~12.5.0';
|
||||||
export const testingLibraryJestNativeVersion = '~5.4.3';
|
export const testingLibraryJestNativeVersion = '~5.4.3';
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`app --minimal should create default application without Nx welcome component 1`] = `
|
exports[`app --minimal should create default application without Nx welcome component 1`] = `
|
||||||
"// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
"// Uncomment this line to use CSS modules
|
||||||
import styles from './app.module.css';
|
// import styles from './app.module.css';
|
||||||
|
|
||||||
export function App() {
|
export function App() {
|
||||||
return (
|
return (
|
||||||
@ -239,8 +239,8 @@ export default defineConfig({
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`app not nested should generate files 1`] = `
|
exports[`app not nested should generate files 1`] = `
|
||||||
"// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
"// Uncomment this line to use CSS modules
|
||||||
import styles from './app.module.css';
|
// import styles from './app.module.css';
|
||||||
import NxWelcome from './nx-welcome';
|
import NxWelcome from './nx-welcome';
|
||||||
|
|
||||||
export function App() {
|
export function App() {
|
||||||
@ -343,8 +343,8 @@ module.exports = {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`app should create Nx specific template 1`] = `
|
exports[`app should create Nx specific template 1`] = `
|
||||||
"// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
"// Uncomment this line to use CSS modules
|
||||||
import styles from './app.module.css';
|
// import styles from './app.module.css';
|
||||||
import NxWelcome from "./nx-welcome";
|
import NxWelcome from "./nx-welcome";
|
||||||
|
|
||||||
export function App() {
|
export function App() {
|
||||||
|
|||||||
@ -7,7 +7,9 @@ import {
|
|||||||
readJson,
|
readJson,
|
||||||
readNxJson,
|
readNxJson,
|
||||||
Tree,
|
Tree,
|
||||||
|
updateJson,
|
||||||
updateNxJson,
|
updateNxJson,
|
||||||
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||||
import { Linter } from '@nx/eslint';
|
import { Linter } from '@nx/eslint';
|
||||||
@ -276,7 +278,6 @@ describe('app', () => {
|
|||||||
expect(tsconfigApp.compilerOptions.outDir).toEqual('../dist/out-tsc');
|
expect(tsconfigApp.compilerOptions.outDir).toEqual('../dist/out-tsc');
|
||||||
expect(tsconfigApp.extends).toEqual('./tsconfig.json');
|
expect(tsconfigApp.extends).toEqual('./tsconfig.json');
|
||||||
expect(tsconfigApp.exclude).toEqual([
|
expect(tsconfigApp.exclude).toEqual([
|
||||||
'jest.config.ts',
|
|
||||||
'src/**/*.spec.ts',
|
'src/**/*.spec.ts',
|
||||||
'src/**/*.test.ts',
|
'src/**/*.test.ts',
|
||||||
'src/**/*.spec.tsx',
|
'src/**/*.spec.tsx',
|
||||||
@ -285,6 +286,7 @@ describe('app', () => {
|
|||||||
'src/**/*.test.js',
|
'src/**/*.test.js',
|
||||||
'src/**/*.spec.jsx',
|
'src/**/*.spec.jsx',
|
||||||
'src/**/*.test.jsx',
|
'src/**/*.test.jsx',
|
||||||
|
'jest.config.ts',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const eslintJson = readJson(appTree, 'my-app/.eslintrc.json');
|
const eslintJson = readJson(appTree, 'my-app/.eslintrc.json');
|
||||||
@ -414,7 +416,6 @@ describe('app', () => {
|
|||||||
path: 'my-dir/my-app/tsconfig.app.json',
|
path: 'my-dir/my-app/tsconfig.app.json',
|
||||||
lookupFn: (json) => json.exclude,
|
lookupFn: (json) => json.exclude,
|
||||||
expectedValue: [
|
expectedValue: [
|
||||||
'jest.config.ts',
|
|
||||||
'src/**/*.spec.ts',
|
'src/**/*.spec.ts',
|
||||||
'src/**/*.test.ts',
|
'src/**/*.test.ts',
|
||||||
'src/**/*.spec.tsx',
|
'src/**/*.spec.tsx',
|
||||||
@ -423,6 +424,7 @@ describe('app', () => {
|
|||||||
'src/**/*.test.js',
|
'src/**/*.test.js',
|
||||||
'src/**/*.spec.jsx',
|
'src/**/*.spec.jsx',
|
||||||
'src/**/*.test.jsx',
|
'src/**/*.test.jsx',
|
||||||
|
'jest.config.ts',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -1241,4 +1243,180 @@ describe('app', () => {
|
|||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('TS solution setup', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
appTree = createTreeWithEmptyWorkspace();
|
||||||
|
updateJson(appTree, 'package.json', (json) => {
|
||||||
|
json.workspaces = ['packages/*', 'apps/*'];
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
writeJson(appTree, 'tsconfig.base.json', {
|
||||||
|
compilerOptions: {
|
||||||
|
composite: true,
|
||||||
|
declaration: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
writeJson(appTree, 'tsconfig.json', {
|
||||||
|
extends: './tsconfig.base.json',
|
||||||
|
files: [],
|
||||||
|
references: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add project references when using TS solution', async () => {
|
||||||
|
await applicationGenerator(appTree, {
|
||||||
|
directory: 'myapp',
|
||||||
|
addPlugin: true,
|
||||||
|
linter: Linter.EsLint,
|
||||||
|
style: 'none',
|
||||||
|
bundler: 'vite',
|
||||||
|
unitTestRunner: 'vitest',
|
||||||
|
e2eTestRunner: 'playwright',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(readJson(appTree, 'tsconfig.json').references)
|
||||||
|
.toMatchInlineSnapshot(`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"path": "./myapp-e2e",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./myapp",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
expect(readJson(appTree, 'myapp/tsconfig.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"files": [],
|
||||||
|
"include": [],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.app.json",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.spec.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(appTree, 'myapp/tsconfig.app.json'))
|
||||||
|
.toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
],
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"outDir": "out-tsc/myapp",
|
||||||
|
"rootDir": "src",
|
||||||
|
"tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo",
|
||||||
|
"types": [
|
||||||
|
"node",
|
||||||
|
"@nx/react/typings/cssmodule.d.ts",
|
||||||
|
"@nx/react/typings/image.d.ts",
|
||||||
|
"vite/client",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"dist",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"src/**/*.spec.tsx",
|
||||||
|
"src/**/*.test.tsx",
|
||||||
|
"src/**/*.spec.js",
|
||||||
|
"src/**/*.test.js",
|
||||||
|
"src/**/*.spec.jsx",
|
||||||
|
"src/**/*.test.jsx",
|
||||||
|
"vite.config.ts",
|
||||||
|
"vite.config.mts",
|
||||||
|
"vitest.config.ts",
|
||||||
|
"vitest.config.mts",
|
||||||
|
],
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
"src/**/*.js",
|
||||||
|
"src/**/*.jsx",
|
||||||
|
"src/**/*.ts",
|
||||||
|
"src/**/*.tsx",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(appTree, 'myapp/tsconfig.spec.json'))
|
||||||
|
.toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"outDir": "./out-tsc/vitest",
|
||||||
|
"types": [
|
||||||
|
"vitest/globals",
|
||||||
|
"vitest/importMeta",
|
||||||
|
"vite/client",
|
||||||
|
"node",
|
||||||
|
"vitest",
|
||||||
|
"@nx/react/typings/cssmodule.d.ts",
|
||||||
|
"@nx/react/typings/image.d.ts",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
"vite.config.ts",
|
||||||
|
"vite.config.mts",
|
||||||
|
"vitest.config.ts",
|
||||||
|
"vitest.config.mts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.test.tsx",
|
||||||
|
"src/**/*.spec.tsx",
|
||||||
|
"src/**/*.test.js",
|
||||||
|
"src/**/*.spec.js",
|
||||||
|
"src/**/*.test.jsx",
|
||||||
|
"src/**/*.spec.jsx",
|
||||||
|
"src/**/*.d.ts",
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.app.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(appTree, 'myapp-e2e/tsconfig.json'))
|
||||||
|
.toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"allowJs": true,
|
||||||
|
"outDir": "dist",
|
||||||
|
"sourceMap": false,
|
||||||
|
"tsBuildInfoFile": "dist/tsconfig.tsbuildinfo",
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"dist",
|
||||||
|
"eslint.config.js",
|
||||||
|
],
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.js",
|
||||||
|
"playwright.config.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.spec.js",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"src/**/*.test.js",
|
||||||
|
"src/**/*.d.ts",
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "../myapp",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -21,14 +21,9 @@ import {
|
|||||||
Tree,
|
Tree,
|
||||||
updateNxJson,
|
updateNxJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
|
|
||||||
import reactInitGenerator from '../init/init';
|
import reactInitGenerator from '../init/init';
|
||||||
import { Linter, lintProjectGenerator } from '@nx/eslint';
|
import { Linter, lintProjectGenerator } from '@nx/eslint';
|
||||||
import {
|
import { babelLoaderVersion, nxVersion } from '../../utils/versions';
|
||||||
babelLoaderVersion,
|
|
||||||
nxRspackVersion,
|
|
||||||
nxVersion,
|
|
||||||
} from '../../utils/versions';
|
|
||||||
import { maybeJs } from '../../utils/maybe-js';
|
import { maybeJs } from '../../utils/maybe-js';
|
||||||
import { installCommonDependencies } from './lib/install-common-dependencies';
|
import { installCommonDependencies } from './lib/install-common-dependencies';
|
||||||
import { extractTsConfigBase } from '../../utils/create-ts-config';
|
import { extractTsConfigBase } from '../../utils/create-ts-config';
|
||||||
@ -46,7 +41,7 @@ import { initGenerator as jsInitGenerator } from '@nx/js';
|
|||||||
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
|
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
|
||||||
import { setupTailwindGenerator } from '../setup-tailwind/setup-tailwind';
|
import { setupTailwindGenerator } from '../setup-tailwind/setup-tailwind';
|
||||||
import { useFlatConfig } from '@nx/eslint/src/utils/flat-config';
|
import { useFlatConfig } from '@nx/eslint/src/utils/flat-config';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
import { updateTsconfigFiles } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
|
||||||
async function addLinting(host: Tree, options: NormalizedSchema) {
|
async function addLinting(host: Tree, options: NormalizedSchema) {
|
||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
@ -114,20 +109,20 @@ export async function applicationGeneratorInternal(
|
|||||||
host: Tree,
|
host: Tree,
|
||||||
schema: Schema
|
schema: Schema
|
||||||
): Promise<GeneratorCallback> {
|
): Promise<GeneratorCallback> {
|
||||||
assertNotUsingTsSolutionSetup(host, 'react', 'application');
|
|
||||||
|
|
||||||
const tasks = [];
|
const tasks = [];
|
||||||
|
|
||||||
const options = await normalizeOptions(host, schema);
|
|
||||||
showPossibleWarnings(host, options);
|
|
||||||
|
|
||||||
const jsInitTask = await jsInitGenerator(host, {
|
const jsInitTask = await jsInitGenerator(host, {
|
||||||
...schema,
|
...schema,
|
||||||
tsConfigName: schema.rootProject ? 'tsconfig.json' : 'tsconfig.base.json',
|
tsConfigName: schema.rootProject ? 'tsconfig.json' : 'tsconfig.base.json',
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
|
addTsPlugin: schema.useTsSolution,
|
||||||
|
formatter: schema.formatter,
|
||||||
});
|
});
|
||||||
tasks.push(jsInitTask);
|
tasks.push(jsInitTask);
|
||||||
|
|
||||||
|
const options = await normalizeOptions(host, schema);
|
||||||
|
showPossibleWarnings(host, options);
|
||||||
|
|
||||||
const initTask = await reactInitGenerator(host, {
|
const initTask = await reactInitGenerator(host, {
|
||||||
...options,
|
...options,
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
@ -165,10 +160,7 @@ export async function applicationGeneratorInternal(
|
|||||||
tasks.push(ensureDependencies(host, { uiFramework: 'react' }));
|
tasks.push(ensureDependencies(host, { uiFramework: 'react' }));
|
||||||
}
|
}
|
||||||
} else if (options.bundler === 'rspack') {
|
} else if (options.bundler === 'rspack') {
|
||||||
const { rspackInitGenerator } = ensurePackage(
|
const { rspackInitGenerator } = ensurePackage('@nx/rspack', nxVersion);
|
||||||
'@nx/rspack',
|
|
||||||
nxRspackVersion
|
|
||||||
);
|
|
||||||
const rspackInitTask = await rspackInitGenerator(host, {
|
const rspackInitTask = await rspackInitGenerator(host, {
|
||||||
...options,
|
...options,
|
||||||
addPlugin: false,
|
addPlugin: false,
|
||||||
@ -213,6 +205,7 @@ export async function applicationGeneratorInternal(
|
|||||||
compiler: options.compiler,
|
compiler: options.compiler,
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
addPlugin: options.addPlugin,
|
addPlugin: options.addPlugin,
|
||||||
|
projectType: 'application',
|
||||||
});
|
});
|
||||||
tasks.push(viteTask);
|
tasks.push(viteTask);
|
||||||
createOrEditViteConfig(
|
createOrEditViteConfig(
|
||||||
@ -236,6 +229,26 @@ export async function applicationGeneratorInternal(
|
|||||||
},
|
},
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
} else if (options.bundler === 'rspack') {
|
||||||
|
const { configurationGenerator } = ensurePackage('@nx/rspack', nxVersion);
|
||||||
|
const rspackTask = await configurationGenerator(host, {
|
||||||
|
project: options.projectName,
|
||||||
|
main: joinPathFragments(
|
||||||
|
options.appProjectRoot,
|
||||||
|
maybeJs(
|
||||||
|
{
|
||||||
|
js: options.js,
|
||||||
|
useJsx: true,
|
||||||
|
},
|
||||||
|
`src/main.tsx`
|
||||||
|
)
|
||||||
|
),
|
||||||
|
tsConfig: joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'),
|
||||||
|
target: 'web',
|
||||||
|
newProject: true,
|
||||||
|
framework: 'react',
|
||||||
|
});
|
||||||
|
tasks.push(rspackTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.bundler !== 'vite' && options.unitTestRunner === 'vitest') {
|
if (options.bundler !== 'vite' && options.unitTestRunner === 'vitest') {
|
||||||
@ -348,6 +361,12 @@ export async function applicationGeneratorInternal(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateTsconfigFiles(host, options.appProjectRoot, 'tsconfig.app.json', {
|
||||||
|
jsx: 'react-jsx',
|
||||||
|
module: 'esnext',
|
||||||
|
moduleResolution: 'bundler',
|
||||||
|
});
|
||||||
|
|
||||||
if (!options.skipFormat) {
|
if (!options.skipFormat) {
|
||||||
await formatFiles(host);
|
await formatFiles(host);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,31 @@
|
|||||||
{
|
<%_ if (isUsingTsSolutionSetup) { _%>{
|
||||||
|
"extends": "<%= offsetFromRoot%>tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "dist",
|
||||||
|
"tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo",
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"lib": ["dom"],
|
||||||
|
"types": [
|
||||||
|
"node",
|
||||||
|
<%_ if (style === 'styled-jsx') { _%>"@nx/react/typings/styled-jsx.d.ts",<%_ } _%>
|
||||||
|
"@nx/react/typings/cssmodule.d.ts",
|
||||||
|
"@nx/react/typings/image.d.ts"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"exclude": ["src/**/*.spec.ts", "src/**/*.test.ts", "src/**/*.spec.tsx", "src/**/*.test.tsx", "src/**/*.spec.js", "src/**/*.test.js", "src/**/*.spec.jsx", "src/**/*.test.jsx"],
|
||||||
|
"include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
|
||||||
|
}<% } else { %>{
|
||||||
"extends": "./tsconfig.json",
|
"extends": "./tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "<%= offsetFromRoot %>dist/out-tsc",
|
"outDir": "<%= offsetFromRoot %>dist/out-tsc",
|
||||||
"types": [
|
"types": [
|
||||||
"node",
|
"node",
|
||||||
<%_ if (style === 'styled-jsx') { %>"@nx/react/typings/styled-jsx.d.ts",<% } _%>
|
<%_ if (style === 'styled-jsx') { _%>"@nx/react/typings/styled-jsx.d.ts",<%_ } _%>
|
||||||
"@nx/react/typings/cssmodule.d.ts",
|
"@nx/react/typings/cssmodule.d.ts",
|
||||||
"@nx/react/typings/image.d.ts"
|
"@nx/react/typings/image.d.ts"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"exclude": ["jest.config.ts","src/**/*.spec.ts", "src/**/*.test.ts", "src/**/*.spec.tsx", "src/**/*.test.tsx", "src/**/*.spec.js", "src/**/*.test.js", "src/**/*.spec.jsx", "src/**/*.test.jsx"],
|
"exclude": ["src/**/*.spec.ts", "src/**/*.test.ts", "src/**/*.spec.tsx", "src/**/*.test.tsx", "src/**/*.spec.js", "src/**/*.test.js", "src/**/*.spec.jsx", "src/**/*.test.jsx"],
|
||||||
"include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
|
"include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
|
||||||
}
|
}
|
||||||
|
<% } %>
|
||||||
|
|||||||
@ -1,4 +1,20 @@
|
|||||||
{
|
<%_ if (isUsingTsSolutionSetup) { _%>{
|
||||||
|
"extends": "<%= offsetFromRoot%>tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "dist",
|
||||||
|
"tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo",
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"lib": ["dom"],
|
||||||
|
"types": [
|
||||||
|
"node",
|
||||||
|
<%_ if (style === 'styled-jsx') { _%>"@nx/react/typings/styled-jsx.d.ts",<%_ } _%>
|
||||||
|
"@nx/react/typings/cssmodule.d.ts",
|
||||||
|
"@nx/react/typings/image.d.ts"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"exclude": ["src/**/*.spec.ts", "src/**/*.test.ts", "src/**/*.spec.tsx", "src/**/*.test.tsx", "src/**/*.spec.js", "src/**/*.test.js", "src/**/*.spec.jsx", "src/**/*.test.jsx"],
|
||||||
|
"include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
|
||||||
|
}<% } else { %>{
|
||||||
"extends": "./tsconfig.json",
|
"extends": "./tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "<%= offsetFromRoot %>dist/out-tsc",
|
"outDir": "<%= offsetFromRoot %>dist/out-tsc",
|
||||||
@ -12,3 +28,4 @@
|
|||||||
"exclude": ["src/**/*.spec.ts", "src/**/*.test.ts", "src/**/*.spec.tsx", "src/**/*.test.tsx", "src/**/*.spec.js", "src/**/*.test.js", "src/**/*.spec.jsx", "src/**/*.test.jsx"],
|
"exclude": ["src/**/*.spec.ts", "src/**/*.test.ts", "src/**/*.spec.tsx", "src/**/*.test.tsx", "src/**/*.spec.js", "src/**/*.test.js", "src/**/*.spec.jsx", "src/**/*.test.jsx"],
|
||||||
"include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
|
"include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
|
||||||
}
|
}
|
||||||
|
<% } %>
|
||||||
|
|||||||
@ -1,4 +1,20 @@
|
|||||||
{
|
<%_ if (isUsingTsSolutionSetup) { _%>{
|
||||||
|
"extends": "<%= offsetFromRoot%>tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "dist",
|
||||||
|
"tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo",
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"lib": ["dom"],
|
||||||
|
"types": [
|
||||||
|
"node",
|
||||||
|
<%_ if (style === 'styled-jsx') { _%>"@nx/react/typings/styled-jsx.d.ts",<%_ } _%>
|
||||||
|
"@nx/react/typings/cssmodule.d.ts",
|
||||||
|
"@nx/react/typings/image.d.ts"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"exclude": ["src/**/*.spec.ts", "src/**/*.test.ts", "src/**/*.spec.tsx", "src/**/*.test.tsx", "src/**/*.spec.js", "src/**/*.test.js", "src/**/*.spec.jsx", "src/**/*.test.jsx"],
|
||||||
|
"include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
|
||||||
|
}<% } else { %>{
|
||||||
"extends": "./tsconfig.json",
|
"extends": "./tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "<%= offsetFromRoot %>dist/out-tsc",
|
"outDir": "<%= offsetFromRoot %>dist/out-tsc",
|
||||||
@ -9,6 +25,7 @@
|
|||||||
"@nx/react/typings/image.d.ts"
|
"@nx/react/typings/image.d.ts"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"exclude": ["jest.config.ts","src/**/*.spec.ts", "src/**/*.test.ts", "src/**/*.spec.tsx", "src/**/*.test.tsx", "src/**/*.spec.js", "src/**/*.test.js", "src/**/*.spec.jsx", "src/**/*.test.jsx"],
|
"exclude": ["src/**/*.spec.ts", "src/**/*.test.ts", "src/**/*.spec.tsx", "src/**/*.test.tsx", "src/**/*.spec.js", "src/**/*.test.js", "src/**/*.spec.jsx", "src/**/*.test.jsx"],
|
||||||
"include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
|
"include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
|
||||||
}
|
}
|
||||||
|
<% } %>
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
<% if (classComponent) { %>
|
<% if (classComponent) { %>
|
||||||
import { Component } from 'react';
|
import { Component } from 'react';
|
||||||
<%_ } _%>
|
<%_ } _%>
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// Uncomment this line to use CSS modules
|
||||||
import styles from './<%= fileName %>.module.<%= style %>';
|
// import styles from './<%= fileName %>.module.<%= style %>';
|
||||||
<%_ if (!minimal) { _%>
|
<%_ if (!minimal) { _%>
|
||||||
import NxWelcome from "./nx-welcome";
|
import NxWelcome from "./nx-welcome";
|
||||||
<%_ } _%>
|
<%_ } _%>
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
import type { GeneratorCallback, Tree } from '@nx/devkit';
|
|
||||||
import {
|
import {
|
||||||
addProjectConfiguration,
|
addProjectConfiguration,
|
||||||
ensurePackage,
|
ensurePackage,
|
||||||
|
GeneratorCallback,
|
||||||
getPackageManagerCommand,
|
getPackageManagerCommand,
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
readNxJson,
|
readNxJson,
|
||||||
|
Tree,
|
||||||
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { webStaticServeGenerator } from '@nx/web';
|
import { webStaticServeGenerator } from '@nx/web';
|
||||||
|
|
||||||
@ -81,6 +83,22 @@ export async function addE2e(
|
|||||||
typeof import('@nx/cypress')
|
typeof import('@nx/cypress')
|
||||||
>('@nx/cypress', nxVersion);
|
>('@nx/cypress', nxVersion);
|
||||||
|
|
||||||
|
if (options.isUsingTsSolutionConfig) {
|
||||||
|
writeJson(
|
||||||
|
tree,
|
||||||
|
joinPathFragments(options.e2eProjectRoot, 'package.json'),
|
||||||
|
{
|
||||||
|
name: options.e2eProjectName,
|
||||||
|
version: '0.0.1',
|
||||||
|
private: true,
|
||||||
|
nx: {
|
||||||
|
projectType: 'application',
|
||||||
|
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
||||||
|
implicitDependencies: [options.projectName],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
addProjectConfiguration(tree, options.e2eProjectName, {
|
addProjectConfiguration(tree, options.e2eProjectName, {
|
||||||
projectType: 'application',
|
projectType: 'application',
|
||||||
root: options.e2eProjectRoot,
|
root: options.e2eProjectRoot,
|
||||||
@ -89,6 +107,7 @@ export async function addE2e(
|
|||||||
implicitDependencies: [options.projectName],
|
implicitDependencies: [options.projectName],
|
||||||
tags: [],
|
tags: [],
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const e2eTask = await configurationGenerator(tree, {
|
const e2eTask = await configurationGenerator(tree, {
|
||||||
...options,
|
...options,
|
||||||
@ -157,6 +176,22 @@ export async function addE2e(
|
|||||||
const { configurationGenerator } = ensurePackage<
|
const { configurationGenerator } = ensurePackage<
|
||||||
typeof import('@nx/playwright')
|
typeof import('@nx/playwright')
|
||||||
>('@nx/playwright', nxVersion);
|
>('@nx/playwright', nxVersion);
|
||||||
|
if (options.isUsingTsSolutionConfig) {
|
||||||
|
writeJson(
|
||||||
|
tree,
|
||||||
|
joinPathFragments(options.e2eProjectRoot, 'package.json'),
|
||||||
|
{
|
||||||
|
name: options.e2eProjectName,
|
||||||
|
version: '0.0.1',
|
||||||
|
private: true,
|
||||||
|
nx: {
|
||||||
|
projectType: 'application',
|
||||||
|
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
||||||
|
implicitDependencies: [options.projectName],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
addProjectConfiguration(tree, options.e2eProjectName, {
|
addProjectConfiguration(tree, options.e2eProjectName, {
|
||||||
projectType: 'application',
|
projectType: 'application',
|
||||||
root: options.e2eProjectRoot,
|
root: options.e2eProjectRoot,
|
||||||
@ -164,6 +199,8 @@ export async function addE2e(
|
|||||||
targets: {},
|
targets: {},
|
||||||
implicitDependencies: [options.projectName],
|
implicitDependencies: [options.projectName],
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const e2eTask = await configurationGenerator(tree, {
|
const e2eTask = await configurationGenerator(tree, {
|
||||||
project: options.e2eProjectName,
|
project: options.e2eProjectName,
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
|
|||||||
@ -23,5 +23,6 @@ export async function addJest(
|
|||||||
setupFile: 'none',
|
setupFile: 'none',
|
||||||
compiler: options.compiler,
|
compiler: options.compiler,
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
|
runtimeTsconfigFileName: 'tsconfig.app.json',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,10 +5,12 @@ import {
|
|||||||
ProjectConfiguration,
|
ProjectConfiguration,
|
||||||
TargetConfiguration,
|
TargetConfiguration,
|
||||||
Tree,
|
Tree,
|
||||||
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { hasWebpackPlugin } from '../../../utils/has-webpack-plugin';
|
import { hasWebpackPlugin } from '../../../utils/has-webpack-plugin';
|
||||||
import { maybeJs } from '../../../utils/maybe-js';
|
import { maybeJs } from '../../../utils/maybe-js';
|
||||||
import { hasRspackPlugin } from '../../../utils/has-rspack-plugin';
|
import { hasRspackPlugin } from '../../../utils/has-rspack-plugin';
|
||||||
|
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||||
|
|
||||||
export function addProject(host: Tree, options: NormalizedSchema) {
|
export function addProject(host: Tree, options: NormalizedSchema) {
|
||||||
const project: ProjectConfiguration = {
|
const project: ProjectConfiguration = {
|
||||||
@ -36,9 +38,25 @@ export function addProject(host: Tree, options: NormalizedSchema) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.isUsingTsSolutionConfig) {
|
||||||
|
writeJson(host, joinPathFragments(options.appProjectRoot, 'package.json'), {
|
||||||
|
name: getImportPath(host, options.name),
|
||||||
|
version: '0.0.1',
|
||||||
|
private: true,
|
||||||
|
nx: {
|
||||||
|
name: options.name,
|
||||||
|
projectType: 'application',
|
||||||
|
sourceRoot: `${options.appProjectRoot}/src`,
|
||||||
|
tags: options.parsedTags?.length ? options.parsedTags : undefined,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options.isUsingTsSolutionConfig || options.alwaysGenerateProjectJson) {
|
||||||
addProjectConfiguration(host, options.projectName, {
|
addProjectConfiguration(host, options.projectName, {
|
||||||
...project,
|
...project,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createRspackBuildTarget(
|
function createRspackBuildTarget(
|
||||||
|
|||||||
@ -18,10 +18,11 @@ import { hasWebpackPlugin } from '../../../utils/has-webpack-plugin';
|
|||||||
import { NormalizedSchema } from '../schema';
|
import { NormalizedSchema } from '../schema';
|
||||||
import { getAppTests } from './get-app-tests';
|
import { getAppTests } from './get-app-tests';
|
||||||
import {
|
import {
|
||||||
getNxCloudAppOnBoardingUrl,
|
|
||||||
createNxCloudOnboardingURLForWelcomeApp,
|
createNxCloudOnboardingURLForWelcomeApp,
|
||||||
|
getNxCloudAppOnBoardingUrl,
|
||||||
} from 'nx/src/nx-cloud/utilities/onboarding';
|
} from 'nx/src/nx-cloud/utilities/onboarding';
|
||||||
import { hasRspackPlugin } from '../../../utils/has-rspack-plugin';
|
import { hasRspackPlugin } from '../../../utils/has-rspack-plugin';
|
||||||
|
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
|
||||||
export async function createApplicationFiles(
|
export async function createApplicationFiles(
|
||||||
host: Tree,
|
host: Tree,
|
||||||
@ -67,6 +68,7 @@ export async function createApplicationFiles(
|
|||||||
inSourceVitestTests: getInSourceVitestTestsTemplate(appTests),
|
inSourceVitestTests: getInSourceVitestTestsTemplate(appTests),
|
||||||
style: options.style === 'tailwind' ? 'css' : options.style,
|
style: options.style === 'tailwind' ? 'css' : options.style,
|
||||||
hasStyleFile,
|
hasStyleFile,
|
||||||
|
isUsingTsSolutionSetup: isUsingTsSolutionSetup(host),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (options.bundler === 'vite') {
|
if (options.bundler === 'vite') {
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import {
|
|||||||
import { assertValidStyle } from '../../../utils/assertion';
|
import { assertValidStyle } from '../../../utils/assertion';
|
||||||
import { NormalizedSchema, Schema } from '../schema';
|
import { NormalizedSchema, Schema } from '../schema';
|
||||||
import { findFreePort } from './find-free-port';
|
import { findFreePort } from './find-free-port';
|
||||||
|
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
|
||||||
export function normalizeDirectory(options: Schema) {
|
export function normalizeDirectory(options: Schema) {
|
||||||
options.directory = options.directory?.replace(/\\{1,2}/g, '/');
|
options.directory = options.directory?.replace(/\\{1,2}/g, '/');
|
||||||
@ -67,6 +68,7 @@ export async function normalizeOptions<T extends Schema = Schema>(
|
|||||||
fileName,
|
fileName,
|
||||||
styledModule,
|
styledModule,
|
||||||
hasStyles: options.style !== 'none',
|
hasStyles: options.style !== 'none',
|
||||||
|
isUsingTsSolutionConfig: isUsingTsSolutionSetup(host),
|
||||||
} as NormalizedSchema;
|
} as NormalizedSchema;
|
||||||
|
|
||||||
normalized.routing = normalized.routing ?? false;
|
normalized.routing = normalized.routing ?? false;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user