diff --git a/docs/generated/cli/init.md b/docs/generated/cli/init.md index 25a3d60b02e5b..88b941ff125c2 100644 --- a/docs/generated/cli/init.md +++ b/docs/generated/cli/init.md @@ -14,3 +14,17 @@ nx init ``` Install `nx` globally to invoke the command directly using `nx`, or use `npx nx`, `yarn nx`, or `pnpm nx`. + +## Options + +### help + +Type: `boolean` + +Show help + +### version + +Type: `boolean` + +Show version number diff --git a/docs/generated/packages/nx/documents/init.md b/docs/generated/packages/nx/documents/init.md index 25a3d60b02e5b..88b941ff125c2 100644 --- a/docs/generated/packages/nx/documents/init.md +++ b/docs/generated/packages/nx/documents/init.md @@ -14,3 +14,17 @@ nx init ``` Install `nx` globally to invoke the command directly using `nx`, or use `npx nx`, `yarn nx`, or `pnpm nx`. + +## Options + +### help + +Type: `boolean` + +Show help + +### version + +Type: `boolean` + +Show version number diff --git a/e2e/nx-init/src/nx-init-angular.test.ts b/e2e/nx-init/src/nx-init-angular.test.ts index 1ae516a92ddc4..98002fdc5c3f9 100644 --- a/e2e/nx-init/src/nx-init-angular.test.ts +++ b/e2e/nx-init/src/nx-init-angular.test.ts @@ -28,7 +28,7 @@ describe('nx init (Angular CLI)', () => { cleanupProject(); }); - it('should successfully convert an Angular CLI workspace to an Nx workspace', () => { + it('should successfully convert an Angular CLI workspace to an Nx standalone workspace', () => { const output = runCommand( `${pmc.runUninstalledPackage} nx@${getPublishedVersion()} init -y` ); @@ -59,4 +59,38 @@ describe('nx init (Angular CLI)', () => { `Successfully ran target build for project ${project}` ); }); + + it('should successfully convert an Angular CLI workspace to an Nx integrated workspace', () => { + const output = runCommand( + `${ + pmc.runUninstalledPackage + } nx@${getPublishedVersion()} init -y --integrated` + ); + + expect(output).toContain('Nx is now enabled in your workspace!'); + // angular.json should have been deleted + checkFilesDoNotExist('angular.json'); + // check nx config files exist + checkFilesExist('nx.json', `apps/${project}/project.json`); + + // check build + const coldBuildOutput = runCLI(`build ${project} --outputHashing none`); + expect(coldBuildOutput).toContain( + `> nx run ${project}:build:production --outputHashing none` + ); + expect(coldBuildOutput).toContain( + `Successfully ran target build for project ${project}` + ); + checkFilesExist(`dist/apps/${project}/main.js`); + + // run build again to check is coming from cache + const cachedBuildOutput = runCLI(`build ${project} --outputHashing none`); + expect(cachedBuildOutput).toContain( + `> nx run ${project}:build:production --outputHashing none [local cache]` + ); + expect(cachedBuildOutput).toContain('Nx read the output from the cache'); + expect(cachedBuildOutput).toContain( + `Successfully ran target build for project ${project}` + ); + }); }); diff --git a/packages/nx/src/command-line/init.ts b/packages/nx/src/command-line/init.ts index 74d58d672497c..0c3c06527e99f 100644 --- a/packages/nx/src/command-line/init.ts +++ b/packages/nx/src/command-line/init.ts @@ -13,7 +13,11 @@ import { runNxSync } from '../utils/child-process'; import { directoryExists, readJsonFile } from '../utils/fileutils'; import { PackageJson } from '../utils/package-json'; -export async function initHandler() { +export interface InitArgs { + integrated: boolean; +} + +export async function initHandler(options: InitArgs) { const args = process.argv.slice(2).join(' '); const flags = parser(args, { boolean: ['useDotNxInstallation'], @@ -36,9 +40,9 @@ export async function initHandler() { } else if (existsSync('package.json')) { const packageJson: PackageJson = readJsonFile('package.json'); if (existsSync('angular.json')) { - await addNxToAngularCliRepo(); + await addNxToAngularCliRepo(options.integrated); } else if (isCRA(packageJson)) { - await addNxToCraRepo(); + await addNxToCraRepo(options.integrated); } else if (isNestCLI(packageJson)) { await addNxToNest(packageJson); } else if (isMonorepo(packageJson)) { diff --git a/packages/nx/src/command-line/nx-commands.ts b/packages/nx/src/command-line/nx-commands.ts index 9959f6119c7ca..c6008efc6994d 100644 --- a/packages/nx/src/command-line/nx-commands.ts +++ b/packages/nx/src/command-line/nx-commands.ts @@ -304,8 +304,9 @@ export const commandsObject = yargs .command({ command: 'init', describe: 'Adds nx.json file and installs nx if not installed already', - handler: async () => { - await (await import('./init')).initHandler(); + builder: (yargs) => withIntegratedOption(yargs), + handler: async (args: any) => { + await (await import('./init')).initHandler(args); process.exit(0); }, }) @@ -1117,6 +1118,16 @@ function withListOptions(yargs) { }); } +function withIntegratedOption(yargs) { + return yargs.option('integrated', { + type: 'boolean', + description: + 'Migrate to an Nx integrated layout workspace. Only for CRA and Angular projects.', + // TODO(leo): keep it hidden until feature is released + hidden: true, + }); +} + function runMigration() { const runLocalMigrate = () => { runNxSync(`_migrate ${process.argv.slice(3).join(' ')}`, { diff --git a/packages/nx/src/nx-init/angular/index.ts b/packages/nx/src/nx-init/angular/index.ts index 4d2ed9b1b2958..5c0173131883c 100644 --- a/packages/nx/src/nx-init/angular/index.ts +++ b/packages/nx/src/nx-init/angular/index.ts @@ -1,26 +1,19 @@ import { prompt } from 'enquirer'; -import { unlinkSync } from 'fs'; -import { dirname, join, relative, resolve } from 'path'; -import { toNewFormat } from '../../adapter/angular-json'; -import { NxJsonConfiguration } from '../../config/nx-json'; -import { - ProjectConfiguration, - TargetConfiguration, -} from '../../config/workspace-json-project-json'; -import { fileExists, readJsonFile, writeJsonFile } from '../../utils/fileutils'; +import { join } from 'path'; +import { readJsonFile, writeJsonFile } from '../../utils/fileutils'; import { sortObjectByKeys } from '../../utils/object-sort'; import { output } from '../../utils/output'; -import { PackageJson } from '../../utils/package-json'; -import { normalizePath } from '../../utils/path'; +import type { PackageJson } from '../../utils/package-json'; import { addDepsToPackageJson, - addVsCodeRecommendedExtensions, askAboutNxCloud, - createNxJsonFile, initCloud, runInstall, } from '../utils'; +import { setupIntegratedWorkspace } from './integrated-workspace'; import { getLegacyMigrationFunctionIfApplicable } from './legacy-angular-versions'; +import { setupStandaloneWorkspace } from './standalone-workspace'; +import type { AngularJsonConfig } from './types'; import yargsParser = require('yargs-parser'); const defaultCacheableOperations: string[] = [ @@ -40,12 +33,13 @@ const parsedArgs = yargsParser(process.argv, { let repoRoot: string; let workspaceTargets: string[]; -export async function addNxToAngularCliRepo() { +export async function addNxToAngularCliRepo(integrated: boolean) { repoRoot = process.cwd(); output.log({ title: '🧐 Checking versions compatibility' }); const legacyMigrationFn = await getLegacyMigrationFunctionIfApplicable( repoRoot, + integrated, parsedArgs.yes !== true ); if (legacyMigrationFn) { @@ -60,14 +54,16 @@ export async function addNxToAngularCliRepo() { }); output.log({ title: '🐳 Nx initialization' }); - const cacheableOperations = await collectCacheableOperations(); + const cacheableOperations = !integrated + ? await collectCacheableOperations() + : []; const useNxCloud = parsedArgs.yes !== true ? await askAboutNxCloud() : false; output.log({ title: '📦 Installing dependencies' }); installDependencies(useNxCloud); output.log({ title: '📝 Setting up workspace' }); - await setupWorkspace(cacheableOperations); + await setupWorkspace(cacheableOperations, integrated); if (useNxCloud) { output.log({ title: '🛠️ Setting up Nx Cloud' }); @@ -155,151 +151,19 @@ function addPluginDependencies(): void { writeJsonFile(packageJsonPath, packageJson); } -type AngularJsonConfigTargetConfiguration = Exclude< - TargetConfiguration, - 'command' | 'executor' | 'outputs' | 'dependsOn' | 'inputs' -> & { - builder: string; -}; -type AngularJsonProjectConfiguration = { - root: string; - sourceRoot: string; - architect?: Record; -}; -interface AngularJsonConfig { - projects: Record; - defaultProject?: string; -} - -async function setupWorkspace(cacheableOperations: string[]): Promise { - const angularJsonPath = join(repoRoot, 'angular.json'); - const angularJson = readJsonFile(angularJsonPath); - const workspaceCapabilities = getWorkspaceCapabilities(angularJson.projects); - createNxJson(angularJson, cacheableOperations, workspaceCapabilities); - addVsCodeRecommendedExtensions( - repoRoot, - [ - 'nrwl.angular-console', - 'angular.ng-template', - workspaceCapabilities.eslintProjectConfigFile - ? 'dbaeumer.vscode-eslint' - : undefined, - ].filter(Boolean) - ); - replaceNgWithNxInPackageJsonScripts(); - - // convert workspace config format to standalone project configs - // update its targets outputs and delete angular.json - const projects = toNewFormat(angularJson).projects; - for (const [projectName, project] of Object.entries(projects)) { - updateProjectOutputs(project); - writeJsonFile(join(project.root, 'project.json'), { - $schema: normalizePath( - relative( - join(repoRoot, project.root), - join(repoRoot, 'node_modules/nx/schemas/project-schema.json') - ) - ), - name: projectName, - ...project, - root: undefined, - }); - } - unlinkSync(angularJsonPath); -} - -type WorkspaceCapabilities = { - eslintProjectConfigFile: boolean; - test: boolean; - karmaProjectConfigFile: boolean; -}; - -function createNxJson( - angularJson: AngularJsonConfig, +async function setupWorkspace( cacheableOperations: string[], - { - eslintProjectConfigFile, - test, - karmaProjectConfigFile, - }: WorkspaceCapabilities -): void { - createNxJsonFile(repoRoot, [], cacheableOperations, {}); - - const nxJson = readJsonFile(join(repoRoot, 'nx.json')); - nxJson.namedInputs = { - sharedGlobals: [], - default: ['{projectRoot}/**/*', 'sharedGlobals'], - production: [ - 'default', - ...(test - ? [ - '!{projectRoot}/tsconfig.spec.json', - '!{projectRoot}/**/*.spec.[jt]s', - karmaProjectConfigFile ? '!{projectRoot}/karma.conf.js' : undefined, - ].filter(Boolean) - : []), - eslintProjectConfigFile ? '!{projectRoot}/.eslintrc.json' : undefined, - ].filter(Boolean), - }; - nxJson.targetDefaults = {}; - if (workspaceTargets.includes('build')) { - nxJson.targetDefaults.build = { - dependsOn: ['^build'], - inputs: ['production', '^production'], - }; - } - if (workspaceTargets.includes('server')) { - nxJson.targetDefaults.server = { inputs: ['production', '^production'] }; - } - if (workspaceTargets.includes('test')) { - const inputs = ['default', '^production']; - if (fileExists(join(repoRoot, 'karma.conf.js'))) { - inputs.push('{workspaceRoot}/karma.conf.js'); - } - nxJson.targetDefaults.test = { inputs }; - } - if (workspaceTargets.includes('lint')) { - const inputs = ['default']; - if (fileExists(join(repoRoot, '.eslintrc.json'))) { - inputs.push('{workspaceRoot}/.eslintrc.json'); - } - nxJson.targetDefaults.lint = { inputs }; - } - if (workspaceTargets.includes('e2e')) { - nxJson.targetDefaults.e2e = { inputs: ['default', '^production'] }; + isIntegratedMigration: boolean +): Promise { + if (isIntegratedMigration) { + setupIntegratedWorkspace(); + } else { + await setupStandaloneWorkspace( + repoRoot, + cacheableOperations, + workspaceTargets + ); } - // Angular 14 workspaces support defaultProject, keep it until we drop support - nxJson.defaultProject = angularJson.defaultProject; - writeJsonFile(join(repoRoot, 'nx.json'), nxJson); -} - -function updateProjectOutputs(project: ProjectConfiguration): void { - Object.values(project.targets ?? {}).forEach((target) => { - if ( - [ - '@angular-devkit/build-angular:browser', - '@angular-builders/custom-webpack:browser', - 'ngx-build-plus:browser', - '@angular-devkit/build-angular:server', - '@angular-builders/custom-webpack:server', - 'ngx-build-plus:server', - ].includes(target.executor) - ) { - target.outputs = ['{options.outputPath}']; - } else if (target.executor === '@angular-eslint/builder:lint') { - target.outputs = ['{options.outputFile}']; - } else if (target.executor === '@angular-devkit/build-angular:ng-packagr') { - try { - const ngPackageJsonPath = join(repoRoot, target.options.project); - const ngPackageJson = readJsonFile(ngPackageJsonPath); - const outputPath = relative( - repoRoot, - resolve(dirname(ngPackageJsonPath), ngPackageJson.dest) - ); - target.outputs = [`{workspaceRoot}/${normalizePath(outputPath)}`]; - } catch {} - } - }); } function getWorkspaceTargets(): string[] { @@ -315,74 +179,3 @@ function getWorkspaceTargets(): string[] { return Array.from(targets); } - -function getWorkspaceCapabilities( - projects: Record -): WorkspaceCapabilities { - const capabilities = { - eslintProjectConfigFile: false, - test: false, - karmaProjectConfigFile: false, - }; - - for (const project of Object.values(projects)) { - if ( - !capabilities.eslintProjectConfigFile && - projectHasEslintConfig(project) - ) { - capabilities.eslintProjectConfigFile = true; - } - if (!capabilities.test && projectUsesKarmaBuilder(project)) { - capabilities.test = true; - } - if ( - !capabilities.karmaProjectConfigFile && - projectHasKarmaConfig(project) - ) { - capabilities.karmaProjectConfigFile = true; - } - - if ( - capabilities.eslintProjectConfigFile && - capabilities.test && - capabilities.karmaProjectConfigFile - ) { - return capabilities; - } - } - - return capabilities; -} - -function projectUsesKarmaBuilder( - project: AngularJsonProjectConfiguration -): boolean { - return Object.values(project.architect ?? {}).some( - (target) => target.builder === '@angular-devkit/build-angular:karma' - ); -} - -function projectHasKarmaConfig( - project: AngularJsonProjectConfiguration -): boolean { - return fileExists(join(project.root, 'karma.conf.js')); -} - -function projectHasEslintConfig( - project: AngularJsonProjectConfiguration -): boolean { - return fileExists(join(project.root, '.eslintrc.json')); -} - -function replaceNgWithNxInPackageJsonScripts(): void { - const packageJsonPath = join(repoRoot, 'package.json'); - const packageJson = readJsonFile(packageJsonPath); - packageJson.scripts ??= {}; - Object.keys(packageJson.scripts).forEach((script) => { - packageJson.scripts[script] = packageJson.scripts[script] - .replace(/^nx$/, 'nx') - .replace(/^ng /, 'nx ') - .replace(/ ng /g, ' nx '); - }); - writeJsonFile(packageJsonPath, packageJson); -} diff --git a/packages/nx/src/nx-init/angular/integrated-workspace.ts b/packages/nx/src/nx-init/angular/integrated-workspace.ts new file mode 100644 index 0000000000000..71d17706a32e6 --- /dev/null +++ b/packages/nx/src/nx-init/angular/integrated-workspace.ts @@ -0,0 +1,7 @@ +import { execSync } from 'child_process'; +import { getPackageManagerCommand } from '../../utils/package-manager'; + +export function setupIntegratedWorkspace(): void { + const pmc = getPackageManagerCommand(); + execSync(`${pmc.exec} ng g @nrwl/angular:ng-add`, { stdio: [0, 1, 2] }); +} diff --git a/packages/nx/src/nx-init/angular/legacy-angular-versions.ts b/packages/nx/src/nx-init/angular/legacy-angular-versions.ts index 30b6d2ee89531..f4629f3f308cb 100644 --- a/packages/nx/src/nx-init/angular/legacy-angular-versions.ts +++ b/packages/nx/src/nx-init/angular/legacy-angular-versions.ts @@ -23,6 +23,7 @@ const versionWithConsolidatedPackages = '13.9.0'; export async function getLegacyMigrationFunctionIfApplicable( repoRoot: string, + isIntegratedMigration: boolean, interactive: boolean ): Promise<() => Promise | null> { const angularVersion = @@ -43,12 +44,18 @@ export async function getLegacyMigrationFunctionIfApplicable( pkgName, `^${majorAngularVersion}.0.0` ); - legacyMigrationCommand = `ng g ${pkgName}:ng-add --preserveAngularCLILayout`; + const preserveAngularCliLayoutFlag = !isIntegratedMigration + ? '--preserveAngularCLILayout' + : '--preserveAngularCLILayout=false'; + legacyMigrationCommand = `ng g ${pkgName}:ng-add ${preserveAngularCliLayoutFlag}`; } else if (majorAngularVersion < 14) { // for v13, the migration was in @nrwl/angular:ng-add pkgName = '@nrwl/angular'; pkgVersion = await resolvePackageVersion(pkgName, '~14.1.0'); - legacyMigrationCommand = `ng g ${pkgName}:ng-add --preserve-angular-cli-layout`; + const preserveAngularCliLayoutFlag = !isIntegratedMigration + ? '--preserve-angular-cli-layout' + : '--preserve-angular-cli-layout=false'; + legacyMigrationCommand = `ng g ${pkgName}:ng-add ${preserveAngularCliLayoutFlag}`; } else { // use the latest Nx version that supported the Angular version pkgName = '@nrwl/angular'; diff --git a/packages/nx/src/nx-init/angular/standalone-workspace.ts b/packages/nx/src/nx-init/angular/standalone-workspace.ts new file mode 100644 index 0000000000000..c15bc096ac838 --- /dev/null +++ b/packages/nx/src/nx-init/angular/standalone-workspace.ts @@ -0,0 +1,225 @@ +import { unlinkSync } from 'fs'; +import { dirname, join, relative, resolve } from 'path'; +import { toNewFormat } from '../../adapter/angular-json'; +import type { NxJsonConfiguration } from '../../config/nx-json'; +import type { ProjectConfiguration } from '../../config/workspace-json-project-json'; +import { fileExists, readJsonFile, writeJsonFile } from '../../utils/fileutils'; +import type { PackageJson } from '../../utils/package-json'; +import { normalizePath } from '../../utils/path'; +import { addVsCodeRecommendedExtensions, createNxJsonFile } from '../utils'; +import type { + AngularJsonConfig, + AngularJsonProjectConfiguration, + WorkspaceCapabilities, +} from './types'; + +export async function setupStandaloneWorkspace( + repoRoot: string, + cacheableOperations: string[], + workspaceTargets: string[] +): Promise { + const angularJsonPath = join(repoRoot, 'angular.json'); + const angularJson = readJsonFile(angularJsonPath); + const workspaceCapabilities = getWorkspaceCapabilities(angularJson.projects); + createNxJson( + repoRoot, + angularJson, + cacheableOperations, + workspaceCapabilities, + workspaceTargets + ); + addVsCodeRecommendedExtensions( + repoRoot, + [ + 'nrwl.angular-console', + 'angular.ng-template', + workspaceCapabilities.eslintProjectConfigFile + ? 'dbaeumer.vscode-eslint' + : undefined, + ].filter(Boolean) + ); + replaceNgWithNxInPackageJsonScripts(repoRoot); + + // convert workspace config format to standalone project configs + // update its targets outputs and delete angular.json + const projects = toNewFormat(angularJson).projects; + for (const [projectName, project] of Object.entries(projects)) { + updateProjectOutputs(repoRoot, project); + writeJsonFile(join(project.root, 'project.json'), { + $schema: normalizePath( + relative( + join(repoRoot, project.root), + join(repoRoot, 'node_modules/nx/schemas/project-schema.json') + ) + ), + name: projectName, + ...project, + root: undefined, + }); + } + unlinkSync(angularJsonPath); +} + +function createNxJson( + repoRoot: string, + angularJson: AngularJsonConfig, + cacheableOperations: string[], + { + eslintProjectConfigFile, + test, + karmaProjectConfigFile, + }: WorkspaceCapabilities, + workspaceTargets: string[] +): void { + createNxJsonFile(repoRoot, [], cacheableOperations, {}); + + const nxJson = readJsonFile(join(repoRoot, 'nx.json')); + nxJson.namedInputs = { + sharedGlobals: [], + default: ['{projectRoot}/**/*', 'sharedGlobals'], + production: [ + 'default', + ...(test + ? [ + '!{projectRoot}/tsconfig.spec.json', + '!{projectRoot}/**/*.spec.[jt]s', + karmaProjectConfigFile ? '!{projectRoot}/karma.conf.js' : undefined, + ].filter(Boolean) + : []), + eslintProjectConfigFile ? '!{projectRoot}/.eslintrc.json' : undefined, + ].filter(Boolean), + }; + nxJson.targetDefaults = {}; + if (workspaceTargets.includes('build')) { + nxJson.targetDefaults.build = { + dependsOn: ['^build'], + inputs: ['production', '^production'], + }; + } + if (workspaceTargets.includes('server')) { + nxJson.targetDefaults.server = { inputs: ['production', '^production'] }; + } + if (workspaceTargets.includes('test')) { + const inputs = ['default', '^production']; + if (fileExists(join(repoRoot, 'karma.conf.js'))) { + inputs.push('{workspaceRoot}/karma.conf.js'); + } + nxJson.targetDefaults.test = { inputs }; + } + if (workspaceTargets.includes('lint')) { + const inputs = ['default']; + if (fileExists(join(repoRoot, '.eslintrc.json'))) { + inputs.push('{workspaceRoot}/.eslintrc.json'); + } + nxJson.targetDefaults.lint = { inputs }; + } + if (workspaceTargets.includes('e2e')) { + nxJson.targetDefaults.e2e = { inputs: ['default', '^production'] }; + } + // Angular 14 workspaces support defaultProject, keep it until we drop support + nxJson.defaultProject = angularJson.defaultProject; + writeJsonFile(join(repoRoot, 'nx.json'), nxJson); +} + +function updateProjectOutputs( + repoRoot: string, + project: ProjectConfiguration +): void { + Object.values(project.targets ?? {}).forEach((target) => { + if ( + [ + '@angular-devkit/build-angular:browser', + '@angular-builders/custom-webpack:browser', + 'ngx-build-plus:browser', + '@angular-devkit/build-angular:server', + '@angular-builders/custom-webpack:server', + 'ngx-build-plus:server', + ].includes(target.executor) + ) { + target.outputs = ['{options.outputPath}']; + } else if (target.executor === '@angular-eslint/builder:lint') { + target.outputs = ['{options.outputFile}']; + } else if (target.executor === '@angular-devkit/build-angular:ng-packagr') { + try { + const ngPackageJsonPath = join(repoRoot, target.options.project); + const ngPackageJson = readJsonFile(ngPackageJsonPath); + const outputPath = relative( + repoRoot, + resolve(dirname(ngPackageJsonPath), ngPackageJson.dest) + ); + target.outputs = [`{workspaceRoot}/${normalizePath(outputPath)}`]; + } catch {} + } + }); +} + +function getWorkspaceCapabilities( + projects: Record +): WorkspaceCapabilities { + const capabilities = { + eslintProjectConfigFile: false, + test: false, + karmaProjectConfigFile: false, + }; + + for (const project of Object.values(projects)) { + if ( + !capabilities.eslintProjectConfigFile && + projectHasEslintConfig(project) + ) { + capabilities.eslintProjectConfigFile = true; + } + if (!capabilities.test && projectUsesKarmaBuilder(project)) { + capabilities.test = true; + } + if ( + !capabilities.karmaProjectConfigFile && + projectHasKarmaConfig(project) + ) { + capabilities.karmaProjectConfigFile = true; + } + + if ( + capabilities.eslintProjectConfigFile && + capabilities.test && + capabilities.karmaProjectConfigFile + ) { + return capabilities; + } + } + + return capabilities; +} + +function projectUsesKarmaBuilder( + project: AngularJsonProjectConfiguration +): boolean { + return Object.values(project.architect ?? {}).some( + (target) => target.builder === '@angular-devkit/build-angular:karma' + ); +} + +function projectHasKarmaConfig( + project: AngularJsonProjectConfiguration +): boolean { + return fileExists(join(project.root, 'karma.conf.js')); +} + +function projectHasEslintConfig( + project: AngularJsonProjectConfiguration +): boolean { + return fileExists(join(project.root, '.eslintrc.json')); +} + +function replaceNgWithNxInPackageJsonScripts(repoRoot: string): void { + const packageJsonPath = join(repoRoot, 'package.json'); + const packageJson = readJsonFile(packageJsonPath); + packageJson.scripts ??= {}; + Object.keys(packageJson.scripts).forEach((script) => { + packageJson.scripts[script] = packageJson.scripts[script] + .replace(/^nx$/, 'nx') + .replace(/^ng /, 'nx ') + .replace(/ ng /g, ' nx '); + }); + writeJsonFile(packageJsonPath, packageJson); +} diff --git a/packages/nx/src/nx-init/angular/types.ts b/packages/nx/src/nx-init/angular/types.ts new file mode 100644 index 0000000000000..6ef86db7852c9 --- /dev/null +++ b/packages/nx/src/nx-init/angular/types.ts @@ -0,0 +1,25 @@ +import type { TargetConfiguration } from '../../config/workspace-json-project-json'; + +export type AngularJsonConfigTargetConfiguration = Exclude< + TargetConfiguration, + 'command' | 'executor' | 'outputs' | 'dependsOn' | 'inputs' +> & { + builder: string; +}; + +export type AngularJsonProjectConfiguration = { + root: string; + sourceRoot: string; + architect?: Record; +}; + +export interface AngularJsonConfig { + projects: Record; + defaultProject?: string; +} + +export type WorkspaceCapabilities = { + eslintProjectConfigFile: boolean; + test: boolean; + karmaProjectConfigFile: boolean; +}; diff --git a/packages/nx/src/nx-init/react/index.ts b/packages/nx/src/nx-init/react/index.ts index cc880a95a264c..e219dc3728272 100644 --- a/packages/nx/src/nx-init/react/index.ts +++ b/packages/nx/src/nx-init/react/index.ts @@ -40,7 +40,7 @@ interface NormalizedOptions extends Options { } const parsedArgs = yargsParser(process.argv, { - boolean: ['force', 'e2e', 'nxCloud', 'vite', 'integrated'], + boolean: ['force', 'e2e', 'nxCloud', 'vite'], default: { nxCloud: true, vite: true, @@ -50,7 +50,7 @@ const parsedArgs = yargsParser(process.argv, { }, }); -export async function addNxToCraRepo() { +export async function addNxToCraRepo(integrated: boolean) { if (!parsedArgs.force) { checkForUncommittedChanges(); checkForCustomWebpackSetup(); @@ -58,7 +58,10 @@ export async function addNxToCraRepo() { output.log({ title: '✨ Nx initialization' }); - const normalizedOptions = normalizeOptions(parsedArgs as unknown as Options); + const normalizedOptions = normalizeOptions( + parsedArgs as unknown as Options, + integrated + ); await reorgnizeWorkspaceStructure(normalizedOptions); } @@ -68,7 +71,10 @@ function addDependencies(pmc: PackageManagerCommands, ...deps: string[]) { execSync(`${pmc.addDev} ${depsArg}`, { stdio: [0, 1, 2] }); } -function normalizeOptions(options: Options): NormalizedOptions { +function normalizeOptions( + options: Options, + integrated: boolean +): NormalizedOptions { const packageManager = detectPackageManager(); const pmc = getPackageManagerCommand(packageManager); @@ -85,7 +91,7 @@ function normalizeOptions(options: Options): NormalizedOptions { // Should remove this check 04/2023 once Node 14 & npm 6 reach EOL const npxYesFlagNeeded = !npmVersion.startsWith('6'); // npm 7 added -y flag to npx const isVite = options.vite; - const isStandalone = !options.integrated; + const isStandalone = !integrated; return { ...options, @@ -97,6 +103,7 @@ function normalizeOptions(options: Options): NormalizedOptions { npxYesFlagNeeded, isVite, isStandalone, + integrated, }; }