feat(core): split nx config to project files (#5880)

This commit is contained in:
Craigory V Coppola 2021-06-22 19:30:38 -05:00 committed by GitHub
parent a7edd3cc70
commit f1911a71f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
170 changed files with 1874 additions and 288 deletions

View File

@ -128,6 +128,14 @@ Type: `boolean`
Skip creating spec files. Skip creating spec files.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### strict ### strict
Default: `true` Default: `true`

View File

@ -150,6 +150,14 @@ Type: `boolean`
Do not update tsconfig.json for development experience. Do not update tsconfig.json for development experience.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### strict ### strict
Default: `true` Default: `true`

View File

@ -98,6 +98,14 @@ Type: `boolean`
Do not add dependencies to package.json. Do not add dependencies to package.json.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### tags ### tags
Type: `string` Type: `string`

View File

@ -66,6 +66,14 @@ Type: `boolean`
Whether or not to configure the ESLint "parserOptions.project" option. We do not do this by default for lint performance reasons. Whether or not to configure the ESLint "parserOptions.project" option. We do not do this by default for lint performance reasons.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### style ### style
Alias(es): s Alias(es): s

View File

@ -72,6 +72,14 @@ Type: `boolean`
Do not add dependencies to package.json. Do not add dependencies to package.json.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### tags ### tags
Type: `string` Type: `string`

View File

@ -108,6 +108,14 @@ Type: `boolean`
Skip updating workspace.json with default options based on values provided to this app (e.g. babel, style) Skip updating workspace.json with default options based on values provided to this app (e.g. babel, style)
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### style ### style
Alias(es): s Alias(es): s

View File

@ -106,6 +106,14 @@ Type: `boolean`
Do not add dependencies to package.json. Do not add dependencies to package.json.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### tags ### tags
Type: `string` Type: `string`

View File

@ -138,6 +138,14 @@ Type: `boolean`
Do not update tsconfig.base.json for development experience. Do not update tsconfig.base.json for development experience.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### strict ### strict
Default: `false` Default: `false`

View File

@ -473,7 +473,7 @@ Callback to install dependencies only if necessary. undefined is returned if cha
### addProjectConfiguration ### addProjectConfiguration
**addProjectConfiguration**(`host`: [_Tree_](../../angular/nx-devkit/index#tree), `projectName`: _string_, `projectConfiguration`: [_ProjectConfiguration_](../../angular/nx-devkit/index#projectconfiguration) & [_NxJsonProjectConfiguration_](../../angular/nx-devkit/index#nxjsonprojectconfiguration)): _void_ **addProjectConfiguration**(`host`: [_Tree_](../../angular/nx-devkit/index#tree), `projectName`: _string_, `projectConfiguration`: [_ProjectConfiguration_](../../angular/nx-devkit/index#projectconfiguration) & [_NxJsonProjectConfiguration_](../../angular/nx-devkit/index#nxjsonprojectconfiguration), `standalone?`: _boolean_): _void_
Adds project configuration to the Nx workspace. Adds project configuration to the Nx workspace.
@ -482,11 +482,12 @@ both files.
#### Parameters #### Parameters
| Name | Type | Description | | Name | Type | Default value | Description |
| :--------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------- | | :--------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------ | :---------------------------------------------------------------------- |
| `host` | [_Tree_](../../angular/nx-devkit/index#tree) | the file system tree | | `host` | [_Tree_](../../angular/nx-devkit/index#tree) | - | the file system tree |
| `projectName` | _string_ | unique name. Often directories are part of the name (e.g., mydir-mylib) | | `projectName` | _string_ | - | unique name. Often directories are part of the name (e.g., mydir-mylib) |
| `projectConfiguration` | [_ProjectConfiguration_](../../angular/nx-devkit/index#projectconfiguration) & [_NxJsonProjectConfiguration_](../../angular/nx-devkit/index#nxjsonprojectconfiguration) | project configuration | | `projectConfiguration` | [_ProjectConfiguration_](../../angular/nx-devkit/index#projectconfiguration) & [_NxJsonProjectConfiguration_](../../angular/nx-devkit/index#nxjsonprojectconfiguration) | - | project configuration |
| `standalone` | _boolean_ | false | - |
**Returns:** _void_ **Returns:** _void_

View File

@ -78,6 +78,14 @@ Type: `boolean`
Do not update tsconfig.json for development experience. Do not update tsconfig.json for development experience.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### tags ### tags
Alias(es): t Alias(es): t

View File

@ -150,6 +150,14 @@ Type: `boolean`
Skip updating workspace.json with default options based on values provided to this app (e.g. babel, style). Skip updating workspace.json with default options based on values provided to this app (e.g. babel, style).
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### strict ### strict
Default: `true` Default: `true`

View File

@ -158,6 +158,14 @@ Type: `boolean`
Do not update tsconfig.json for development experience. Do not update tsconfig.json for development experience.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### strict ### strict
Default: `true` Default: `true`

View File

@ -77,3 +77,11 @@ The tool to use for running lint checks.
Type: `string` Type: `string`
Project name Project name
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json

View File

@ -60,6 +60,14 @@ Type: `string`
Library or application name Library or application name
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### uiFramework ### uiFramework
Type: `string` Type: `string`

View File

@ -53,3 +53,11 @@ The tool to use for running lint checks.
Type: `string` Type: `string`
Library or application name Library or application name
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json

View File

@ -76,6 +76,14 @@ Type: `boolean`
Skip formatting files Skip formatting files
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### style ### style
Default: `css` Default: `css`

View File

@ -130,6 +130,14 @@ Type: `boolean`
Do not update tsconfig.json for development experience. Do not update tsconfig.json for development experience.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### strict ### strict
Default: `false` Default: `false`

View File

@ -128,6 +128,14 @@ Type: `boolean`
Skip creating spec files. Skip creating spec files.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### strict ### strict
Default: `true` Default: `true`

View File

@ -150,6 +150,14 @@ Type: `boolean`
Do not update tsconfig.json for development experience. Do not update tsconfig.json for development experience.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### strict ### strict
Default: `true` Default: `true`

View File

@ -98,6 +98,14 @@ Type: `boolean`
Do not add dependencies to package.json. Do not add dependencies to package.json.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### tags ### tags
Type: `string` Type: `string`

View File

@ -66,6 +66,14 @@ Type: `boolean`
Whether or not to configure the ESLint "parserOptions.project" option. We do not do this by default for lint performance reasons. Whether or not to configure the ESLint "parserOptions.project" option. We do not do this by default for lint performance reasons.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### style ### style
Alias(es): s Alias(es): s

View File

@ -72,6 +72,14 @@ Type: `boolean`
Do not add dependencies to package.json. Do not add dependencies to package.json.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### tags ### tags
Type: `string` Type: `string`

View File

@ -108,6 +108,14 @@ Type: `boolean`
Skip updating workspace.json with default options based on values provided to this app (e.g. babel, style) Skip updating workspace.json with default options based on values provided to this app (e.g. babel, style)
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### style ### style
Alias(es): s Alias(es): s

View File

@ -106,6 +106,14 @@ Type: `boolean`
Do not add dependencies to package.json. Do not add dependencies to package.json.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### tags ### tags
Type: `string` Type: `string`

View File

@ -138,6 +138,14 @@ Type: `boolean`
Do not update tsconfig.base.json for development experience. Do not update tsconfig.base.json for development experience.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### strict ### strict
Default: `false` Default: `false`

View File

@ -473,7 +473,7 @@ Callback to install dependencies only if necessary. undefined is returned if cha
### addProjectConfiguration ### addProjectConfiguration
**addProjectConfiguration**(`host`: [_Tree_](../../node/nx-devkit/index#tree), `projectName`: _string_, `projectConfiguration`: [_ProjectConfiguration_](../../node/nx-devkit/index#projectconfiguration) & [_NxJsonProjectConfiguration_](../../node/nx-devkit/index#nxjsonprojectconfiguration)): _void_ **addProjectConfiguration**(`host`: [_Tree_](../../node/nx-devkit/index#tree), `projectName`: _string_, `projectConfiguration`: [_ProjectConfiguration_](../../node/nx-devkit/index#projectconfiguration) & [_NxJsonProjectConfiguration_](../../node/nx-devkit/index#nxjsonprojectconfiguration), `standalone?`: _boolean_): _void_
Adds project configuration to the Nx workspace. Adds project configuration to the Nx workspace.
@ -482,11 +482,12 @@ both files.
#### Parameters #### Parameters
| Name | Type | Description | | Name | Type | Default value | Description |
| :--------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------- | | :--------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------ | :---------------------------------------------------------------------- |
| `host` | [_Tree_](../../node/nx-devkit/index#tree) | the file system tree | | `host` | [_Tree_](../../node/nx-devkit/index#tree) | - | the file system tree |
| `projectName` | _string_ | unique name. Often directories are part of the name (e.g., mydir-mylib) | | `projectName` | _string_ | - | unique name. Often directories are part of the name (e.g., mydir-mylib) |
| `projectConfiguration` | [_ProjectConfiguration_](../../node/nx-devkit/index#projectconfiguration) & [_NxJsonProjectConfiguration_](../../node/nx-devkit/index#nxjsonprojectconfiguration) | project configuration | | `projectConfiguration` | [_ProjectConfiguration_](../../node/nx-devkit/index#projectconfiguration) & [_NxJsonProjectConfiguration_](../../node/nx-devkit/index#nxjsonprojectconfiguration) | - | project configuration |
| `standalone` | _boolean_ | false | - |
**Returns:** _void_ **Returns:** _void_

View File

@ -78,6 +78,14 @@ Type: `boolean`
Do not update tsconfig.json for development experience. Do not update tsconfig.json for development experience.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### tags ### tags
Alias(es): t Alias(es): t

View File

@ -150,6 +150,14 @@ Type: `boolean`
Skip updating workspace.json with default options based on values provided to this app (e.g. babel, style). Skip updating workspace.json with default options based on values provided to this app (e.g. babel, style).
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### strict ### strict
Default: `true` Default: `true`

View File

@ -158,6 +158,14 @@ Type: `boolean`
Do not update tsconfig.json for development experience. Do not update tsconfig.json for development experience.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### strict ### strict
Default: `true` Default: `true`

View File

@ -77,3 +77,11 @@ The tool to use for running lint checks.
Type: `string` Type: `string`
Project name Project name
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json

View File

@ -60,6 +60,14 @@ Type: `string`
Library or application name Library or application name
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### uiFramework ### uiFramework
Type: `string` Type: `string`

View File

@ -53,3 +53,11 @@ The tool to use for running lint checks.
Type: `string` Type: `string`
Library or application name Library or application name
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json

View File

@ -76,6 +76,14 @@ Type: `boolean`
Skip formatting files Skip formatting files
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### style ### style
Default: `css` Default: `css`

View File

@ -130,6 +130,14 @@ Type: `boolean`
Do not update tsconfig.json for development experience. Do not update tsconfig.json for development experience.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### strict ### strict
Default: `false` Default: `false`

View File

@ -128,6 +128,14 @@ Type: `boolean`
Skip creating spec files. Skip creating spec files.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### strict ### strict
Default: `true` Default: `true`

View File

@ -150,6 +150,14 @@ Type: `boolean`
Do not update tsconfig.json for development experience. Do not update tsconfig.json for development experience.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### strict ### strict
Default: `true` Default: `true`

View File

@ -98,6 +98,14 @@ Type: `boolean`
Do not add dependencies to package.json. Do not add dependencies to package.json.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### tags ### tags
Type: `string` Type: `string`

View File

@ -66,6 +66,14 @@ Type: `boolean`
Whether or not to configure the ESLint "parserOptions.project" option. We do not do this by default for lint performance reasons. Whether or not to configure the ESLint "parserOptions.project" option. We do not do this by default for lint performance reasons.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### style ### style
Alias(es): s Alias(es): s

View File

@ -72,6 +72,14 @@ Type: `boolean`
Do not add dependencies to package.json. Do not add dependencies to package.json.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### tags ### tags
Type: `string` Type: `string`

View File

@ -108,6 +108,14 @@ Type: `boolean`
Skip updating workspace.json with default options based on values provided to this app (e.g. babel, style) Skip updating workspace.json with default options based on values provided to this app (e.g. babel, style)
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### style ### style
Alias(es): s Alias(es): s

View File

@ -106,6 +106,14 @@ Type: `boolean`
Do not add dependencies to package.json. Do not add dependencies to package.json.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### tags ### tags
Type: `string` Type: `string`

View File

@ -138,6 +138,14 @@ Type: `boolean`
Do not update tsconfig.base.json for development experience. Do not update tsconfig.base.json for development experience.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### strict ### strict
Default: `false` Default: `false`

View File

@ -473,7 +473,7 @@ Callback to install dependencies only if necessary. undefined is returned if cha
### addProjectConfiguration ### addProjectConfiguration
**addProjectConfiguration**(`host`: [_Tree_](../../react/nx-devkit/index#tree), `projectName`: _string_, `projectConfiguration`: [_ProjectConfiguration_](../../react/nx-devkit/index#projectconfiguration) & [_NxJsonProjectConfiguration_](../../react/nx-devkit/index#nxjsonprojectconfiguration)): _void_ **addProjectConfiguration**(`host`: [_Tree_](../../react/nx-devkit/index#tree), `projectName`: _string_, `projectConfiguration`: [_ProjectConfiguration_](../../react/nx-devkit/index#projectconfiguration) & [_NxJsonProjectConfiguration_](../../react/nx-devkit/index#nxjsonprojectconfiguration), `standalone?`: _boolean_): _void_
Adds project configuration to the Nx workspace. Adds project configuration to the Nx workspace.
@ -482,11 +482,12 @@ both files.
#### Parameters #### Parameters
| Name | Type | Description | | Name | Type | Default value | Description |
| :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :---------------------------------------------------------------------- | | :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :------------ | :---------------------------------------------------------------------- |
| `host` | [_Tree_](../../react/nx-devkit/index#tree) | the file system tree | | `host` | [_Tree_](../../react/nx-devkit/index#tree) | - | the file system tree |
| `projectName` | _string_ | unique name. Often directories are part of the name (e.g., mydir-mylib) | | `projectName` | _string_ | - | unique name. Often directories are part of the name (e.g., mydir-mylib) |
| `projectConfiguration` | [_ProjectConfiguration_](../../react/nx-devkit/index#projectconfiguration) & [_NxJsonProjectConfiguration_](../../react/nx-devkit/index#nxjsonprojectconfiguration) | project configuration | | `projectConfiguration` | [_ProjectConfiguration_](../../react/nx-devkit/index#projectconfiguration) & [_NxJsonProjectConfiguration_](../../react/nx-devkit/index#nxjsonprojectconfiguration) | - | project configuration |
| `standalone` | _boolean_ | false | - |
**Returns:** _void_ **Returns:** _void_

View File

@ -78,6 +78,14 @@ Type: `boolean`
Do not update tsconfig.json for development experience. Do not update tsconfig.json for development experience.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### tags ### tags
Alias(es): t Alias(es): t

View File

@ -150,6 +150,14 @@ Type: `boolean`
Skip updating workspace.json with default options based on values provided to this app (e.g. babel, style). Skip updating workspace.json with default options based on values provided to this app (e.g. babel, style).
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### strict ### strict
Default: `true` Default: `true`

View File

@ -158,6 +158,14 @@ Type: `boolean`
Do not update tsconfig.json for development experience. Do not update tsconfig.json for development experience.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### strict ### strict
Default: `true` Default: `true`

View File

@ -77,3 +77,11 @@ The tool to use for running lint checks.
Type: `string` Type: `string`
Project name Project name
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json

View File

@ -60,6 +60,14 @@ Type: `string`
Library or application name Library or application name
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### uiFramework ### uiFramework
Type: `string` Type: `string`

View File

@ -53,3 +53,11 @@ The tool to use for running lint checks.
Type: `string` Type: `string`
Library or application name Library or application name
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json

View File

@ -76,6 +76,14 @@ Type: `boolean`
Skip formatting files Skip formatting files
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### style ### style
Default: `css` Default: `css`

View File

@ -130,6 +130,14 @@ Type: `boolean`
Do not update tsconfig.json for development experience. Do not update tsconfig.json for development experience.
### standaloneConfig
Default: `false`
Type: `boolean`
Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json
### strict ### strict
Default: `false` Default: `false`

View File

@ -56,6 +56,24 @@ describe('Node Applications', () => {
expect(result).toContain('Hello World!'); expect(result).toContain('Hello World!');
}, 300000); }, 300000);
// TODO: This test fails in CI, but succeeds locally. It should be re-enabled once the reasoning is understood.
xit('should be able to generate an empty application with standalone configuration', async () => {
const nodeapp = uniq('nodeapp');
runCLI(
`generate @nrwl/node:app ${nodeapp} --linter=eslint --standaloneConfig`
);
updateFile(`apps/${nodeapp}/src/main.ts`, `console.log('Hello World!');`);
await runCLIAsync(`build ${nodeapp}`);
checkFilesExist(`dist/apps/${nodeapp}/main.js`);
const result = execSync(`node dist/apps/${nodeapp}/main.js`, {
cwd: tmpProjPath(),
}).toString();
expect(result).toContain('Hello World!');
}, 300000);
xit('should be able to generate an express application', async () => { xit('should be able to generate an express application', async () => {
const nodeapp = uniq('nodeapp'); const nodeapp = uniq('nodeapp');
const port = 3334; const port = 3334;

View File

@ -1,4 +1,5 @@
import { detectPackageManager } from '@nrwl/tao/src/shared/package-manager'; import { detectPackageManager } from '@nrwl/tao/src/shared/package-manager';
import { inlineProjectConfigurations } from '@nrwl/tao/src/shared/workspace';
import { ChildProcess, exec, execSync } from 'child_process'; import { ChildProcess, exec, execSync } from 'child_process';
import { import {
copySync, copySync,
@ -19,6 +20,7 @@ const kill = require('kill-port');
const isWindows = require('is-windows'); const isWindows = require('is-windows');
import { check as portCheck } from 'tcp-port-used'; import { check as portCheck } from 'tcp-port-used';
import { parseJson } from '@nrwl/devkit'; import { parseJson } from '@nrwl/devkit';
import chalk = require('chalk'); import chalk = require('chalk');
import treeKill = require('tree-kill'); import treeKill = require('tree-kill');
import { promisify } from 'util'; import { promisify } from 'util';
@ -36,7 +38,7 @@ interface RunCmdOpts {
} }
export function currentCli() { export function currentCli() {
return process.env.SELECTED_CLI ?? 'nx'; return process.env.SELECTED_CLI || 'nx';
} }
export function isNightlyRun() { export function isNightlyRun() {
@ -443,7 +445,10 @@ function setMaxWorkers() {
const workspace = readJson(workspaceFile); const workspace = readJson(workspaceFile);
Object.keys(workspace.projects).forEach((appName) => { Object.keys(workspace.projects).forEach((appName) => {
const project = workspace.projects[appName]; let project = workspace.projects[appName];
if (typeof project === 'string') {
project = readJson(path.join(project, 'project.json'));
}
const { build } = project.targets ?? project.architect; const { build } = project.targets ?? project.architect;
if (!build) { if (!build) {

View File

@ -38,5 +38,5 @@ describe('file-server', () => {
} catch { } catch {
expect('process running').toBeFalsy(); expect('process running').toBeFalsy();
} }
}, 300000); }, 150000);
}); });

View File

@ -21,6 +21,8 @@ describe('Web Components Applications', () => {
const appName = uniq('app'); const appName = uniq('app');
runCLI(`generate @nrwl/web:app ${appName} --no-interactive`); runCLI(`generate @nrwl/web:app ${appName} --no-interactive`);
checkFilesDoNotExist(`apps/${appName}/project.json`);
const lintResults = runCLI(`lint ${appName}`); const lintResults = runCLI(`lint ${appName}`);
expect(lintResults).toContain('All files pass linting.'); expect(lintResults).toContain('All files pass linting.');
@ -60,6 +62,18 @@ describe('Web Components Applications', () => {
} }
}, 500000); }, 500000);
it('should be able to generate a web app with standaloneConfig', async () => {
const appName = uniq('app');
runCLI(
`generate @nrwl/web:app ${appName} --no-interactive --standalone-config`
);
checkFilesExist(`apps/${appName}/project.json`);
const lintResults = runCLI(`lint ${appName}`);
expect(lintResults).toContain('All files pass linting.');
}, 120000);
it('should remove previous output before building', async () => { it('should remove previous output before building', async () => {
const appName = uniq('app'); const appName = uniq('app');
const libName = uniq('lib'); const libName = uniq('lib');

View File

@ -9,6 +9,7 @@ import {
installPackagesTask, installPackagesTask,
} from '@nrwl/devkit'; } from '@nrwl/devkit';
import { wrapAngularDevkitSchematic } from '@nrwl/devkit/ngcli-adapter'; import { wrapAngularDevkitSchematic } from '@nrwl/devkit/ngcli-adapter';
import { convertToNxProjectGenerator } from '@nrwl/workspace';
import { UnitTestRunner } from '../../utils/test-runners'; import { UnitTestRunner } from '../../utils/test-runners';
import init from '../init/init'; import init from '../init/init';
@ -99,6 +100,10 @@ export async function applicationGenerator(
setApplicationStrictDefault(host, false); setApplicationStrictDefault(host, false);
} }
if (options.standaloneConfig) {
await convertToNxProjectGenerator(host, {project: options.name, all: false});
}
if (!options.skipFormat) { if (!options.skipFormat) {
await formatFiles(host); await formatFiles(host);
} }

View File

@ -19,4 +19,5 @@ export interface Schema {
e2eTestRunner: E2eTestRunner; e2eTestRunner: E2eTestRunner;
backendProject?: string; backendProject?: string;
strict?: boolean; strict?: boolean;
standaloneConfig?: boolean;
} }

View File

@ -117,6 +117,11 @@
"type": "boolean", "type": "boolean",
"description": "Creates an application with stricter type checking and build optimization options.", "description": "Creates an application with stricter type checking and build optimization options.",
"default": true "default": true
},
"standaloneConfig": {
"description": "Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json",
"type": "boolean",
"default": false
} }
}, },
"required": [] "required": []

View File

@ -11,6 +11,7 @@ export interface Schema {
buildable: boolean; buildable: boolean;
publishable: boolean; publishable: boolean;
importPath?: string; importPath?: string;
standaloneConfig?: boolean;
spec?: boolean; spec?: boolean;
flat?: boolean; flat?: boolean;

View File

@ -103,6 +103,11 @@
"description": "Enable Ivy for library in tsconfig.lib.prod.json. Should not be used with publishable libraries.", "description": "Enable Ivy for library in tsconfig.lib.prod.json. Should not be used with publishable libraries.",
"type": "boolean", "type": "boolean",
"default": false "default": false
},
"standaloneConfig": {
"description": "Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json",
"type": "boolean",
"default": false
} }
}, },
"required": [] "required": []

View File

@ -14,6 +14,7 @@ describe('schematic:cypress-project', () => {
let tree: Tree; let tree: Tree;
const defaultOptions: Omit<Schema, 'name' | 'project'> = { const defaultOptions: Omit<Schema, 'name' | 'project'> = {
linter: Linter.EsLint, linter: Linter.EsLint,
standaloneConfig: false,
}; };
beforeEach(() => { beforeEach(() => {
@ -76,6 +77,7 @@ describe('schematic:cypress-project', () => {
name: 'my-app-e2e', name: 'my-app-e2e',
project: 'my-app', project: 'my-app',
linter: Linter.TsLint, linter: Linter.TsLint,
standaloneConfig: false,
}); });
const workspaceJson = readJson(tree, 'workspace.json'); const workspaceJson = readJson(tree, 'workspace.json');
const project = workspaceJson.projects['my-app-e2e']; const project = workspaceJson.projects['my-app-e2e'];
@ -114,6 +116,7 @@ describe('schematic:cypress-project', () => {
name: 'my-app-e2e', name: 'my-app-e2e',
project: 'my-app', project: 'my-app',
linter: Linter.TsLint, linter: Linter.TsLint,
standaloneConfig: false,
}); });
const workspaceJson = readJson(tree, 'workspace.json'); const workspaceJson = readJson(tree, 'workspace.json');
const project = workspaceJson.projects['my-app-e2e']; const project = workspaceJson.projects['my-app-e2e'];
@ -147,6 +150,7 @@ describe('schematic:cypress-project', () => {
name: 'my-app-e2e', name: 'my-app-e2e',
project: 'my-app', project: 'my-app',
linter: Linter.EsLint, linter: Linter.EsLint,
standaloneConfig: false,
}); });
const workspaceJson = readJson(tree, 'workspace.json'); const workspaceJson = readJson(tree, 'workspace.json');
const project = workspaceJson.projects['my-app-e2e']; const project = workspaceJson.projects['my-app-e2e'];
@ -164,6 +168,7 @@ describe('schematic:cypress-project', () => {
name: 'my-app-e2e', name: 'my-app-e2e',
project: 'my-app', project: 'my-app',
linter: Linter.None, linter: Linter.None,
standaloneConfig: false,
}); });
const workspaceJson = readJson(tree, 'workspace.json'); const workspaceJson = readJson(tree, 'workspace.json');
const project = workspaceJson.projects['my-app-e2e']; const project = workspaceJson.projects['my-app-e2e'];
@ -176,6 +181,7 @@ describe('schematic:cypress-project', () => {
name: 'my-app-e2e', name: 'my-app-e2e',
project: 'my-app', project: 'my-app',
linter: Linter.EsLint, linter: Linter.EsLint,
standaloneConfig: false,
}); });
const project = readProjectConfiguration(tree, 'my-app-e2e'); const project = readProjectConfiguration(tree, 'my-app-e2e');
@ -224,6 +230,7 @@ describe('schematic:cypress-project', () => {
project: 'my-dir-my-app', project: 'my-dir-my-app',
directory: 'my-dir', directory: 'my-dir',
linter: Linter.TsLint, linter: Linter.TsLint,
standaloneConfig: false,
}); });
const projectConfig = readJson(tree, 'workspace.json').projects[ const projectConfig = readJson(tree, 'workspace.json').projects[
'my-dir-my-app-e2e' 'my-dir-my-app-e2e'
@ -319,6 +326,7 @@ describe('schematic:cypress-project', () => {
name: 'my-app-e2e', name: 'my-app-e2e',
project: 'my-app', project: 'my-app',
linter: Linter.EsLint, linter: Linter.EsLint,
standaloneConfig: false,
}); });
const packageJson = readJson(tree, 'package.json'); const packageJson = readJson(tree, 'package.json');
expect( expect(

View File

@ -51,28 +51,39 @@ function addProject(tree: Tree, options: CypressProjectSchema) {
: devServerTarget; : devServerTarget;
} }
addProjectConfiguration(tree, options.projectName, { addProjectConfiguration(
root: options.projectRoot, tree,
sourceRoot: joinPathFragments(options.projectRoot, 'src'), options.projectName,
projectType: 'application', {
targets: { root: options.projectRoot,
e2e: { sourceRoot: joinPathFragments(options.projectRoot, 'src'),
executor: '@nrwl/cypress:cypress', projectType: 'application',
options: { targets: {
cypressConfig: joinPathFragments(options.projectRoot, 'cypress.json'), e2e: {
tsConfig: joinPathFragments(options.projectRoot, 'tsconfig.e2e.json'), executor: '@nrwl/cypress:cypress',
devServerTarget, options: {
}, cypressConfig: joinPathFragments(
configurations: { options.projectRoot,
production: { 'cypress.json'
devServerTarget: `${options.project}:serve:production`, ),
tsConfig: joinPathFragments(
options.projectRoot,
'tsconfig.e2e.json'
),
devServerTarget,
},
configurations: {
production: {
devServerTarget: `${options.project}:serve:production`,
},
}, },
}, },
}, },
tags: [],
implicitDependencies: options.project ? [options.project] : undefined,
}, },
tags: [], options.standaloneConfig
implicitDependencies: options.project ? [options.project] : undefined, );
});
} }
export async function addLinter(host: Tree, options: CypressProjectSchema) { export async function addLinter(host: Tree, options: CypressProjectSchema) {

View File

@ -8,4 +8,5 @@ export interface Schema {
js?: boolean; js?: boolean;
skipFormat?: boolean; skipFormat?: boolean;
setParserOptionsProject?: boolean; setParserOptionsProject?: boolean;
standaloneConfig?: booleann;
} }

View File

@ -45,6 +45,11 @@
"type": "boolean", "type": "boolean",
"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
},
"standaloneConfig": {
"description": "Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json",
"type": "boolean",
"default": false
} }
}, },
"required": ["name"] "required": ["name"]

