From 081ff42955d8293195414a3cc6542672071e65d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leosvel=20P=C3=A9rez=20Espinosa?= Date: Thu, 10 Mar 2022 13:09:04 +0000 Subject: [PATCH] fix(angular): handle newProjectRoot correctly when generating apps and libs (#9255) --- .../application/application.spec.ts | 10 +++--- .../src/generators/application/application.ts | 28 +++++---------- .../src/generators/application/lib/add-e2e.ts | 17 ++-------- .../application/lib/create-files.ts | 8 +---- .../application/lib/normalize-options.ts | 23 ++++++++++++- .../application/lib/normalized-schema.ts | 2 ++ .../application/lib/update-config-files.ts | 34 ++++++++++--------- .../library/lib/normalize-options.ts | 20 ++++++++++- .../library/lib/normalized-schema.ts | 1 + .../generators/library/lib/update-project.ts | 24 +++++++------ .../src/generators/library/library.spec.ts | 25 ++++++++++++++ .../angular/src/generators/library/library.ts | 8 ++++- .../src/generators/project-configuration.ts | 4 ++- .../preset/__snapshots__/preset.spec.ts.snap | 6 ++-- 14 files changed, 129 insertions(+), 81 deletions(-) diff --git a/packages/angular/src/generators/application/application.spec.ts b/packages/angular/src/generators/application/application.spec.ts index b6852588fc102..94cb4ebcbaf67 100644 --- a/packages/angular/src/generators/application/application.spec.ts +++ b/packages/angular/src/generators/application/application.spec.ts @@ -159,11 +159,7 @@ describe('app', () => { expect(appE2eSpec).toContain('Welcome my-app-with-prefix'); }); - // TODO: this should work - // This has been carried over from the Angular Devkit Schematic - // It seems like Jest is failing as it's trying to look for the - // tsconfig in the incorrect place - xit('should work if the new project root is changed', async () => { + it('should work if the new project root is changed', async () => { // ARRANGE updateJson(appTree, '/workspace.json', (json) => ({ ...json, @@ -171,7 +167,9 @@ describe('app', () => { })); // ACT - await generateApp(appTree); + await generateApp(appTree, 'my-app', { + e2eTestRunner: E2eTestRunner.Protractor, + }); // ASSERT expect(appTree.exists('apps/my-app/src/main.ts')).toEqual(true); diff --git a/packages/angular/src/generators/application/application.ts b/packages/angular/src/generators/application/application.ts index fdb6fedf648ec..b374f48990f86 100644 --- a/packages/angular/src/generators/application/application.ts +++ b/packages/angular/src/generators/application/application.ts @@ -1,9 +1,7 @@ import { formatFiles, - getWorkspacePath, installPackagesTask, moveFilesToNewDirectory, - readJson, Tree, } from '@nrwl/devkit'; import { wrapAngularDevkitSchematic } from '@nrwl/devkit/ngcli-adapter'; @@ -36,20 +34,6 @@ export async function applicationGenerator( ) { const options = normalizeOptions(host, schema); - // Determine the roots where @schematics/angular will place the projects - // This is not where the projects actually end up - const workspaceJsonPath = getWorkspacePath(host); - let newProjectRoot = null; - if (workspaceJsonPath) { - ({ newProjectRoot } = readJson(host, workspaceJsonPath)); - } - const appProjectRoot = newProjectRoot - ? `${newProjectRoot}/${options.name}` - : options.name; - const e2eProjectRoot = newProjectRoot - ? `${newProjectRoot}/${options.e2eProjectName}` - : `${options.name}/e2e`; - await angularInitGenerator(host, { ...options, skipFormat: true, @@ -72,9 +56,15 @@ export async function applicationGenerator( skipPackageJson: options.skipPackageJson, }); - createFiles(host, options, appProjectRoot); + if (options.ngCliSchematicAppRoot !== options.appProjectRoot) { + moveFilesToNewDirectory( + host, + options.ngCliSchematicAppRoot, + options.appProjectRoot + ); + } - moveFilesToNewDirectory(host, appProjectRoot, options.appProjectRoot); + createFiles(host, options); updateConfigFiles(host, options); updateAppComponentTemplate(host, options); @@ -114,7 +104,7 @@ export async function applicationGenerator( addLinting(host, options); await addUnitTestRunner(host, options); - await addE2e(host, options, e2eProjectRoot); + await addE2e(host, options); updateEditorTsConfig(host, options); if (options.backendProject) { diff --git a/packages/angular/src/generators/application/lib/add-e2e.ts b/packages/angular/src/generators/application/lib/add-e2e.ts index 61c2b4c02126d..e04c6c08e5056 100644 --- a/packages/angular/src/generators/application/lib/add-e2e.ts +++ b/packages/angular/src/generators/application/lib/add-e2e.ts @@ -12,24 +12,11 @@ import { convertToNxProjectGenerator } from '@nrwl/workspace'; import { Linter, lintProjectGenerator } from '@nrwl/linter'; import { getWorkspaceLayout, joinPathFragments } from '@nrwl/devkit'; -/** - * Add E2E Config - * - * @param tree Nx Devkit Virtual Tree - * @param options Normalized Schema - * @param e2eProjectRoot Raw E2E Project Root that Angular tries to write to - * - * @returns Function to run to add Cypres config after intial app files have been moved to correct location - */ -export async function addE2e( - tree: Tree, - options: NormalizedSchema, - e2eProjectRoot: string -) { +export async function addE2e(tree: Tree, options: NormalizedSchema) { if (options.e2eTestRunner === E2eTestRunner.Protractor) { await addProtractor(tree, options); } else { - removeScaffoldedE2e(tree, options, e2eProjectRoot); + removeScaffoldedE2e(tree, options, options.ngCliSchematicE2ERoot); } if (options.e2eTestRunner === 'cypress') { diff --git a/packages/angular/src/generators/application/lib/create-files.ts b/packages/angular/src/generators/application/lib/create-files.ts index ac5153d6a86cb..ed1a081d8c68a 100644 --- a/packages/angular/src/generators/application/lib/create-files.ts +++ b/packages/angular/src/generators/application/lib/create-files.ts @@ -3,13 +3,7 @@ import { generateFiles, joinPathFragments } from '@nrwl/devkit'; import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript'; import type { NormalizedSchema } from './normalized-schema'; -export function createFiles( - host: Tree, - options: NormalizedSchema, - appProjectRoot: string -) { - host.delete(`${appProjectRoot}/src/favicon.ico`); - +export function createFiles(host: Tree, options: NormalizedSchema) { generateFiles( host, joinPathFragments(__dirname, '../files'), diff --git a/packages/angular/src/generators/application/lib/normalize-options.ts b/packages/angular/src/generators/application/lib/normalize-options.ts index f8a719107156d..e75760eae9c70 100644 --- a/packages/angular/src/generators/application/lib/normalize-options.ts +++ b/packages/angular/src/generators/application/lib/normalize-options.ts @@ -1,4 +1,9 @@ -import { joinPathFragments, Tree } from '@nrwl/devkit'; +import { + getWorkspacePath, + joinPathFragments, + readJson, + Tree, +} from '@nrwl/devkit'; import type { Schema } from '../schema'; import type { NormalizedSchema } from './normalized-schema'; @@ -35,6 +40,20 @@ export function normalizeOptions( options.standaloneConfig = options.standaloneConfig ?? standaloneAsDefault; + // Determine the roots where @schematics/angular will place the projects + // This might not be where the projects actually end up + const workspaceJsonPath = getWorkspacePath(host); + let newProjectRoot = null; + if (workspaceJsonPath) { + ({ newProjectRoot } = readJson(host, workspaceJsonPath)); + } + const ngCliSchematicAppRoot = newProjectRoot + ? `${newProjectRoot}/${appProjectName}` + : appProjectName; + const ngCliSchematicE2ERoot = newProjectRoot + ? `${newProjectRoot}/${e2eProjectName}` + : `${appProjectName}/e2e`; + // Set defaults and then overwrite with user options return { style: 'css', @@ -54,5 +73,7 @@ export function normalizeOptions( e2eProjectRoot, e2eProjectName, parsedTags, + ngCliSchematicAppRoot, + ngCliSchematicE2ERoot, }; } diff --git a/packages/angular/src/generators/application/lib/normalized-schema.ts b/packages/angular/src/generators/application/lib/normalized-schema.ts index 14573867fc903..27e2e03f6a4b3 100644 --- a/packages/angular/src/generators/application/lib/normalized-schema.ts +++ b/packages/angular/src/generators/application/lib/normalized-schema.ts @@ -10,4 +10,6 @@ export interface NormalizedSchema extends Schema { e2eProjectName: string; e2eProjectRoot: string; parsedTags: string[]; + ngCliSchematicAppRoot: string; + ngCliSchematicE2ERoot: string; } diff --git a/packages/angular/src/generators/application/lib/update-config-files.ts b/packages/angular/src/generators/application/lib/update-config-files.ts index 22a9132b8bb00..af991b4c75807 100644 --- a/packages/angular/src/generators/application/lib/update-config-files.ts +++ b/packages/angular/src/generators/application/lib/update-config-files.ts @@ -38,42 +38,44 @@ function updateAppAndE2EProjectConfigurations( options: NormalizedSchema ) { // workspace.json - const project = readProjectConfiguration(host, options.name); + let project = readProjectConfiguration(host, options.name); - let fixedProject = replaceAppNameWithPath( - project, - options.name, - options.appProjectRoot - ); + if (options.ngCliSchematicAppRoot !== options.appProjectRoot) { + project = replaceAppNameWithPath( + project, + options.ngCliSchematicAppRoot, + options.appProjectRoot + ); + } - delete fixedProject.targets.test; + delete project.targets.test; // Ensure the outputs property comes after the executor for // better readability. - const { executor, ...rest } = fixedProject.targets.build; - fixedProject.targets.build = { + const { executor, ...rest } = project.targets.build; + project.targets.build = { executor, outputs: ['{options.outputPath}'], ...rest, }; - if (fixedProject.generators) { - delete fixedProject.generators; + if (project.generators) { + delete project.generators; } if (options.port) { - fixedProject.targets.serve = { - ...fixedProject.targets.serve, + project.targets.serve = { + ...project.targets.serve, options: { - ...fixedProject.targets.serve.options, + ...project.targets.serve.options, port: options.port, }, }; } - fixedProject.tags = options.parsedTags; + project.tags = options.parsedTags; - updateProjectConfiguration(host, options.name, fixedProject); + updateProjectConfiguration(host, options.name, project); if (options.unitTestRunner === UnitTestRunner.None) { host.delete(`${options.appProjectRoot}/src/app/app.component.spec.ts`); diff --git a/packages/angular/src/generators/library/lib/normalize-options.ts b/packages/angular/src/generators/library/lib/normalize-options.ts index 9685e8dd7e52a..cbb5db8792346 100644 --- a/packages/angular/src/generators/library/lib/normalize-options.ts +++ b/packages/angular/src/generators/library/lib/normalize-options.ts @@ -1,4 +1,10 @@ -import { getWorkspaceLayout, joinPathFragments, Tree } from '@nrwl/devkit'; +import { + getWorkspaceLayout, + getWorkspacePath, + joinPathFragments, + readJson, + Tree, +} from '@nrwl/devkit'; import { Schema } from '../schema'; import { NormalizedSchema } from './normalized-schema'; import { names } from '@nrwl/devkit'; @@ -51,6 +57,17 @@ export function normalizeOptions( const importPath = options.importPath || `@${defaultPrefix}/${projectDirectory}`; + // Determine the roots where @schematics/angular will place the projects + // This might not be where the projects actually end up + const workspaceJsonPath = getWorkspacePath(host); + let newProjectRoot = null; + if (workspaceJsonPath) { + ({ newProjectRoot } = readJson(host, workspaceJsonPath)); + } + const ngCliSchematicLibRoot = newProjectRoot + ? `${newProjectRoot}/${projectName}` + : projectName; + return { ...options, linter: options.linter ?? Linter.EsLint, @@ -65,5 +82,6 @@ export function normalizeOptions( parsedTags, fileName, importPath, + ngCliSchematicLibRoot, }; } diff --git a/packages/angular/src/generators/library/lib/normalized-schema.ts b/packages/angular/src/generators/library/lib/normalized-schema.ts index 68a12aa4fc83b..3bd193e2ff419 100644 --- a/packages/angular/src/generators/library/lib/normalized-schema.ts +++ b/packages/angular/src/generators/library/lib/normalized-schema.ts @@ -12,4 +12,5 @@ export interface NormalizedSchema extends Schema { moduleName: string; projectDirectory: string; parsedTags: string[]; + ngCliSchematicLibRoot: string; } diff --git a/packages/angular/src/generators/library/lib/update-project.ts b/packages/angular/src/generators/library/lib/update-project.ts index acc4856cd82ad..f8b6e58afa798 100644 --- a/packages/angular/src/generators/library/lib/update-project.ts +++ b/packages/angular/src/generators/library/lib/update-project.ts @@ -129,23 +129,25 @@ function createFiles(host: Tree, options: NormalizedSchema) { } function fixProjectWorkspaceConfig(host: Tree, options: NormalizedSchema) { - const project = readProjectConfiguration(host, options.name); + let project = readProjectConfiguration(host, options.name); project.tags = options.parsedTags; - const fixedProject = replaceAppNameWithPath( - project, - options.name, - options.projectRoot - ); + if (options.ngCliSchematicLibRoot !== options.projectRoot) { + project = replaceAppNameWithPath( + project, + options.ngCliSchematicLibRoot, + options.projectRoot + ); + } if (!options.publishable && !options.buildable) { - delete fixedProject.targets.build; + delete project.targets.build; } else { // Set the right builder for the type of library. // Ensure the outputs property comes after the builder for // better readability. - const { executor, ...rest } = fixedProject.targets.build; - fixedProject.targets.build = { + const { executor, ...rest } = project.targets.build; + project.targets.build = { executor: options.publishable ? '@nrwl/angular:package' : '@nrwl/angular:ng-packagr-lite', @@ -160,9 +162,9 @@ function fixProjectWorkspaceConfig(host: Tree, options: NormalizedSchema) { }; } - delete fixedProject.targets.test; + delete project.targets.test; - updateProjectConfiguration(host, options.name, fixedProject); + updateProjectConfiguration(host, options.name, project); } function updateProjectTsConfig(host: Tree, options: NormalizedSchema) { diff --git a/packages/angular/src/generators/library/library.spec.ts b/packages/angular/src/generators/library/library.spec.ts index fa70df8956e08..285d09e1d50b7 100644 --- a/packages/angular/src/generators/library/library.spec.ts +++ b/packages/angular/src/generators/library/library.spec.ts @@ -457,6 +457,31 @@ describe('lib', () => { ).toBeFalsy(); }); + it('should work if the new project root is changed', async () => { + // ARRANGE + updateJson(tree, 'workspace.json', (json) => ({ + ...json, + newProjectRoot: 'newProjectRoot', + })); + + // ACT + await runLibraryGeneratorWithOpts(); + + // ASSERT + expect(tree.exists('libs/my-lib/src/index.ts')).toBeTruthy(); + expect(tree.exists('libs/my-lib/src/lib/my-lib.module.ts')).toBeTruthy(); + expect( + tree.exists('libs/my-lib/src/lib/my-lib.component.ts') + ).toBeFalsy(); + expect( + tree.exists('libs/my-lib/src/lib/my-lib.component.spec.ts') + ).toBeFalsy(); + expect(tree.exists('libs/my-lib/src/lib/my-lib.service.ts')).toBeFalsy(); + expect( + tree.exists('libs/my-lib/src/lib/my-lib.service.spec.ts') + ).toBeFalsy(); + }); + it('should default the prefix to npmScope', async () => { // ACT await runLibraryGeneratorWithOpts(); diff --git a/packages/angular/src/generators/library/library.ts b/packages/angular/src/generators/library/library.ts index 947ccf32fd75b..918b110def257 100644 --- a/packages/angular/src/generators/library/library.ts +++ b/packages/angular/src/generators/library/library.ts @@ -63,7 +63,13 @@ export async function libraryGenerator(host: Tree, schema: Partial) { skipTsConfig: true, }); - moveFilesToNewDirectory(host, options.name, options.projectRoot); + if (options.ngCliSchematicLibRoot !== options.projectRoot) { + moveFilesToNewDirectory( + host, + options.ngCliSchematicLibRoot, + options.projectRoot + ); + } await updateProject(host, options); updateTsConfig(host, options); await addUnitTestRunner(host, options); diff --git a/packages/devkit/src/generators/project-configuration.ts b/packages/devkit/src/generators/project-configuration.ts index 13eaf30f05c01..dc517ba38727b 100644 --- a/packages/devkit/src/generators/project-configuration.ts +++ b/packages/devkit/src/generators/project-configuration.ts @@ -189,7 +189,9 @@ export function updateWorkspaceConfiguration( ...json, version: workspaceConfig.version, }; - delete (config as any).newProjectRoot; + if (!(workspaceConfig as any).newProjectRoot) { + delete (config as any).newProjectRoot; + } return config; }); } diff --git a/packages/workspace/src/generators/preset/__snapshots__/preset.spec.ts.snap b/packages/workspace/src/generators/preset/__snapshots__/preset.spec.ts.snap index acdfe7b52ce04..a48a3b470d898 100644 --- a/packages/workspace/src/generators/preset/__snapshots__/preset.spec.ts.snap +++ b/packages/workspace/src/generators/preset/__snapshots__/preset.spec.ts.snap @@ -2,12 +2,12 @@ exports[`preset should create files (preset = angular) 1`] = ` Array [ - "src", - "tsconfig.editor.json", - "tsconfig.json", ".browserslistrc", "tsconfig.app.json", "tsconfig.spec.json", + "src", + "tsconfig.editor.json", + "tsconfig.json", ".eslintrc.json", "jest.config.js", ]