From 6fd181f348e94a3bb126d0d422bdad048f8a5feb Mon Sep 17 00:00:00 2001 From: Victor Savkin Date: Fri, 26 Jul 2019 19:09:45 -0400 Subject: [PATCH] feat(nx): improve the dev ergonomics of create-nx-workspace --- docs/api-workspace/schematics/ng-new.md | 6 + docs/api-workspace/schematics/tao-new.md | 6 + .../bin/create-nx-workspace.ts | 130 +++++++++++++----- .../src/schematics/ng-new/schema.json | 4 + .../workspace/src/schematics/preset/preset.ts | 2 +- .../src/schematics/shared-new/shared-new.ts | 9 +- .../src/schematics/tao-new/schema.json | 4 + 7 files changed, 122 insertions(+), 39 deletions(-) diff --git a/docs/api-workspace/schematics/ng-new.md b/docs/api-workspace/schematics/ng-new.md index d3dca0663b..f47ebd97a8 100644 --- a/docs/api-workspace/schematics/ng-new.md +++ b/docs/api-workspace/schematics/ng-new.md @@ -11,6 +11,12 @@ ng generate ng-new ... ## Options +### appName + +Type: `string` + +Application name. + ### commit Default: `true` diff --git a/docs/api-workspace/schematics/tao-new.md b/docs/api-workspace/schematics/tao-new.md index 1375e6308e..9e10dd7497 100644 --- a/docs/api-workspace/schematics/tao-new.md +++ b/docs/api-workspace/schematics/tao-new.md @@ -11,6 +11,12 @@ ng generate tao-new ... ## Options +### appName + +Type: `string` + +Application name. + ### commit Default: `true` diff --git a/packages/create-nx-workspace/bin/create-nx-workspace.ts b/packages/create-nx-workspace/bin/create-nx-workspace.ts index a98e634544..536b02119c 100644 --- a/packages/create-nx-workspace/bin/create-nx-workspace.ts +++ b/packages/create-nx-workspace/bin/create-nx-workspace.ts @@ -40,7 +40,10 @@ const nxVersion = 'NX_VERSION'; const angularCliVersion = 'ANGULAR_CLI_VERSION'; const parsedArgs = yargsParser(process.argv, { - string: ['cli', 'preset'], + string: ['cli', 'preset', 'appName'], + alias: { + appName: 'app-name' + }, boolean: ['help'] }); @@ -48,14 +51,17 @@ if (parsedArgs.help) { showHelp(); process.exit(0); } -validateInput(parsedArgs); const packageManager = determinePackageManager(); -determinePreset(parsedArgs).then(preset => { - return determineCli(preset, parsedArgs).then(cli => { - const tmpDir = createSandbox(packageManager, cli); - createApp(tmpDir, cli, parsedArgs, preset); - showNxWarning(); - showCliWarning(preset, parsedArgs); +determineWorkspaceName(parsedArgs).then(name => { + determinePreset(parsedArgs).then(preset => { + return determineAppName(preset, parsedArgs).then(appName => { + return determineCli(preset, parsedArgs).then(cli => { + const tmpDir = createSandbox(packageManager, cli); + createApp(tmpDir, cli, parsedArgs, name, preset, appName); + showNxWarning(); + showCliWarning(preset, parsedArgs); + }); + }); }); }); @@ -73,6 +79,8 @@ function showHelp() { .map(o => '"' + o.value + '"') .join(', ')}) + appName the name of the application created by some presets + cli CLI to power the Nx workspace (options: "nx", "angular") [new workspace options] any 'new workspace' options @@ -103,32 +111,46 @@ function determinePackageManager() { return packageManager; } -function validateInput(parsedArgs: any) { - const projectName = parsedArgs._[2]; +function determineWorkspaceName(parsedArgs: any) { + const workspaceName = parsedArgs._[2]; - if (!projectName) { - output.error({ - title: 'A project name is required when creating a new workspace', - bodyLines: [ - output.colors.gray('For example:'), - '', - `${output.colors.gray('>')} create-nx-workspace my-new-workspace` - ] - }); - process.exit(1); + if (workspaceName) { + return Promise.resolve(workspaceName); + } else { + return inquirer + .prompt([ + { + name: 'WorkspaceName', + message: `Workspace name (e.g., org name) `, + type: 'string' + } + ]) + .then(a => { + if (!a.WorkspaceName) { + output.error({ + title: 'Invalid workspace name', + bodyLines: [`Workspace name cannot be empty`] + }); + process.exit(1); + } + return a.WorkspaceName; + }); } - return projectName; + return workspaceName; } function determinePreset(parsedArgs: any): Promise { if (parsedArgs.preset) { if (presetOptions.map(o => o.value).indexOf(parsedArgs.preset) === -1) { - console.error( - `Invalid preset. It must be one of the following: ${presetOptions - .map(o => '"' + o.value + '"') - .join(', ')}.` - ); + output.error({ + title: 'Invalid preset', + bodyLines: [ + `It must be one of the following:`, + '', + ...presetOptions.map(o => o.value) + ] + }); process.exit(1); } else { return Promise.resolve(parsedArgs.preset); @@ -148,6 +170,35 @@ function determinePreset(parsedArgs: any): Promise { } } +function determineAppName(preset: string, parsedArgs: any): Promise { + if (preset === 'empty') { + return Promise.resolve(''); + } + + if (parsedArgs.appName) { + return Promise.resolve(parsedArgs.appName); + } else { + return inquirer + .prompt([ + { + name: 'AppName', + message: `Application name `, + type: 'string' + } + ]) + .then(a => { + if (!a.AppName) { + output.error({ + title: 'Invalid name', + bodyLines: [`Name cannot be empty`] + }); + process.exit(1); + } + return a.AppName; + }); + } +} + function determineCli(preset: string, parsedArgs: any) { const angular = { package: '@angular/cli', @@ -163,9 +214,10 @@ function determineCli(preset: string, parsedArgs: any) { if (parsedArgs.cli) { if (['nx', 'angular'].indexOf(parsedArgs.cli) === -1) { - console.error( - `Invalid cli. It must be one of the following: "nx", "angular".` - ); + output.error({ + title: 'Invalid cli', + bodyLines: [`It must be one of the following:`, '', 'nx', 'angular'] + }); process.exit(1); } return Promise.resolve(parsedArgs.cli === 'angular' ? angular : nx); @@ -231,16 +283,22 @@ function createApp( tmpDir: string, cli: { command: string }, parsedArgs: any, - preset: string + name: string, + preset: string, + appName: string ) { // creating the app itself - const args = process.argv - .slice(2) - .filter(a => !a.startsWith('--cli')) // not used by the new command - .map(a => `"${a}"`) - .join(' '); + const args = [ + name, + ...process.argv + .slice(parsedArgs._[2] ? 3 : 2) + .filter(a => !a.startsWith('--cli')) // not used by the new command + .map(a => `"${a}"`) + ].join(' '); - const presetArg = parsedArgs.preset ? '' : ` --preset=${preset}`; + const presetArg = parsedArgs.preset + ? '' + : ` --preset=${preset} --appName=${appName}`; console.log(`new ${args}${presetArg} --collection=@nrwl/workspace`); execSync( diff --git a/packages/workspace/src/schematics/ng-new/schema.json b/packages/workspace/src/schematics/ng-new/schema.json index c632e655ea..5bc218d71a 100644 --- a/packages/workspace/src/schematics/ng-new/schema.json +++ b/packages/workspace/src/schematics/ng-new/schema.json @@ -117,6 +117,10 @@ } ] } + }, + "appName": { + "type": "string", + "description": "Application name." } } } diff --git a/packages/workspace/src/schematics/preset/preset.ts b/packages/workspace/src/schematics/preset/preset.ts index 28437fdd78..3849740dc4 100644 --- a/packages/workspace/src/schematics/preset/preset.ts +++ b/packages/workspace/src/schematics/preset/preset.ts @@ -132,7 +132,7 @@ function connectFrontendAndApi(options: Schema) { ) ]); - const scope = options.npmScope ? options.npmScope : options.name; + const scope = options.npmScope; const style = options.style ? options.style : 'css'; host.overwrite( `apps/${options.name}/src/app/app.component.ts`, diff --git a/packages/workspace/src/schematics/shared-new/shared-new.ts b/packages/workspace/src/schematics/shared-new/shared-new.ts index 42315ef54b..e22f72775e 100644 --- a/packages/workspace/src/schematics/shared-new/shared-new.ts +++ b/packages/workspace/src/schematics/shared-new/shared-new.ts @@ -27,6 +27,7 @@ import { platform } from 'os'; export interface Schema { directory: string; name: string; + appName: string; npmScope?: string; skipInstall?: boolean; skipGit?: boolean; @@ -62,11 +63,15 @@ function createPresetTaskExecutor(cli: string, opts: Schema) { const args = [ `g`, `@nrwl/workspace:preset`, - `--name=${opts.name}`, + `--name=${opts.appName}`, opts.style ? `--style=${opts.style}` : null, - opts.npmScope ? `--npmScope=${opts.npmScope}` : null, + opts.npmScope + ? `--npmScope=${opts.npmScope}` + : `--npmScope=${opts.name}`, opts.preset ? `--preset=${opts.preset}` : null ].filter(e => !!e); + + console.log('here', path.join(process.cwd(), opts.directory)); return new Observable(obs => { spawn(executable, args, spawnOptions).on('close', (code: number) => { if (code === 0) { diff --git a/packages/workspace/src/schematics/tao-new/schema.json b/packages/workspace/src/schematics/tao-new/schema.json index c632e655ea..5bc218d71a 100644 --- a/packages/workspace/src/schematics/tao-new/schema.json +++ b/packages/workspace/src/schematics/tao-new/schema.json @@ -117,6 +117,10 @@ } ] } + }, + "appName": { + "type": "string", + "description": "Application name." } } }