View File

@ -0,0 +1,101 @@
import { Tree } from '@nrwl/tao/src/shared/tree';
import {
readProjectConfiguration,
addProjectConfiguration,
updateProjectConfiguration,
removeProjectConfiguration,
getProjects,
} from './project-configuration';
import { createTreeWithEmptyWorkspace } from '../tests/create-tree-with-empty-workspace';
import { ProjectConfiguration } from '@nrwl/tao/src/shared/workspace';
import { readJson } from '../utils/json';
const baseTestProjectConfig: ProjectConfiguration = {
root: 'libs/test',
sourceRoot: 'libs/test/src',
targets: {},
};
describe('project configuration', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
});
it('should create project.json file when adding a project if standalone is true', () => {
addProjectConfiguration(tree, 'test', baseTestProjectConfig, true);
expect(tree.exists('libs/test/project.json')).toBeTruthy();
});
it('should not create project.json file when adding a project if standalone is false', () => {
addProjectConfiguration(tree, 'test', baseTestProjectConfig, false);
expect(tree.exists('libs/test/project.json')).toBeFalsy();
});
it('should be able to read from standalone projects', () => {
tree.write(
'libs/test/project.json',
JSON.stringify(baseTestProjectConfig, null, 2)
);
tree.write(
'workspace.json',
JSON.stringify(
{
projects: {
test: 'libs/test',
},
},
null,
2
)
);
const projectConfig = readProjectConfiguration(tree, 'test');
expect(projectConfig).toEqual(baseTestProjectConfig);
});
it('should update project.json file when updating a project', () => {
addProjectConfiguration(tree, 'test', baseTestProjectConfig, true);
const expectedProjectConfig = {
...baseTestProjectConfig,
targets: { build: { executor: '' } },
};
updateProjectConfiguration(tree, 'test', expectedProjectConfig);
expect(readJson(tree, 'libs/test/project.json')).toEqual(
expectedProjectConfig
);
});
it('should update workspace.json file when updating an inline project', () => {
addProjectConfiguration(tree, 'test', baseTestProjectConfig, false);
const expectedProjectConfig = {
...baseTestProjectConfig,
targets: { build: { executor: '' } },
};
updateProjectConfiguration(tree, 'test', expectedProjectConfig);
expect(readJson(tree, 'workspace.json').projects.test).toEqual(
expectedProjectConfig
);
});
it('should remove project.json file when removing projct configuration', () => {
addProjectConfiguration(tree, 'test', baseTestProjectConfig, true);
removeProjectConfiguration(tree, 'test');
expect(tree.exists('test/project.json')).toBeFalsy();
});
it('should support workspaces with standalone and inline projects', () => {
addProjectConfiguration(tree, 'test', baseTestProjectConfig, true);
addProjectConfiguration(tree, 'test2', baseTestProjectConfig, false);
const configurations = getProjects(tree);
expect(configurations.get('test')).toEqual(baseTestProjectConfig);
expect(configurations.get('test2')).toEqual(baseTestProjectConfig);
});
});

View File

@ -1,15 +1,17 @@
import type { Tree } from '@nrwl/tao/src/shared/tree'; import type { Tree } from '@nrwl/tao/src/shared/tree';
import type { import {
ProjectConfiguration, ProjectConfiguration,
RawWorkspaceJsonConfiguration,
toNewFormat,
WorkspaceJsonConfiguration, WorkspaceJsonConfiguration,
} from '@nrwl/tao/src/shared/workspace'; } from '@nrwl/tao/src/shared/workspace';
import { toNewFormat } from '@nrwl/tao/src/shared/workspace';
import { readJson, updateJson, writeJson } from '../utils/json'; import { readJson, updateJson, writeJson } from '../utils/json';
import type { import type {
NxJsonConfiguration, NxJsonConfiguration,
NxJsonProjectConfiguration, NxJsonProjectConfiguration,
} from '@nrwl/tao/src/shared/nx'; } from '@nrwl/tao/src/shared/nx';
import { getWorkspacePath } from '../utils/get-workspace-layout'; import { getWorkspacePath } from '../utils/get-workspace-layout';
import { join } from 'path';
export type WorkspaceConfiguration = Omit< export type WorkspaceConfiguration = Omit<
WorkspaceJsonConfiguration, WorkspaceJsonConfiguration,
@ -30,9 +32,16 @@ export type WorkspaceConfiguration = Omit<
export function addProjectConfiguration( export function addProjectConfiguration(
host: Tree, host: Tree,
projectName: string, projectName: string,
projectConfiguration: ProjectConfiguration & NxJsonProjectConfiguration projectConfiguration: ProjectConfiguration & NxJsonProjectConfiguration,
standalone: boolean = false
): void { ): void {
setProjectConfiguration(host, projectName, projectConfiguration, 'create'); setProjectConfiguration(
host,
projectName,
projectConfiguration,
'create',
standalone
);
} }
/** /**
@ -78,10 +87,10 @@ export function getProjects(
const nxJson = readJson<NxJsonConfiguration>(host, 'nx.json'); const nxJson = readJson<NxJsonConfiguration>(host, 'nx.json');
return new Map( return new Map(
Object.keys(workspace.projects).map((projectName) => { Object.keys(workspace.projects || {}).map((projectName) => {
return [ return [
projectName, projectName,
getProjectConfiguration(projectName, workspace, nxJson), getProjectConfiguration(host, projectName, workspace, nxJson),
]; ];
}) })
); );
@ -156,31 +165,36 @@ export function readProjectConfiguration(
} }
const nxJson = readJson<NxJsonConfiguration>(host, 'nx.json'); const nxJson = readJson<NxJsonConfiguration>(host, 'nx.json');
if (!nxJson.projects[projectName]) {
throw new Error(
`Cannot find configuration for '${projectName}' in nx.json`
);
}
return getProjectConfiguration(projectName, workspace, nxJson); // TODO: Remove after confirming that nx.json should be optional.
// if (!nxJson.projects[projectName]) {
// throw new Error(
// `Cannot find configuration for '${projectName}' in nx.json`
// );
// }
return getProjectConfiguration(host, projectName, workspace, nxJson);
} }
function getProjectConfiguration( function getProjectConfiguration(
host: Tree,
projectName: string, projectName: string,
workspace: WorkspaceJsonConfiguration, workspace: WorkspaceJsonConfiguration,
nxJson: NxJsonConfiguration nxJson: NxJsonConfiguration
): ProjectConfiguration & NxJsonProjectConfiguration { ): ProjectConfiguration & NxJsonProjectConfiguration {
return { return {
...readWorkspaceSection(workspace, projectName), ...readWorkspaceSection(host, workspace, projectName),
...readNxJsonSection(nxJson, projectName), ...readNxJsonSection(nxJson, projectName),
}; };
} }
function readWorkspaceSection( function readWorkspaceSection(
host: Tree,
workspace: WorkspaceJsonConfiguration, workspace: WorkspaceJsonConfiguration,
projectName: string projectName: string
) { ) {
return workspace.projects[projectName]; const config = workspace.projects[projectName];
return config;
} }
function readNxJsonSection(nxJson: NxJsonConfiguration, projectName: string) { function readNxJsonSection(nxJson: NxJsonConfiguration, projectName: string) {
@ -191,7 +205,8 @@ function setProjectConfiguration(
host: Tree, host: Tree,
projectName: string, projectName: string,
projectConfiguration: ProjectConfiguration & NxJsonProjectConfiguration, projectConfiguration: ProjectConfiguration & NxJsonProjectConfiguration,
mode: 'create' | 'update' | 'delete' mode: 'create' | 'update' | 'delete',
standalone: boolean = false
) { ) {
if (mode === 'delete') { if (mode === 'delete') {
addProjectToNxJson(host, projectName, undefined, mode); addProjectToNxJson(host, projectName, undefined, mode);
@ -205,9 +220,14 @@ function setProjectConfiguration(
); );
} }
const { tags, implicitDependencies, ...workspaceConfiguration } = const { tags, implicitDependencies } = projectConfiguration;
projectConfiguration; addProjectToWorkspaceJson(
addProjectToWorkspaceJson(host, projectName, workspaceConfiguration, mode); host,
projectName,
projectConfiguration,
mode,
standalone
);
addProjectToNxJson( addProjectToNxJson(
host, host,
projectName, projectName,
@ -222,11 +242,118 @@ function setProjectConfiguration(
function addProjectToWorkspaceJson( function addProjectToWorkspaceJson(
host: Tree, host: Tree,
projectName: string, projectName: string,
project: ProjectConfiguration, project: ProjectConfiguration & NxJsonProjectConfiguration,
mode: 'create' | 'update' | 'delete' mode: 'create' | 'update' | 'delete',
standalone: boolean = false
) { ) {
const path = getWorkspacePath(host); const path = getWorkspacePath(host);
const workspaceJson = readJson<WorkspaceJsonConfiguration>(host, path); const workspaceJson = readJson<RawWorkspaceJsonConfiguration>(host, path);
validateWorkspaceJsonOperations(mode, workspaceJson, projectName);
const configFile =
mode === 'create' && standalone
? join(project.root, 'project.json')
: getProjectFileLocation(host, projectName);
if (configFile) {
if (mode === 'delete') {
host.delete(configFile);
} else {
writeJson(host, configFile, project);
}
if (mode === 'create') {
workspaceJson.projects[projectName] = project.root;
writeJson(host, path, workspaceJson);
}
} else {
let workspaceConfiguration: ProjectConfiguration;
if (project) {
const { tags, implicitDependencies, ...c } = project;
workspaceConfiguration = c;
}
workspaceJson.projects[projectName] = workspaceConfiguration;
writeJson(host, path, workspaceJson);
}
}
function addProjectToNxJson(
host: Tree,
projectName: string,
config: NxJsonProjectConfiguration,
mode: 'create' | 'update' | 'delete'
) {
// distributed project files do not use nx.json,
// so only proceed if the project does not use them.
if (!getProjectFileLocation(host, projectName)) {
const nxJson = readJson<NxJsonConfiguration>(host, 'nx.json');
if (mode === 'delete') {
delete nxJson.projects[projectName];
} else {
nxJson.projects[projectName] = {
...{
tags: [],
},
...(config || {}),
};
}
writeJson(host, 'nx.json', nxJson);
}
}
function readWorkspace(host: Tree): WorkspaceJsonConfiguration {
const workspaceJson = inlineProjectConfigurationsWithTree(host);
const originalVersion = workspaceJson.version;
return {
...toNewFormat(workspaceJson),
version: originalVersion,
};
}
/**
* This has to be separate from the inline functionality inside tao,
* as the functionality in tao does not use a Tree. Changes made during
* a generator would not be present during runtime execution.
* @returns
*/
function inlineProjectConfigurationsWithTree(
host: Tree
): WorkspaceJsonConfiguration {
const path = getWorkspacePath(host);
const workspaceJson = readJson<RawWorkspaceJsonConfiguration>(host, path);
Object.entries(workspaceJson.projects || {}).forEach(([project, config]) => {
if (typeof config === 'string') {
const configFileLocation = join(config, 'project.json');
workspaceJson.projects[project] = readJson<
ProjectConfiguration & NxJsonProjectConfiguration
>(host, configFileLocation);
}
});
return workspaceJson as WorkspaceJsonConfiguration;
}
/**
* @description Determine where a project's configuration is located.
* @returns file path if separate from root config, null otherwise.
*/
function getProjectFileLocation(host: Tree, project: string): string | null {
const rawWorkspace = readJson<RawWorkspaceJsonConfiguration>(
host,
getWorkspacePath(host)
);
const projectConfig = rawWorkspace.projects?.[project];
return typeof projectConfig === 'string'
? join(projectConfig, 'project.json')
: null;
}
function validateWorkspaceJsonOperations(
mode: 'create' | 'update' | 'delete',
workspaceJson: RawWorkspaceJsonConfiguration | WorkspaceJsonConfiguration,
projectName: string
) {
if (mode == 'create' && workspaceJson.projects[projectName]) { if (mode == 'create' && workspaceJson.projects[projectName]) {
throw new Error( throw new Error(
`Cannot create Project '${projectName}'. It already exists.` `Cannot create Project '${projectName}'. It already exists.`
@ -239,39 +366,7 @@ function addProjectToWorkspaceJson(
} }
if (mode == 'delete' && !workspaceJson.projects[projectName]) { if (mode == 'delete' && !workspaceJson.projects[projectName]) {
throw new Error( throw new Error(
`Cannot update Project '${projectName}'. It does not exist.` `Cannot delete Project '${projectName}'. It does not exist.`
); );
} }
workspaceJson.projects[projectName] = project;
writeJson(host, path, workspaceJson);
}
function addProjectToNxJson(
host: Tree,
projectName: string,
config: NxJsonProjectConfiguration,
mode: 'create' | 'update' | 'delete'
) {
const nxJson = readJson<NxJsonConfiguration>(host, 'nx.json');
if (mode === 'delete') {
delete nxJson.projects[projectName];
} else {
nxJson.projects[projectName] = {
...{
tags: [],
},
...(config || {}),
};
}
writeJson(host, 'nx.json', nxJson);
}
function readWorkspace(host: Tree): WorkspaceJsonConfiguration {
const path = getWorkspacePath(host);
const workspaceJson = readJson<WorkspaceJsonConfiguration>(host, path);
const originalVersion = workspaceJson.version;
return {
...toNewFormat(workspaceJson),
version: originalVersion,
};
} }

View File

@ -4,10 +4,10 @@ import type { Tree } from '@nrwl/tao/src/shared/tree';
/** /**
* Creates a host for testing. * Creates a host for testing.
*/ */
export function createTreeWithEmptyWorkspace(): Tree { export function createTreeWithEmptyWorkspace(version = 1): Tree {
const tree = new FsTree('/virtual', false); const tree = new FsTree('/virtual', false);
tree.write('/workspace.json', JSON.stringify({ version: 1, projects: {} })); tree.write('/workspace.json', JSON.stringify({ version, projects: {} }));
tree.write('./.prettierrc', JSON.stringify({ singleQuote: true })); tree.write('./.prettierrc', JSON.stringify({ singleQuote: true }));
tree.write( tree.write(
'/package.json', '/package.json',

View File

@ -13,4 +13,5 @@ export interface Schema {
babelJest?: boolean; babelJest?: boolean;
js: boolean; js: boolean;
pascalCaseFiles: boolean; pascalCaseFiles: boolean;
standaloneConfig?: boolean;
} }

View File

@ -64,6 +64,11 @@
"type": "boolean", "type": "boolean",
"description": "Generate JavaScript files rather than TypeScript files.", "description": "Generate JavaScript files rather than TypeScript files.",
"default": false "default": false
},
"standaloneConfig": {
"description": "Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json",
"type": "boolean",
"default": false
} }
}, },
"required": [] "required": []

View File

@ -13,7 +13,11 @@ describe('app', () => {
}); });
it('should update workspace.json', async () => { it('should update workspace.json', async () => {
await applicationGenerator(tree, { name: 'myApp', style: 'css' }); await applicationGenerator(tree, {
name: 'myApp',
style: 'css',
standaloneConfig: false,
});
const workspaceJson = readJson(tree, '/workspace.json'); const workspaceJson = readJson(tree, '/workspace.json');
expect(workspaceJson.projects['my-app'].root).toEqual('apps/my-app'); expect(workspaceJson.projects['my-app'].root).toEqual('apps/my-app');
@ -28,6 +32,7 @@ describe('app', () => {
name: 'myApp', name: 'myApp',
style: 'css', style: 'css',
tags: 'one,two', tags: 'one,two',
standaloneConfig: false,
}); });
const nxJson = readJson<NxJsonConfiguration>(tree, '/nx.json'); const nxJson = readJson<NxJsonConfiguration>(tree, '/nx.json');
expect(nxJson.projects).toEqual({ expect(nxJson.projects).toEqual({
@ -42,7 +47,11 @@ describe('app', () => {
}); });
it('should generate files', async () => { it('should generate files', async () => {
await applicationGenerator(tree, { name: 'myApp', style: 'css' }); await applicationGenerator(tree, {
name: 'myApp',
style: 'css',
standaloneConfig: false,
});
expect(tree.exists('apps/my-app/tsconfig.json')).toBeTruthy(); expect(tree.exists('apps/my-app/tsconfig.json')).toBeTruthy();
expect(tree.exists('apps/my-app/tsconfig.app.json')).toBeTruthy(); expect(tree.exists('apps/my-app/tsconfig.app.json')).toBeTruthy();
expect(tree.exists('apps/my-app/src/pages/index.tsx')).toBeTruthy(); expect(tree.exists('apps/my-app/src/pages/index.tsx')).toBeTruthy();
@ -55,6 +64,7 @@ describe('app', () => {
await applicationGenerator(tree, { await applicationGenerator(tree, {
name: 'myApp', name: 'myApp',
style: 'scss', style: 'scss',
standaloneConfig: false,
}); });
expect( expect(
tree.exists('apps/my-app/src/pages/index.module.scss') tree.exists('apps/my-app/src/pages/index.module.scss')
@ -79,6 +89,7 @@ describe('app', () => {
await applicationGenerator(tree, { await applicationGenerator(tree, {
name: 'myApp', name: 'myApp',
style: 'less', style: 'less',
standaloneConfig: false,
}); });
expect( expect(
tree.exists('apps/my-app/src/pages/index.module.less') tree.exists('apps/my-app/src/pages/index.module.less')
@ -103,6 +114,7 @@ describe('app', () => {
await applicationGenerator(tree, { await applicationGenerator(tree, {
name: 'myApp', name: 'myApp',
style: 'styl', style: 'styl',
standaloneConfig: false,
}); });
expect( expect(
tree.exists('apps/my-app/src/pages/index.module.styl') tree.exists('apps/my-app/src/pages/index.module.styl')
@ -127,6 +139,7 @@ describe('app', () => {
await applicationGenerator(tree, { await applicationGenerator(tree, {
name: 'myApp', name: 'myApp',
style: 'styled-components', style: 'styled-components',
standaloneConfig: false,
}); });
expect( expect(
tree.exists('apps/my-app/src/pages/index.module.styled-components') tree.exists('apps/my-app/src/pages/index.module.styled-components')
@ -152,6 +165,7 @@ describe('app', () => {
await applicationGenerator(tree, { await applicationGenerator(tree, {
name: 'myApp', name: 'myApp',
style: '@emotion/styled', style: '@emotion/styled',
standaloneConfig: false,
}); });
expect( expect(
tree.exists('apps/my-app/src/pages/index.module.styled-components') tree.exists('apps/my-app/src/pages/index.module.styled-components')
@ -177,6 +191,7 @@ describe('app', () => {
await applicationGenerator(tree, { await applicationGenerator(tree, {
name: 'myApp', name: 'myApp',
style: 'styled-jsx', style: 'styled-jsx',
standaloneConfig: false,
}); });
const indexContent = tree const indexContent = tree
@ -206,6 +221,7 @@ describe('app', () => {
await applicationGenerator(tree, { await applicationGenerator(tree, {
name: 'my-app', name: 'my-app',
style: 'css', style: 'css',
standaloneConfig: false,
}); });
expect(tree.read('apps/my-app/jest.config.js', 'utf-8')).toContain( expect(tree.read('apps/my-app/jest.config.js', 'utf-8')).toContain(
@ -217,6 +233,7 @@ describe('app', () => {
await applicationGenerator(tree, { await applicationGenerator(tree, {
name: 'my-app', name: 'my-app',
style: 'css', style: 'css',
standaloneConfig: false,
}); });
expect(tree.read('apps/my-app/jest.config.js', 'utf-8')).toContain( expect(tree.read('apps/my-app/jest.config.js', 'utf-8')).toContain(
@ -228,6 +245,7 @@ describe('app', () => {
await applicationGenerator(tree, { await applicationGenerator(tree, {
name: 'my-app', name: 'my-app',
style: 'css', style: 'css',
standaloneConfig: false,
}); });
const workspaceJson = readJson(tree, 'workspace.json'); const workspaceJson = readJson(tree, 'workspace.json');
const architectConfig = workspaceJson.projects['my-app'].architect; const architectConfig = workspaceJson.projects['my-app'].architect;
@ -241,6 +259,7 @@ describe('app', () => {
await applicationGenerator(tree, { await applicationGenerator(tree, {
name: 'my-app', name: 'my-app',
style: 'css', style: 'css',
standaloneConfig: false,
}); });
const workspaceJson = readJson(tree, 'workspace.json'); const workspaceJson = readJson(tree, 'workspace.json');
const architectConfig = workspaceJson.projects['my-app'].architect; const architectConfig = workspaceJson.projects['my-app'].architect;
@ -259,6 +278,7 @@ describe('app', () => {
name: 'myApp', name: 'myApp',
style: 'css', style: 'css',
unitTestRunner: 'none', unitTestRunner: 'none',
standaloneConfig: false,
}); });
expect(tree.exists('jest.config.js')).toBeFalsy(); expect(tree.exists('jest.config.js')).toBeFalsy();
expect(tree.exists('apps/my-app/specs/index.spec.tsx')).toBeFalsy(); expect(tree.exists('apps/my-app/specs/index.spec.tsx')).toBeFalsy();
@ -271,6 +291,7 @@ describe('app', () => {
name: 'myApp', name: 'myApp',
style: 'css', style: 'css',
e2eTestRunner: 'none', e2eTestRunner: 'none',
standaloneConfig: false,
}); });
expect(tree.exists('apps/my-app-e2e')).toBeFalsy(); expect(tree.exists('apps/my-app-e2e')).toBeFalsy();
const workspaceJson = readJson(tree, 'workspace.json'); const workspaceJson = readJson(tree, 'workspace.json');
@ -279,7 +300,11 @@ describe('app', () => {
}); });
it('should generate an index component', async () => { it('should generate an index component', async () => {
await applicationGenerator(tree, { name: 'myApp', style: 'css' }); await applicationGenerator(tree, {
name: 'myApp',
style: 'css',
standaloneConfig: false,
});
const appContent = tree.read('apps/my-app/src/pages/index.tsx', 'utf-8'); const appContent = tree.read('apps/my-app/src/pages/index.tsx', 'utf-8');
@ -290,6 +315,7 @@ describe('app', () => {
await applicationGenerator(tree, { await applicationGenerator(tree, {
name: 'myApp', name: 'myApp',
style: 'css', style: 'css',
standaloneConfig: false,
}); });
const packageJson = readJson(tree, '/package.json'); const packageJson = readJson(tree, '/package.json');
@ -349,6 +375,7 @@ describe('app', () => {
name: 'myApp', name: 'myApp',
style: 'css', style: 'css',
js: true, js: true,
standaloneConfig: false,
}); });
expect(tree.exists('apps/my-app/src/pages/index.js')).toBeTruthy(); expect(tree.exists('apps/my-app/src/pages/index.js')).toBeTruthy();

View File

@ -46,8 +46,13 @@ export function addProject(host: Tree, options: NormalizedSchema) {
targets, targets,
}; };
addProjectConfiguration(host, options.projectName, { addProjectConfiguration(
...project, host,
...nxConfig, options.projectName,
}); {
...project,
...nxConfig,
},
options.standaloneConfig
);
} }

View File

@ -9,4 +9,5 @@ export interface Schema {
e2eTestRunner?: 'cypress' | 'none'; e2eTestRunner?: 'cypress' | 'none';
js?: boolean; js?: boolean;
setParserOptionsProject?: boolean; setParserOptionsProject?: boolean;
standaloneConfig?: boolean;
} }

View File

@ -89,6 +89,11 @@
"type": "boolean", "type": "boolean",
"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
},
"standaloneConfig": {
"description": "Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json",
"type": "boolean",
"default": false
} }
}, },
"required": ["name"] "required": ["name"]

View File

@ -12,7 +12,11 @@ describe('component', () => {
tree = createTreeWithEmptyWorkspace(); tree = createTreeWithEmptyWorkspace();
tree.write('.gitignore', '# empty'); tree.write('.gitignore', '# empty');
tree.write('.prettierignore', '# empty'); tree.write('.prettierignore', '# empty');
await applicationGenerator(tree, { name: projectName, style: 'css' }); await applicationGenerator(tree, {
name: projectName,
style: 'css',
standaloneConfig: false,
});
}); });
it('should generate component in components directory', async () => { it('should generate component in components directory', async () => {

View File

@ -12,7 +12,11 @@ describe('component', () => {
tree = createTreeWithEmptyWorkspace(); tree = createTreeWithEmptyWorkspace();
tree.write('.gitignore', '# empty'); tree.write('.gitignore', '# empty');
tree.write('.prettierignore', '# empty'); tree.write('.prettierignore', '# empty');
await applicationGenerator(tree, { name: projectName, style: 'css' }); await applicationGenerator(tree, {
name: projectName,
style: 'css',
standaloneConfig: false,
});
}); });
it('should generate component in pages directory', async () => { it('should generate component in pages directory', async () => {

View File

@ -10,4 +10,5 @@ export interface Schema {
tags?: string; tags?: string;
linter: Linter; linter: Linter;
frontendProject?: string; frontendProject?: string;
standaloneConfig?: boolean;
} }

View File

@ -46,6 +46,11 @@
"frontendProject": { "frontendProject": {
"type": "string", "type": "string",
"description": "Frontend project that needs to access this application. This sets up proxy configuration." "description": "Frontend project that needs to access this application. This sets up proxy configuration."
},
"standaloneConfig": {
"description": "Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json",
"type": "boolean",
"default": false
} }
}, },
"required": [] "required": []

View File

@ -13,7 +13,11 @@ describe('app', () => {
describe('not nested', () => { describe('not nested', () => {
it('should update workspace.json', async () => { it('should update workspace.json', async () => {
await applicationGenerator(tree, { name: 'myApp', style: 'css' }); await applicationGenerator(tree, {
name: 'myApp',
style: 'css',
standaloneConfig: false,
});
const workspaceJson = readJson(tree, 'workspace.json'); const workspaceJson = readJson(tree, 'workspace.json');
@ -29,6 +33,7 @@ describe('app', () => {
name: 'myApp', name: 'myApp',
style: 'css', style: 'css',
tags: 'one,two', tags: 'one,two',
standaloneConfig: false,
}); });
const nxJson = readJson(tree, 'nx.json'); const nxJson = readJson(tree, 'nx.json');
@ -45,7 +50,11 @@ describe('app', () => {
}); });
it('should generate files', async () => { it('should generate files', async () => {
await applicationGenerator(tree, { name: 'myApp', style: 'css' }); await applicationGenerator(tree, {
name: 'myApp',
style: 'css',
standaloneConfig: false,
});
expect(tree.exists('apps/my-app/tsconfig.json')).toBeTruthy(); expect(tree.exists('apps/my-app/tsconfig.json')).toBeTruthy();
expect(tree.exists('apps/my-app/pages/index.tsx')).toBeTruthy(); expect(tree.exists('apps/my-app/pages/index.tsx')).toBeTruthy();
expect(tree.exists('apps/my-app/specs/index.spec.tsx')).toBeTruthy(); expect(tree.exists('apps/my-app/specs/index.spec.tsx')).toBeTruthy();
@ -58,6 +67,7 @@ describe('app', () => {
await applicationGenerator(tree, { await applicationGenerator(tree, {
name: 'myApp', name: 'myApp',
style: 'scss', style: 'scss',
standaloneConfig: false,
}); });
expect(tree.exists('apps/my-app/pages/index.module.scss')).toBeTruthy(); expect(tree.exists('apps/my-app/pages/index.module.scss')).toBeTruthy();
@ -75,6 +85,7 @@ describe('app', () => {
await applicationGenerator(tree, { await applicationGenerator(tree, {
name: 'myApp', name: 'myApp',
style: 'less', style: 'less',
standaloneConfig: false,
}); });
expect(tree.exists('apps/my-app/pages/index.module.less')).toBeTruthy(); expect(tree.exists('apps/my-app/pages/index.module.less')).toBeTruthy();
@ -92,6 +103,7 @@ describe('app', () => {
await applicationGenerator(tree, { await applicationGenerator(tree, {
name: 'myApp', name: 'myApp',
style: 'styl', style: 'styl',
standaloneConfig: false,
}); });
expect(tree.exists('apps/my-app/pages/index.module.styl')).toBeTruthy(); expect(tree.exists('apps/my-app/pages/index.module.styl')).toBeTruthy();
@ -109,6 +121,7 @@ describe('app', () => {
await applicationGenerator(tree, { await applicationGenerator(tree, {
name: 'myApp', name: 'myApp',
style: 'styled-components', style: 'styled-components',
standaloneConfig: false,
}); });
expect( expect(
@ -127,6 +140,7 @@ describe('app', () => {
await applicationGenerator(tree, { await applicationGenerator(tree, {
name: 'myApp', name: 'myApp',
style: '@emotion/styled', style: '@emotion/styled',
standaloneConfig: false,
}); });
expect( expect(
@ -145,6 +159,7 @@ describe('app', () => {
await applicationGenerator(tree, { await applicationGenerator(tree, {
name: 'myApp', name: 'myApp',
style: 'styled-jsx', style: 'styled-jsx',
standaloneConfig: false,
}); });
const indexContent = tree.read('apps/my-app/pages/index.tsx', 'utf-8'); const indexContent = tree.read('apps/my-app/pages/index.tsx', 'utf-8');
@ -163,7 +178,11 @@ describe('app', () => {
}); });
it('should setup jest with tsx support', async () => { it('should setup jest with tsx support', async () => {
await applicationGenerator(tree, { name: 'my-app', style: 'css' }); await applicationGenerator(tree, {
name: 'my-app',
style: 'css',
standaloneConfig: false,
});
expect(tree.read('apps/my-app/jest.config.js', 'utf-8')).toContain( expect(tree.read('apps/my-app/jest.config.js', 'utf-8')).toContain(
`moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],` `moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],`
@ -171,7 +190,11 @@ describe('app', () => {
}); });
it('should setup jest with SVGR support', async () => { it('should setup jest with SVGR support', async () => {
await applicationGenerator(tree, { name: 'my-app', style: 'css' }); await applicationGenerator(tree, {
name: 'my-app',
style: 'css',
standaloneConfig: false,
});
expect(tree.read('apps/my-app/jest.config.js', 'utf-8')).toContain( expect(tree.read('apps/my-app/jest.config.js', 'utf-8')).toContain(
`'^(?!.*\\\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest'` `'^(?!.*\\\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest'`
@ -179,7 +202,11 @@ describe('app', () => {
}); });
it('should set up the nrwl next build builder', async () => { it('should set up the nrwl next build builder', async () => {
await applicationGenerator(tree, { name: 'my-app', style: 'css' }); await applicationGenerator(tree, {
name: 'my-app',
style: 'css',
standaloneConfig: false,
});
const workspaceJson = readJson(tree, 'workspace.json'); const workspaceJson = readJson(tree, 'workspace.json');
const architectConfig = workspaceJson.projects['my-app'].architect; const architectConfig = workspaceJson.projects['my-app'].architect;
@ -191,7 +218,11 @@ describe('app', () => {
}); });
it('should set up the nrwl next server builder', async () => { it('should set up the nrwl next server builder', async () => {
await applicationGenerator(tree, { name: 'my-app', style: 'css' }); await applicationGenerator(tree, {
name: 'my-app',
style: 'css',
standaloneConfig: false,
});
const workspaceJson = readJson(tree, 'workspace.json'); const workspaceJson = readJson(tree, 'workspace.json');
const architectConfig = workspaceJson.projects['my-app'].architect; const architectConfig = workspaceJson.projects['my-app'].architect;
@ -206,7 +237,11 @@ describe('app', () => {
}); });
it('should set up the nrwl next export builder', async () => { it('should set up the nrwl next export builder', async () => {
await applicationGenerator(tree, { name: 'my-app', style: 'css' }); await applicationGenerator(tree, {
name: 'my-app',
style: 'css',
standaloneConfig: false,
});
const workspaceJson = readJson(tree, 'workspace.json'); const workspaceJson = readJson(tree, 'workspace.json');
const architectConfig = workspaceJson.projects['my-app'].architect; const architectConfig = workspaceJson.projects['my-app'].architect;
@ -222,6 +257,7 @@ describe('app', () => {
name: 'myApp', name: 'myApp',
style: 'css', style: 'css',
unitTestRunner: 'none', unitTestRunner: 'none',
standaloneConfig: false,
}); });
expect(tree.exists('jest.config.js')).toBeFalsy(); expect(tree.exists('jest.config.js')).toBeFalsy();
expect(tree.exists('apps/my-app/specs/index.spec.tsx')).toBeFalsy(); expect(tree.exists('apps/my-app/specs/index.spec.tsx')).toBeFalsy();
@ -234,6 +270,7 @@ describe('app', () => {
name: 'myApp', name: 'myApp',
style: 'css', style: 'css',
e2eTestRunner: 'none', e2eTestRunner: 'none',
standaloneConfig: false,
}); });
expect(tree.exists('apps/my-app-e2e')).toBeFalsy(); expect(tree.exists('apps/my-app-e2e')).toBeFalsy();
const workspaceJson = readJson(tree, 'workspace.json'); const workspaceJson = readJson(tree, 'workspace.json');
@ -242,7 +279,11 @@ describe('app', () => {
}); });
it('should generate functional components by default', async () => { it('should generate functional components by default', async () => {
await applicationGenerator(tree, { name: 'myApp', style: 'css' }); await applicationGenerator(tree, {
name: 'myApp',
style: 'css',
standaloneConfig: false,
});
const appContent = tree.read('apps/my-app/pages/index.tsx', 'utf-8'); const appContent = tree.read('apps/my-app/pages/index.tsx', 'utf-8');
@ -255,6 +296,7 @@ describe('app', () => {
await applicationGenerator(tree, { await applicationGenerator(tree, {
name: 'myApp', name: 'myApp',
style: 'css', style: 'css',
standaloneConfig: false,
}); });
const packageJson = readJson(tree, '/package.json'); const packageJson = readJson(tree, '/package.json');
@ -311,6 +353,7 @@ describe('app', () => {
name: 'myApp', name: 'myApp',
style: 'css', style: 'css',
linter: Linter.TsLint, linter: Linter.TsLint,
standaloneConfig: false,
}); });
const tslintJson = readJson(tree, 'apps/my-app/tslint.json'); const tslintJson = readJson(tree, 'apps/my-app/tslint.json');
@ -335,6 +378,7 @@ describe('app', () => {
name: 'myApp', name: 'myApp',
style: 'css', style: 'css',
js: true, js: true,
standaloneConfig: false,
}); });
expect(tree.exists('apps/my-app/pages/index.js')).toBeTruthy(); expect(tree.exists('apps/my-app/pages/index.js')).toBeTruthy();

View File

@ -63,8 +63,13 @@ export function addProject(host: Tree, options: NormalizedSchema) {
targets, targets,
}; };
addProjectConfiguration(host, options.projectName, { addProjectConfiguration(
...project, host,
...nxConfig, options.projectName,
}); {
...project,
...nxConfig,
},
options.standaloneConfig
);
} }

View File

@ -14,4 +14,5 @@ export interface Schema {
skipWorkspaceJson?: boolean; skipWorkspaceJson?: boolean;
js?: boolean; js?: boolean;
setParserOptionsProject?: boolean; setParserOptionsProject?: boolean;
standaloneConfig?: boolean;
} }

View File

@ -109,6 +109,11 @@
"type": "boolean", "type": "boolean",
"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
},
"standaloneConfig": {
"description": "Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json",
"type": "boolean",
"default": false
} }
}, },
"required": [] "required": []

View File

@ -10,7 +10,11 @@ describe('component', () => {
beforeEach(async () => { beforeEach(async () => {
projectName = 'my-app'; projectName = 'my-app';
tree = createTreeWithEmptyWorkspace(); tree = createTreeWithEmptyWorkspace();
await applicationGenerator(tree, { name: projectName, style: 'css' }); await applicationGenerator(tree, {
name: projectName,
style: 'css',
standaloneConfig: false,
});
}); });
it('should generate component in components directory', async () => { it('should generate component in components directory', async () => {

View File

@ -10,7 +10,11 @@ describe('component', () => {
beforeEach(async () => { beforeEach(async () => {
projectName = 'my-app'; projectName = 'my-app';
tree = createTreeWithEmptyWorkspace(); tree = createTreeWithEmptyWorkspace();
await applicationGenerator(tree, { name: projectName, style: 'css' }); await applicationGenerator(tree, {
name: projectName,
style: 'css',
standaloneConfig: false,
});
}); });
it('should generate component in pages directory', async () => { it('should generate component in pages directory', async () => {

View File

@ -31,7 +31,10 @@ describe('app', () => {
describe('not nested', () => { describe('not nested', () => {
it('should update workspace.json', async () => { it('should update workspace.json', async () => {
await applicationGenerator(tree, { name: 'myNodeApp' }); await applicationGenerator(tree, {
name: 'myNodeApp',
standaloneConfig: false,
});
const workspaceJson = readJson(tree, '/workspace.json'); const workspaceJson = readJson(tree, '/workspace.json');
const project = workspaceJson.projects['my-node-app']; const project = workspaceJson.projects['my-node-app'];
expect(project.root).toEqual('apps/my-node-app'); expect(project.root).toEqual('apps/my-node-app');
@ -79,7 +82,11 @@ describe('app', () => {
}); });
it('should update nx.json', async () => { it('should update nx.json', async () => {
await applicationGenerator(tree, { name: 'myNodeApp', tags: 'one,two' }); await applicationGenerator(tree, {
name: 'myNodeApp',
tags: 'one,two',
standaloneConfig: false,
});
const nxJson = readJson<NxJsonConfiguration>(tree, '/nx.json'); const nxJson = readJson<NxJsonConfiguration>(tree, '/nx.json');
expect(nxJson.projects).toEqual({ expect(nxJson.projects).toEqual({
'my-node-app': { 'my-node-app': {
@ -89,7 +96,10 @@ describe('app', () => {
}); });
it('should generate files', async () => { it('should generate files', async () => {
await applicationGenerator(tree, { name: 'myNodeApp' }); await applicationGenerator(tree, {
name: 'myNodeApp',
standaloneConfig: false,
});
expect(tree.exists(`apps/my-node-app/jest.config.js`)).toBeTruthy(); expect(tree.exists(`apps/my-node-app/jest.config.js`)).toBeTruthy();
expect(tree.exists('apps/my-node-app/src/main.ts')).toBeTruthy(); expect(tree.exists('apps/my-node-app/src/main.ts')).toBeTruthy();
@ -158,6 +168,7 @@ describe('app', () => {
await applicationGenerator(tree, { await applicationGenerator(tree, {
name: 'myNodeApp', name: 'myNodeApp',
directory: 'myDir', directory: 'myDir',
standaloneConfig: false,
}); });
const workspaceJson = readJson(tree, '/workspace.json'); const workspaceJson = readJson(tree, '/workspace.json');
@ -183,6 +194,7 @@ describe('app', () => {
name: 'myNodeApp', name: 'myNodeApp',
directory: 'myDir', directory: 'myDir',
tags: 'one,two', tags: 'one,two',
standaloneConfig: false,
}); });
const nxJson = readJson<NxJsonConfiguration>(tree, '/nx.json'); const nxJson = readJson<NxJsonConfiguration>(tree, '/nx.json');
expect(nxJson.projects).toEqual({ expect(nxJson.projects).toEqual({
@ -201,6 +213,7 @@ describe('app', () => {
await applicationGenerator(tree, { await applicationGenerator(tree, {
name: 'myNodeApp', name: 'myNodeApp',
directory: 'myDir', directory: 'myDir',
standaloneConfig: false,
}); });
// Make sure these exist // Make sure these exist
@ -237,6 +250,7 @@ describe('app', () => {
await applicationGenerator(tree, { await applicationGenerator(tree, {
name: 'myNodeApp', name: 'myNodeApp',
unitTestRunner: 'none', unitTestRunner: 'none',
standaloneConfig: false,
}); });
expect(tree.exists('jest.config.js')).toBeFalsy(); expect(tree.exists('jest.config.js')).toBeFalsy();
expect(tree.exists('apps/my-node-app/src/test-setup.ts')).toBeFalsy(); expect(tree.exists('apps/my-node-app/src/test-setup.ts')).toBeFalsy();
@ -268,6 +282,7 @@ describe('app', () => {
await applicationGenerator(tree, { await applicationGenerator(tree, {
name: 'myNodeApp', name: 'myNodeApp',
frontendProject: 'my-frontend', frontendProject: 'my-frontend',
standaloneConfig: false,
}); });
expect(tree.exists('apps/my-frontend/proxy.conf.json')).toBeTruthy(); expect(tree.exists('apps/my-frontend/proxy.conf.json')).toBeTruthy();
@ -284,11 +299,13 @@ describe('app', () => {
await applicationGenerator(tree, { await applicationGenerator(tree, {
name: 'cart', name: 'cart',
frontendProject: 'my-frontend', frontendProject: 'my-frontend',
standaloneConfig: false,
}); });
await applicationGenerator(tree, { await applicationGenerator(tree, {
name: 'billing', name: 'billing',
frontendProject: 'my-frontend', frontendProject: 'my-frontend',
standaloneConfig: false,
}); });
expect(tree.exists('apps/my-frontend/proxy.conf.json')).toBeTruthy(); expect(tree.exists('apps/my-frontend/proxy.conf.json')).toBeTruthy();
@ -305,6 +322,7 @@ describe('app', () => {
await applicationGenerator(tree, { await applicationGenerator(tree, {
name: 'myNodeApp', name: 'myNodeApp',
frontendProject: 'myFrontend', frontendProject: 'myFrontend',
standaloneConfig: false,
}); });
expect(tree.exists('apps/my-frontend/proxy.conf.json')).toBeTruthy(); expect(tree.exists('apps/my-frontend/proxy.conf.json')).toBeTruthy();

View File

@ -93,7 +93,12 @@ function addProject(tree: Tree, options: NormalizedSchema) {
project.targets.build = getBuildConfig(project, options); project.targets.build = getBuildConfig(project, options);
project.targets.serve = getServeConfig(options); project.targets.serve = getServeConfig(options);
addProjectConfiguration(tree, options.name, project); addProjectConfiguration(
tree,
options.name,
project,
options.standaloneConfig
);
const workspace = readWorkspaceConfiguration(tree); const workspace = readWorkspaceConfiguration(tree);

View File

@ -13,4 +13,5 @@ export interface Schema {
js?: boolean; js?: boolean;
pascalCaseFiles?: boolean; pascalCaseFiles?: boolean;
setParserOptionsProject?: boolean; setParserOptionsProject?: boolean;
standaloneConfig?: boolean;
} }

View File

@ -68,6 +68,11 @@
"type": "boolean", "type": "boolean",
"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
},
"standaloneConfig": {
"description": "Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json",
"type": "boolean",
"default": false
} }
}, },
"required": [] "required": []

View File

@ -13,7 +13,7 @@ describe('lib', () => {
describe('not nested', () => { describe('not nested', () => {
it('should update workspace.json', async () => { it('should update workspace.json', async () => {
await libraryGenerator(tree, { name: 'myLib' }); await libraryGenerator(tree, { name: 'myLib', standaloneConfig: false });
const workspaceJson = readJson(tree, '/workspace.json'); const workspaceJson = readJson(tree, '/workspace.json');
expect(workspaceJson.projects['my-lib'].root).toEqual('libs/my-lib'); expect(workspaceJson.projects['my-lib'].root).toEqual('libs/my-lib');
expect(workspaceJson.projects['my-lib'].architect.build).toBeUndefined(); expect(workspaceJson.projects['my-lib'].architect.build).toBeUndefined();
@ -38,6 +38,7 @@ describe('lib', () => {
name: 'myLib', name: 'myLib',
rootDir: './src', rootDir: './src',
buildable: true, buildable: true,
standaloneConfig: false,
}); });
const workspaceJson = readJson(tree, '/workspace.json'); const workspaceJson = readJson(tree, '/workspace.json');
expect( expect(
@ -47,7 +48,11 @@ describe('lib', () => {
}); });
it('should update nx.json', async () => { it('should update nx.json', async () => {
await libraryGenerator(tree, { name: 'myLib', tags: 'one,two' }); await libraryGenerator(tree, {
name: 'myLib',
tags: 'one,two',
standaloneConfig: false,
});
const nxJson = readJson<NxJsonConfiguration>(tree, '/nx.json'); const nxJson = readJson<NxJsonConfiguration>(tree, '/nx.json');
expect(nxJson.projects).toEqual({ expect(nxJson.projects).toEqual({
'my-lib': { 'my-lib': {
@ -57,7 +62,7 @@ describe('lib', () => {
}); });
it('should update root tsconfig.base.json', async () => { it('should update root tsconfig.base.json', async () => {
await libraryGenerator(tree, { name: 'myLib' }); await libraryGenerator(tree, { name: 'myLib', standaloneConfig: false });
const tsconfigJson = readJson(tree, '/tsconfig.base.json'); const tsconfigJson = readJson(tree, '/tsconfig.base.json');
expect(tsconfigJson.compilerOptions.paths['@proj/my-lib']).toEqual([ expect(tsconfigJson.compilerOptions.paths['@proj/my-lib']).toEqual([
'libs/my-lib/src/index.ts', 'libs/my-lib/src/index.ts',
@ -65,7 +70,7 @@ describe('lib', () => {
}); });
it('should create a local tsconfig.json', async () => { it('should create a local tsconfig.json', async () => {
await libraryGenerator(tree, { name: 'myLib' }); await libraryGenerator(tree, { name: 'myLib', standaloneConfig: false });
const tsconfigJson = readJson(tree, 'libs/my-lib/tsconfig.json'); const tsconfigJson = readJson(tree, 'libs/my-lib/tsconfig.json');
expect(tsconfigJson).toMatchInlineSnapshot(` expect(tsconfigJson).toMatchInlineSnapshot(`
Object { Object {
@ -85,20 +90,20 @@ describe('lib', () => {
}); });
it('should extend the local tsconfig.json with tsconfig.spec.json', async () => { it('should extend the local tsconfig.json with tsconfig.spec.json', async () => {
await libraryGenerator(tree, { name: 'myLib' }); await libraryGenerator(tree, { name: 'myLib', standaloneConfig: false });
const tsconfigJson = readJson(tree, 'libs/my-lib/tsconfig.spec.json'); const tsconfigJson = readJson(tree, 'libs/my-lib/tsconfig.spec.json');
expect(tsconfigJson.extends).toEqual('./tsconfig.json'); expect(tsconfigJson.extends).toEqual('./tsconfig.json');
}); });
it('should extend the local tsconfig.json with tsconfig.lib.json', async () => { it('should extend the local tsconfig.json with tsconfig.lib.json', async () => {
await libraryGenerator(tree, { name: 'myLib' }); await libraryGenerator(tree, { name: 'myLib', standaloneConfig: false });
const tsconfigJson = readJson(tree, 'libs/my-lib/tsconfig.lib.json'); const tsconfigJson = readJson(tree, 'libs/my-lib/tsconfig.lib.json');
expect(tsconfigJson.compilerOptions.types).toContain('node'); expect(tsconfigJson.compilerOptions.types).toContain('node');
expect(tsconfigJson.extends).toEqual('./tsconfig.json'); expect(tsconfigJson.extends).toEqual('./tsconfig.json');
}); });
it('should generate files', async () => { it('should generate files', async () => {
await libraryGenerator(tree, { name: 'myLib' }); await libraryGenerator(tree, { name: 'myLib', standaloneConfig: false });
expect(tree.exists(`libs/my-lib/jest.config.js`)).toBeTruthy(); expect(tree.exists(`libs/my-lib/jest.config.js`)).toBeTruthy();
expect(tree.exists('libs/my-lib/src/index.ts')).toBeTruthy(); expect(tree.exists('libs/my-lib/src/index.ts')).toBeTruthy();
@ -147,6 +152,7 @@ describe('lib', () => {
name: 'myLib', name: 'myLib',
directory: 'myDir', directory: 'myDir',
tags: 'one', tags: 'one',
standaloneConfig: false,
}); });
const nxJson = readJson<NxJsonConfiguration>(tree, '/nx.json'); const nxJson = readJson<NxJsonConfiguration>(tree, '/nx.json');
expect(nxJson.projects).toEqual({ expect(nxJson.projects).toEqual({
@ -159,6 +165,7 @@ describe('lib', () => {
name: 'myLib2', name: 'myLib2',
directory: 'myDir', directory: 'myDir',
tags: 'one,two', tags: 'one,two',
standaloneConfig: false,
}); });
const nxJson2 = readJson<NxJsonConfiguration>(tree, '/nx.json'); const nxJson2 = readJson<NxJsonConfiguration>(tree, '/nx.json');
expect(nxJson2.projects).toEqual({ expect(nxJson2.projects).toEqual({
@ -172,13 +179,21 @@ describe('lib', () => {
}); });
it('should generate files', async () => { it('should generate files', async () => {
await libraryGenerator(tree, { name: 'myLib', directory: 'myDir' }); await libraryGenerator(tree, {
name: 'myLib',
directory: 'myDir',
standaloneConfig: false,
});
expect(tree.exists(`libs/my-dir/my-lib/jest.config.js`)).toBeTruthy(); expect(tree.exists(`libs/my-dir/my-lib/jest.config.js`)).toBeTruthy();
expect(tree.exists('libs/my-dir/my-lib/src/index.ts')).toBeTruthy(); expect(tree.exists('libs/my-dir/my-lib/src/index.ts')).toBeTruthy();
}); });
it('should update workspace.json', async () => { it('should update workspace.json', async () => {
await libraryGenerator(tree, { name: 'myLib', directory: 'myDir' }); await libraryGenerator(tree, {
name: 'myLib',
directory: 'myDir',
standaloneConfig: false,
});
const workspaceJson = readJson(tree, '/workspace.json'); const workspaceJson = readJson(tree, '/workspace.json');
expect(workspaceJson.projects['my-dir-my-lib'].root).toEqual( expect(workspaceJson.projects['my-dir-my-lib'].root).toEqual(
@ -193,7 +208,11 @@ describe('lib', () => {
}); });
it('should update tsconfig.json', async () => { it('should update tsconfig.json', async () => {
await libraryGenerator(tree, { name: 'myLib', directory: 'myDir' }); await libraryGenerator(tree, {
name: 'myLib',
directory: 'myDir',
standaloneConfig: false,
});
const tsconfigJson = readJson(tree, '/tsconfig.base.json'); const tsconfigJson = readJson(tree, '/tsconfig.base.json');
expect(tsconfigJson.compilerOptions.paths['@proj/my-dir/my-lib']).toEqual( expect(tsconfigJson.compilerOptions.paths['@proj/my-dir/my-lib']).toEqual(
['libs/my-dir/my-lib/src/index.ts'] ['libs/my-dir/my-lib/src/index.ts']
@ -211,6 +230,7 @@ describe('lib', () => {
name: 'myLib', name: 'myLib',
directory: 'myDir', directory: 'myDir',
publishable: true, publishable: true,
standaloneConfig: false,
}); });
} catch (e) { } catch (e) {
expect(e.message).toContain( expect(e.message).toContain(
@ -220,7 +240,11 @@ describe('lib', () => {
}); });
it('should create a local tsconfig.json', async () => { it('should create a local tsconfig.json', async () => {
await libraryGenerator(tree, { name: 'myLib', directory: 'myDir' }); await libraryGenerator(tree, {
name: 'myLib',
directory: 'myDir',
standaloneConfig: false,
});
const tsconfigJson = readJson(tree, 'libs/my-dir/my-lib/tsconfig.json'); const tsconfigJson = readJson(tree, 'libs/my-dir/my-lib/tsconfig.json');
expect(tsconfigJson.extends).toEqual('../../../tsconfig.base.json'); expect(tsconfigJson.extends).toEqual('../../../tsconfig.base.json');
@ -239,6 +263,7 @@ describe('lib', () => {
name: 'myLib', name: 'myLib',
directory: 'myDir', directory: 'myDir',
simpleModuleName: true, simpleModuleName: true,
standaloneConfig: false,
}); });
expect(tree.exists(`libs/my-dir/my-lib/jest.config.js`)).toBeTruthy(); expect(tree.exists(`libs/my-dir/my-lib/jest.config.js`)).toBeTruthy();
expect(tree.exists('libs/my-dir/my-lib/src/index.ts')).toBeTruthy(); expect(tree.exists('libs/my-dir/my-lib/src/index.ts')).toBeTruthy();
@ -253,7 +278,11 @@ describe('lib', () => {
describe('--unit-test-runner none', () => { describe('--unit-test-runner none', () => {
it('should not generate test configuration', async () => { it('should not generate test configuration', async () => {
await libraryGenerator(tree, { name: 'myLib', unitTestRunner: 'none' }); await libraryGenerator(tree, {
name: 'myLib',
unitTestRunner: 'none',
standaloneConfig: false,
});
expect(tree.exists('libs/my-lib/tsconfig.spec.json')).toBeFalsy(); expect(tree.exists('libs/my-lib/tsconfig.spec.json')).toBeFalsy();
expect(tree.exists('libs/my-lib/jest.config.js')).toBeFalsy(); expect(tree.exists('libs/my-lib/jest.config.js')).toBeFalsy();
expect(tree.exists('libs/my-lib/lib/my-lib.spec.ts')).toBeFalsy(); expect(tree.exists('libs/my-lib/lib/my-lib.spec.ts')).toBeFalsy();
@ -282,7 +311,11 @@ describe('lib', () => {
describe('buildable package', () => { describe('buildable package', () => {
it('should have a builder defined', async () => { it('should have a builder defined', async () => {
await libraryGenerator(tree, { name: 'myLib', buildable: true }); await libraryGenerator(tree, {
name: 'myLib',
buildable: true,
standaloneConfig: false,
});
const workspaceJson = readJson(tree, '/workspace.json'); const workspaceJson = readJson(tree, '/workspace.json');
expect(workspaceJson.projects['my-lib'].root).toEqual('libs/my-lib'); expect(workspaceJson.projects['my-lib'].root).toEqual('libs/my-lib');
@ -314,6 +347,7 @@ describe('lib', () => {
name: 'myLib', name: 'myLib',
publishable: true, publishable: true,
importPath: '@proj/mylib', importPath: '@proj/mylib',
standaloneConfig: false,
}); });
const workspaceJson = readJson(tree, '/workspace.json'); const workspaceJson = readJson(tree, '/workspace.json');
@ -327,6 +361,7 @@ describe('lib', () => {
name: 'mylib', name: 'mylib',
publishable: true, publishable: true,
importPath: '@proj/mylib', importPath: '@proj/mylib',
standaloneConfig: false,
}); });
let packageJsonContent = readJson(tree, 'libs/mylib/package.json'); let packageJsonContent = readJson(tree, 'libs/mylib/package.json');
@ -342,6 +377,7 @@ describe('lib', () => {
publishable: true, publishable: true,
directory: 'myDir', directory: 'myDir',
importPath: '@myorg/lib', importPath: '@myorg/lib',
standaloneConfig: false,
}); });
const packageJson = readJson(tree, 'libs/my-dir/my-lib/package.json'); const packageJson = readJson(tree, 'libs/my-dir/my-lib/package.json');
const tsconfigJson = readJson(tree, '/tsconfig.base.json'); const tsconfigJson = readJson(tree, '/tsconfig.base.json');
@ -357,6 +393,7 @@ describe('lib', () => {
name: 'myLib1', name: 'myLib1',
publishable: true, publishable: true,
importPath: '@myorg/lib', importPath: '@myorg/lib',
standaloneConfig: false,
}); });
try { try {
@ -364,6 +401,7 @@ describe('lib', () => {
name: 'myLib2', name: 'myLib2',
publishable: true, publishable: true,
importPath: '@myorg/lib', importPath: '@myorg/lib',
standaloneConfig: false,
}); });
} catch (e) { } catch (e) {
expect(e.message).toContain( expect(e.message).toContain(

View File

@ -18,4 +18,5 @@ export interface Schema {
js?: boolean; js?: boolean;
pascalCaseFiles?: boolean; pascalCaseFiles?: boolean;
strict?: boolean; strict?: boolean;
standaloneConfig?: boolean;
} }

View File

@ -101,6 +101,11 @@
"type": "boolean", "type": "boolean",
"description": "Whether to enable tsconfig strict mode or not.", "description": "Whether to enable tsconfig strict mode or not.",
"default": false "default": false
},
"standaloneConfig": {
"description": "Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json",
"type": "boolean",
"default": false
} }
}, },
"required": ["name"] "required": ["name"]

View File

@ -25,6 +25,7 @@ describe('NxPlugin e2e-project Generator', () => {
pluginName: 'my-plugin', pluginName: 'my-plugin',
pluginOutputPath: `dist/libs/my-plugin`, pluginOutputPath: `dist/libs/my-plugin`,
npmPackageName: '@proj/my-plugin', npmPackageName: '@proj/my-plugin',
standaloneConfig: false,
}) })
).resolves.not.toThrow(); ).resolves.not.toThrow();
@ -33,6 +34,7 @@ describe('NxPlugin e2e-project Generator', () => {
pluginName: 'my-nonexistentplugin', pluginName: 'my-nonexistentplugin',
pluginOutputPath: `dist/libs/my-nonexistentplugin`, pluginOutputPath: `dist/libs/my-nonexistentplugin`,
npmPackageName: '@proj/my-nonexistentplugin', npmPackageName: '@proj/my-nonexistentplugin',
standaloneConfig: false,
}) })
).rejects.toThrow(); ).rejects.toThrow();
}); });
@ -42,6 +44,7 @@ describe('NxPlugin e2e-project Generator', () => {
pluginName: 'my-plugin', pluginName: 'my-plugin',
pluginOutputPath: `dist/libs/my-plugin`, pluginOutputPath: `dist/libs/my-plugin`,
npmPackageName: '@proj/my-plugin', npmPackageName: '@proj/my-plugin',
standaloneConfig: false,
}); });
expect(tree.exists('apps/my-plugin-e2e/tsconfig.json')).toBeTruthy(); expect(tree.exists('apps/my-plugin-e2e/tsconfig.json')).toBeTruthy();
@ -56,6 +59,7 @@ describe('NxPlugin e2e-project Generator', () => {
pluginOutputPath: `dist/libs/namespace/my-plugin`, pluginOutputPath: `dist/libs/namespace/my-plugin`,
npmPackageName: '@proj/namespace-my-plugin', npmPackageName: '@proj/namespace-my-plugin',
projectDirectory: 'namespace/my-plugin', projectDirectory: 'namespace/my-plugin',
standaloneConfig: false,
}); });
const project = readProjectConfiguration(tree, 'my-plugin-e2e'); const project = readProjectConfiguration(tree, 'my-plugin-e2e');
@ -67,6 +71,7 @@ describe('NxPlugin e2e-project Generator', () => {
pluginName: 'my-plugin', pluginName: 'my-plugin',
pluginOutputPath: `dist/libs/my-plugin`, pluginOutputPath: `dist/libs/my-plugin`,
npmPackageName: '@proj/my-plugin', npmPackageName: '@proj/my-plugin',
standaloneConfig: false,
}); });
expect(readJson(tree, 'nx.json')).toMatchObject({ expect(readJson(tree, 'nx.json')).toMatchObject({
@ -84,6 +89,7 @@ describe('NxPlugin e2e-project Generator', () => {
pluginName: 'my-plugin', pluginName: 'my-plugin',
pluginOutputPath: `dist/libs/my-plugin`, pluginOutputPath: `dist/libs/my-plugin`,
npmPackageName: '@proj/my-plugin', npmPackageName: '@proj/my-plugin',
standaloneConfig: false,
}); });
const project = readProjectConfiguration(tree, 'my-plugin-e2e'); const project = readProjectConfiguration(tree, 'my-plugin-e2e');
@ -106,6 +112,7 @@ describe('NxPlugin e2e-project Generator', () => {
pluginName: 'my-plugin', pluginName: 'my-plugin',
pluginOutputPath: `dist/libs/my-plugin`, pluginOutputPath: `dist/libs/my-plugin`,
npmPackageName: '@proj/my-plugin', npmPackageName: '@proj/my-plugin',
standaloneConfig: false,
}); });
const project = readProjectConfiguration(tree, 'my-plugin-e2e'); const project = readProjectConfiguration(tree, 'my-plugin-e2e');

View File

@ -56,23 +56,28 @@ function addFiles(host: Tree, options: NormalizedSchema) {
} }
function updateWorkspaceConfiguration(host: Tree, options: NormalizedSchema) { function updateWorkspaceConfiguration(host: Tree, options: NormalizedSchema) {
addProjectConfiguration(host, options.projectName, { addProjectConfiguration(
root: options.projectRoot, host,
projectType: 'application', options.projectName,
sourceRoot: `${options.projectRoot}/src`, {
targets: { root: options.projectRoot,
e2e: { projectType: 'application',
executor: '@nrwl/nx-plugin:e2e', sourceRoot: `${options.projectRoot}/src`,
options: { targets: {
target: `${options.pluginName}:build`, e2e: {
npmPackageName: options.npmPackageName, executor: '@nrwl/nx-plugin:e2e',
pluginOutputPath: options.pluginOutputPath, options: {
target: `${options.pluginName}:build`,
npmPackageName: options.npmPackageName,
pluginOutputPath: options.pluginOutputPath,
},
}, },
}, },
tags: [],
implicitDependencies: [options.pluginName],
}, },
tags: [], options.standaloneConfig
implicitDependencies: [options.pluginName], );
});
} }
async function addJest(host: Tree, options: NormalizedSchema) { async function addJest(host: Tree, options: NormalizedSchema) {

View File

@ -4,4 +4,5 @@ export interface Schema {
projectDirectory?: string; projectDirectory?: string;
pluginOutputPath?: string; pluginOutputPath?: string;
jestConfig?: string; jestConfig?: string;
standaloneConfig?: boolean;
} }

View File

@ -29,6 +29,11 @@
"type": "string", "type": "string",
"description": "Spec tsconfig file", "description": "Spec tsconfig file",
"x-deprecated": true "x-deprecated": true
},
"standaloneConfig": {
"description": "Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json",
"type": "boolean",
"default": false
} }
}, },
"required": ["pluginName", "npmPackageName"], "required": ["pluginName", "npmPackageName"],

View File

@ -150,6 +150,7 @@ export async function pluginGenerator(host: Tree, schema: Schema) {
projectDirectory: options.projectDirectory, projectDirectory: options.projectDirectory,
pluginOutputPath: `dist/${options.libsDir}/${options.projectDirectory}`, pluginOutputPath: `dist/${options.libsDir}/${options.projectDirectory}`,
npmPackageName: options.npmPackageName, npmPackageName: options.npmPackageName,
standaloneConfig: options.standaloneConfig,
}); });
await formatFiles(host); await formatFiles(host);

View File

@ -9,4 +9,5 @@ export interface Schema {
tags?: string; tags?: string;
unitTestRunner: 'jest' | 'none'; unitTestRunner: 'jest' | 'none';
linter: Linter; linter: Linter;
standaloneConfig?: boolean;
} }

View File

@ -55,6 +55,11 @@
"type": "boolean", "type": "boolean",
"default": false, "default": false,
"description": "Do not update tsconfig.json for development experience." "description": "Do not update tsconfig.json for development experience."
},
"standaloneConfig": {
"description": "Split the project configuration into <projectRoot>/project.json rather than including it inside workspace.json",
"type": "boolean",
"default": false
} }
}, },
"required": ["name"], "required": ["name"],

View File

@ -20,6 +20,7 @@ describe('app', () => {
linter: Linter.EsLint, linter: Linter.EsLint,
style: 'css', style: 'css',
strict: false, strict: false,
standaloneConfig: false,
}; };
beforeEach(() => { beforeEach(() => {

View File

@ -22,10 +22,15 @@ export function addProject(host, options: NormalizedSchema) {
}, },
}; };
addProjectConfiguration(host, options.projectName, { addProjectConfiguration(
...project, host,
...nxConfig, options.projectName,
}); {
...project,
...nxConfig,
},
options.standaloneConfig
);
} }
function maybeJs(options: NormalizedSchema, path: string): string { function maybeJs(options: NormalizedSchema, path: string): string {

View File

@ -19,6 +19,7 @@ export interface Schema {
globalCss?: boolean; globalCss?: boolean;
strict?: boolean; strict?: boolean;
setParserOptionsProject?: boolean; setParserOptionsProject?: boolean;
standaloneConfig?: boolean;
} }
export interface NormalizedSchema extends Schema { export interface NormalizedSchema extends Schema {

Some files were not shown because too many files have changed in this diff Show More