feat(workspace-schematic): support list-schematics and interactive prompts
This commit is contained in:
parent
cc553ae687
commit
d7a617e43c
@ -258,7 +258,8 @@ CommentsLoaded,
|
|||||||
CommentsLoadError
|
CommentsLoadError
|
||||||
}
|
}
|
||||||
|
|
||||||
````
|
```
|
||||||
|
|
||||||
###### comments.selectors.ts
|
###### comments.selectors.ts
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
@ -282,7 +283,7 @@ export const commentsQuery = {
|
|||||||
getAllComments,
|
getAllComments,
|
||||||
getSelectedComments
|
getSelectedComments
|
||||||
}
|
}
|
||||||
````
|
```
|
||||||
|
|
||||||
###### comments.reducer.ts
|
###### comments.reducer.ts
|
||||||
|
|
||||||
|
|||||||
@ -32,7 +32,6 @@ yarn global add @nrwl/schematics
|
|||||||
|
|
||||||
> If you want to work with the version still in development you can use `@nrwl/schematics@next` as the package to install.
|
> If you want to work with the version still in development you can use `@nrwl/schematics@next` as the package to install.
|
||||||
|
|
||||||
|
|
||||||
## Nx Workspace
|
## Nx Workspace
|
||||||
|
|
||||||
### Creating an Nx Workspace
|
### Creating an Nx Workspace
|
||||||
@ -51,7 +50,6 @@ create-nx-workspace myworkspacename
|
|||||||
|
|
||||||
This command still runs `ng new` under the hood, but it does it in a sandboxed environment, and, as a result, never fails.
|
This command still runs `ng new` under the hood, but it does it in a sandboxed environment, and, as a result, never fails.
|
||||||
|
|
||||||
|
|
||||||
### Adding to an Existing Angular CLI workspace
|
### Adding to an Existing Angular CLI workspace
|
||||||
|
|
||||||
If you already have a regular Angular CLI project, you can add Nx power-ups by running:
|
If you already have a regular Angular CLI project, you can add Nx power-ups by running:
|
||||||
@ -60,8 +58,6 @@ If you already have a regular Angular CLI project, you can add Nx power-ups by r
|
|||||||
ng add @nrwl/schematics
|
ng add @nrwl/schematics
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Creating First Application
|
## Creating First Application
|
||||||
|
|
||||||
Unlike the CLI, an Nx workspace starts blank. There are no applications to build, serve, and test. To create one run:
|
Unlike the CLI, an Nx workspace starts blank. There are no applications to build, serve, and test. To create one run:
|
||||||
@ -104,12 +100,10 @@ nx.json
|
|||||||
|
|
||||||
All the files that the CLI would have in a new project are still here, just in a different folder structure which makes it easier to create more apps and libs in the future.
|
All the files that the CLI would have in a new project are still here, just in a different folder structure which makes it easier to create more apps and libs in the future.
|
||||||
|
|
||||||
|
|
||||||
## Serving Application
|
## Serving Application
|
||||||
|
|
||||||
Run `ng serve myapp` to serve the newly generated application!
|
Run `ng serve myapp` to serve the newly generated application!
|
||||||
|
|
||||||
|
|
||||||
## Use Angular Console
|
## Use Angular Console
|
||||||
|
|
||||||
You can also create a new Nx project using Angular Console--UI for the CLI:
|
You can also create a new Nx project using Angular Console--UI for the CLI:
|
||||||
|
|||||||
@ -2,11 +2,10 @@
|
|||||||
|
|
||||||
Nx **is not** a replacement for Angular CLI. It's a collection of Angular CLI power-ups (schematics and builders) that transform the CLI into a powerful tool for full-stack development.
|
Nx **is not** a replacement for Angular CLI. It's a collection of Angular CLI power-ups (schematics and builders) that transform the CLI into a powerful tool for full-stack development.
|
||||||
|
|
||||||
* **An Nx workspace is an Angular CLI workspace.**
|
- **An Nx workspace is an Angular CLI workspace.**
|
||||||
* You run same `ng build`, `ng serve` commands.
|
- You run same `ng build`, `ng serve` commands.
|
||||||
* You configure your projects in `angular.json`.
|
- You configure your projects in `angular.json`.
|
||||||
* Anything you can do in a standard Angular CLI project, you can also do in an Nx workspace.
|
- Anything you can do in a standard Angular CLI project, you can also do in an Nx workspace.
|
||||||
|
|
||||||
|
|
||||||
## How?
|
## How?
|
||||||
|
|
||||||
@ -14,13 +13,11 @@ Angular CLI is extensible. Nx extends what the CLI generates (schematics) and ho
|
|||||||
|
|
||||||
What does Nx add?
|
What does Nx add?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Full-Stack Development
|
## Full-Stack Development
|
||||||
|
|
||||||
With Nx, you can build a backend application next to your Angular application in the same repository. The backend and the frontend can share code. You can connect them to enable a fantastic development experience.
|
With Nx, you can build a backend application next to your Angular application in the same repository. The backend and the frontend can share code. You can connect them to enable a fantastic development experience.
|
||||||
|
|
||||||
*How do you do it?*
|
_How do you do it?_
|
||||||
|
|
||||||
First, generate a node application.
|
First, generate a node application.
|
||||||
|
|
||||||
@ -49,15 +46,11 @@ Now, add the right proxy configuration:
|
|||||||
|
|
||||||
Finally, you can run `ng serve backend` and `ng serve frontend`. There is a lot more to full-stack development in Nx, which we will cover the the guides.
|
Finally, you can run `ng serve backend` and `ng serve frontend`. There is a lot more to full-stack development in Nx, which we will cover the the guides.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Use effective development practices pioneered at Google
|
## Use effective development practices pioneered at Google
|
||||||
|
|
||||||
Using Nx, you can implement monorepo-style development--an approach popularized by Google and used by many tech companies today (Facebook, Uber, Twitter, etc..).
|
Using Nx, you can implement monorepo-style development--an approach popularized by Google and used by many tech companies today (Facebook, Uber, Twitter, etc..).
|
||||||
|
|
||||||
*Doesn't Angular CLI support having multiple projects in the same workspace?*
|
_Doesn't Angular CLI support having multiple projects in the same workspace?_
|
||||||
|
|
||||||
Yes, starting with Angular CLI 6 you can add different types of projects to a single workspace (by default you can add applications and libraries). This is great, but is not sufficient to enable the monorepo-style development. Nx adds an extra layer of tooling to make this possible.
|
Yes, starting with Angular CLI 6 you can add different types of projects to a single workspace (by default you can add applications and libraries). This is great, but is not sufficient to enable the monorepo-style development. Nx adds an extra layer of tooling to make this possible.
|
||||||
|
|
||||||
@ -67,7 +60,6 @@ To be able to support the monorepo-style development, the tools must know how di
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
### Imposing Constraints on the Dependency Graph
|
### Imposing Constraints on the Dependency Graph
|
||||||
|
|
||||||
If you partition your code into well-defined cohesive units, even a small organization will end up with a dozen apps and dozens or hundreds of libs. If all of them can depend on each other freely, chaos will ensue and the workspace will become unmanageable.
|
If you partition your code into well-defined cohesive units, even a small organization will end up with a dozen apps and dozens or hundreds of libs. If all of them can depend on each other freely, chaos will ensue and the workspace will become unmanageable.
|
||||||
@ -105,7 +97,6 @@ For instance, with this configuration, when we import private client code from t
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
### Rebuilding and Retesting What is Affected
|
### Rebuilding and Retesting What is Affected
|
||||||
|
|
||||||
To be productive in a monorepo, you need to be able to check that your change is safe, and rebuilding and retesting everything on every change won’t scale. Nx uses code analysis to determine what needs to be rebuilt and retested.
|
To be productive in a monorepo, you need to be able to check that your change is safe, and rebuilding and retesting everything on every change won’t scale. Nx uses code analysis to determine what needs to be rebuilt and retested.
|
||||||
@ -120,7 +111,6 @@ yarn affected:e2e --base=master # reruns e2e tests for all the projects affected
|
|||||||
|
|
||||||
Nx will topologically sort the projects, and will run what it can in parallel.
|
Nx will topologically sort the projects, and will run what it can in parallel.
|
||||||
|
|
||||||
|
|
||||||
### Angular CLI = Code Collocation, Nx = Monorepo
|
### Angular CLI = Code Collocation, Nx = Monorepo
|
||||||
|
|
||||||
Imagine you have a regular Angular CLI workspace containing tens projects, where each project has its own suite of e2e tests. The CLI doesnt't know how the projects depend on each other, so the only way for you to make sure your PR works is to rebuild and retest all ten projects. This isn't great.
|
Imagine you have a regular Angular CLI workspace containing tens projects, where each project has its own suite of e2e tests. The CLI doesnt't know how the projects depend on each other, so the only way for you to make sure your PR works is to rebuild and retest all ten projects. This isn't great.
|
||||||
@ -131,12 +121,10 @@ First, this makes the CI expensive--10 times more expensive in the worse case sc
|
|||||||
|
|
||||||
This is a hard requirement for monorepo-style development. Nx implements it.
|
This is a hard requirement for monorepo-style development. Nx implements it.
|
||||||
|
|
||||||
|
|
||||||
### Automation
|
### Automation
|
||||||
|
|
||||||
In addition to using the monorepo, Google is also know for its use of automation. Nx adds powerful capabilities helping your team promote best practices and ensure consistency.
|
In addition to using the monorepo, Google is also know for its use of automation. Nx adds powerful capabilities helping your team promote best practices and ensure consistency.
|
||||||
|
|
||||||
|
|
||||||
## Use Innovative Tools
|
## Use Innovative Tools
|
||||||
|
|
||||||
Tools like Apollo, Cypress, Jest, Prettier, and NestJS have gained a lot of popularity.
|
Tools like Apollo, Cypress, Jest, Prettier, and NestJS have gained a lot of popularity.
|
||||||
@ -164,13 +152,11 @@ Nx is not a replacement for the CLI. It's a set of Angular CLI power-ups.
|
|||||||
|
|
||||||
With Nx, you can:
|
With Nx, you can:
|
||||||
|
|
||||||
* Do everything you can do using the CLI
|
- Do everything you can do using the CLI
|
||||||
* Build full-stack applications using Angular and NestJS
|
- Build full-stack applications using Angular and NestJS
|
||||||
* Use scalable development practices such as monorepos
|
- Use scalable development practices such as monorepos
|
||||||
* Use innovative tools like Cypress and Jest
|
- Use innovative tools like Cypress and Jest
|
||||||
|
|
||||||
|
|
||||||
### A la carte
|
### A la carte
|
||||||
|
|
||||||
Most importantly, you can use these power-ups a la carte. Just want to build a single Angular application using Cypress? Nx is still an excellent choice for that.
|
Most importantly, you can use these power-ups a la carte. Just want to build a single Angular application using Cypress? Nx is still an excellent choice for that.
|
||||||
|
|
||||||
|
|||||||
@ -4,9 +4,9 @@ Nx is a set of Angular CLI power-ups that transform the CLI into a powerful tool
|
|||||||
|
|
||||||
With Nx, you can:
|
With Nx, you can:
|
||||||
|
|
||||||
* Build full-stack applications using Angular and NestJS
|
- Build full-stack applications using Angular and NestJS
|
||||||
* Use effective development practices pioneered at Google
|
- Use effective development practices pioneered at Google
|
||||||
* Use innovative tools like Cypress and Jest
|
- Use innovative tools like Cypress and Jest
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
@ -20,8 +20,8 @@ With Nx, you can:
|
|||||||
- [API docs](apidocs.md)
|
- [API docs](apidocs.md)
|
||||||
|
|
||||||
## Community
|
## Community
|
||||||
- [Books, talks, and blog posts about Nx](resources.md)
|
|
||||||
|
|
||||||
|
- [Books, talks, and blog posts about Nx](resources.md)
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
|||||||
@ -142,7 +142,7 @@ describe('Command line', () => {
|
|||||||
|
|
||||||
it('should support workspace-specific schematics', () => {
|
it('should support workspace-specific schematics', () => {
|
||||||
newProject();
|
newProject();
|
||||||
runCLI('g workspace-schematic custom');
|
runCLI('g workspace-schematic custom -- --noInteractive');
|
||||||
checkFilesExist(
|
checkFilesExist(
|
||||||
'tools/schematics/custom/index.ts',
|
'tools/schematics/custom/index.ts',
|
||||||
'tools/schematics/custom/schema.json'
|
'tools/schematics/custom/schema.json'
|
||||||
@ -165,7 +165,7 @@ describe('Command line', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const dryRunOutput = runCommand(
|
const dryRunOutput = runCommand(
|
||||||
'npm run workspace-schematic custom mylib -- --directory=dir -d'
|
'npm run workspace-schematic custom mylib -- --noInteractive --directory=dir -d'
|
||||||
);
|
);
|
||||||
expect(exists('libs/dir/mylib/src/index.ts')).toEqual(false);
|
expect(exists('libs/dir/mylib/src/index.ts')).toEqual(false);
|
||||||
expect(dryRunOutput).toContain(
|
expect(dryRunOutput).toContain(
|
||||||
@ -175,7 +175,7 @@ describe('Command line', () => {
|
|||||||
expect(dryRunOutput).toContain('update nx.json');
|
expect(dryRunOutput).toContain('update nx.json');
|
||||||
|
|
||||||
const output = runCommand(
|
const output = runCommand(
|
||||||
'npm run workspace-schematic custom mylib -- --directory=dir'
|
'npm run workspace-schematic custom mylib -- --no-interactive --directory=dir'
|
||||||
);
|
);
|
||||||
checkFilesExist('libs/dir/mylib/src/index.ts');
|
checkFilesExist('libs/dir/mylib/src/index.ts');
|
||||||
expect(output).toContain(
|
expect(output).toContain(
|
||||||
@ -183,7 +183,26 @@ describe('Command line', () => {
|
|||||||
);
|
);
|
||||||
expect(output).toContain('update angular.json');
|
expect(output).toContain('update angular.json');
|
||||||
expect(output).toContain('update nx.json');
|
expect(output).toContain('update nx.json');
|
||||||
|
|
||||||
|
runCLI('g workspace-schematic another -- --noInteractive');
|
||||||
|
|
||||||
|
const listSchematicsOutput = runCommand(
|
||||||
|
'npm run workspace-schematic -- --list-schematics'
|
||||||
|
);
|
||||||
|
expect(listSchematicsOutput).toContain(
|
||||||
|
'nx workspace-schematic "--list-schematics"'
|
||||||
|
);
|
||||||
|
expect(listSchematicsOutput).toContain('custom');
|
||||||
|
expect(listSchematicsOutput).toContain('another');
|
||||||
|
|
||||||
|
const promptOutput = runCommand(
|
||||||
|
'npm run workspace-schematic custom mylib2 --'
|
||||||
|
);
|
||||||
|
expect(promptOutput).toContain(
|
||||||
|
'In which directory should the library be generated?'
|
||||||
|
);
|
||||||
}, 1000000);
|
}, 1000000);
|
||||||
|
|
||||||
describe('dep-graph', () => {
|
describe('dep-graph', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
newProject();
|
newProject();
|
||||||
|
|||||||
@ -123,13 +123,25 @@ yargs
|
|||||||
.command('update', 'Update workspace', noop, _ => update([]))
|
.command('update', 'Update workspace', noop, _ => update([]))
|
||||||
.alias('update', 'migrates') // TODO: Remove after 1.0
|
.alias('update', 'migrates') // TODO: Remove after 1.0
|
||||||
.command(
|
.command(
|
||||||
'workspace-schematic <name>',
|
'workspace-schematic [name]',
|
||||||
'Runs a workspace schematic from the tools/schematics directory',
|
'Runs a workspace schematic from the tools/schematics directory',
|
||||||
yargs =>
|
yargs => {
|
||||||
yargs.positional('name', {
|
yargs.option('list-schematics', {
|
||||||
|
describe: 'List the available workspace-schematics',
|
||||||
|
type: 'boolean'
|
||||||
|
});
|
||||||
|
/**
|
||||||
|
* Don't require `name` if only listing available
|
||||||
|
* schematics
|
||||||
|
*/
|
||||||
|
if (yargs.argv.listSchematics !== true) {
|
||||||
|
yargs.demandOption(['name']).positional('name', {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
describe: 'The name of your schematic`'
|
describe: 'The name of your schematic`'
|
||||||
}),
|
});
|
||||||
|
}
|
||||||
|
return yargs;
|
||||||
|
},
|
||||||
() => workspaceSchematic(process.argv.slice(3))
|
() => workspaceSchematic(process.argv.slice(3))
|
||||||
)
|
)
|
||||||
.help('help')
|
.help('help')
|
||||||
|
|||||||
@ -1,24 +1,47 @@
|
|||||||
|
import {
|
||||||
|
JsonObject,
|
||||||
|
logging,
|
||||||
|
normalize,
|
||||||
|
schema,
|
||||||
|
virtualFs
|
||||||
|
} from '@angular-devkit/core';
|
||||||
|
import { createConsoleLogger, NodeJsSyncHost } from '@angular-devkit/core/node';
|
||||||
|
import {
|
||||||
|
SchematicEngine,
|
||||||
|
UnsuccessfulWorkflowExecution
|
||||||
|
} from '@angular-devkit/schematics';
|
||||||
|
import {
|
||||||
|
NodeModulesEngineHost,
|
||||||
|
NodeWorkflow
|
||||||
|
} from '@angular-devkit/schematics/tools';
|
||||||
|
import * as appRoot from 'app-root-path';
|
||||||
import { execSync } from 'child_process';
|
import { execSync } from 'child_process';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import { readFileSync, writeFileSync, statSync } from 'fs';
|
import { readFileSync, statSync, writeFileSync } from 'fs';
|
||||||
import * as path from 'path';
|
|
||||||
import { copySync, removeSync } from 'fs-extra';
|
import { copySync, removeSync } from 'fs-extra';
|
||||||
import { NodeWorkflow } from '@angular-devkit/schematics/tools';
|
import * as inquirer from 'inquirer';
|
||||||
import { UnsuccessfulWorkflowExecution } from '@angular-devkit/schematics';
|
import * as path from 'path';
|
||||||
|
|
||||||
import * as yargsParser from 'yargs-parser';
|
import * as yargsParser from 'yargs-parser';
|
||||||
import * as appRoot from 'app-root-path';
|
|
||||||
import { virtualFs, normalize, JsonObject } from '@angular-devkit/core';
|
|
||||||
import { NodeJsSyncHost, createConsoleLogger } from '@angular-devkit/core/node';
|
|
||||||
|
|
||||||
const rootDirectory = appRoot.path;
|
const rootDirectory = appRoot.path;
|
||||||
|
|
||||||
export function workspaceSchematic(args: string[]) {
|
export function workspaceSchematic(args: string[]) {
|
||||||
const parsedArgs = parseOptions(args);
|
const parsedArgs = parseOptions(args);
|
||||||
|
const logger = createConsoleLogger(
|
||||||
|
parsedArgs['verbose'],
|
||||||
|
process.stdout,
|
||||||
|
process.stderr
|
||||||
|
);
|
||||||
const outDir = compileTools();
|
const outDir = compileTools();
|
||||||
|
if (parsedArgs['list-schematics']) {
|
||||||
|
return listSchematics(
|
||||||
|
path.join(outDir, 'workspace-schematics.json'),
|
||||||
|
logger
|
||||||
|
);
|
||||||
|
}
|
||||||
const schematicName = args[0];
|
const schematicName = args[0];
|
||||||
const workflow = createWorkflow(parsedArgs.dryRun);
|
const workflow = createWorkflow(parsedArgs.dryRun);
|
||||||
executeSchematic(schematicName, parsedArgs, workflow, outDir);
|
executeSchematic(schematicName, parsedArgs, workflow, outDir, logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
// compile tools
|
// compile tools
|
||||||
@ -98,12 +121,70 @@ function createWorkflow(dryRun: boolean) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function listSchematics(collectionName: string, logger: logging.Logger) {
|
||||||
|
try {
|
||||||
|
const engineHost = new NodeModulesEngineHost();
|
||||||
|
const engine = new SchematicEngine(engineHost);
|
||||||
|
const collection = engine.createCollection(collectionName);
|
||||||
|
logger.info(engine.listSchematicNames(collection).join('\n'));
|
||||||
|
} catch (error) {
|
||||||
|
logger.fatal(error.message);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createPromptProvider(): schema.PromptProvider {
|
||||||
|
return (definitions: Array<schema.PromptDefinition>) => {
|
||||||
|
const questions: inquirer.Questions = definitions.map(definition => {
|
||||||
|
const question: inquirer.Question = {
|
||||||
|
name: definition.id,
|
||||||
|
message: definition.message,
|
||||||
|
default: definition.default
|
||||||
|
};
|
||||||
|
|
||||||
|
const validator = definition.validator;
|
||||||
|
if (validator) {
|
||||||
|
question.validate = input => validator(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (definition.type) {
|
||||||
|
case 'confirmation':
|
||||||
|
return { ...question, type: 'confirm' };
|
||||||
|
case 'list':
|
||||||
|
return {
|
||||||
|
...question,
|
||||||
|
type: 'list',
|
||||||
|
choices:
|
||||||
|
definition.items &&
|
||||||
|
definition.items.map(item => {
|
||||||
|
if (typeof item == 'string') {
|
||||||
|
return item;
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
name: item.label,
|
||||||
|
value: item.value
|
||||||
|
};
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
return { ...question, type: definition.type };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return inquirer.prompt(questions);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// execute schematic
|
// execute schematic
|
||||||
async function executeSchematic(
|
async function executeSchematic(
|
||||||
schematicName: string,
|
schematicName: string,
|
||||||
options: { [p: string]: any },
|
options: { [p: string]: any },
|
||||||
workflow: NodeWorkflow,
|
workflow: NodeWorkflow,
|
||||||
outDir: string
|
outDir: string,
|
||||||
|
logger: logging.Logger
|
||||||
) {
|
) {
|
||||||
let nothingDone = true;
|
let nothingDone = true;
|
||||||
workflow.reporter.subscribe((event: any) => {
|
workflow.reporter.subscribe((event: any) => {
|
||||||
@ -146,7 +227,11 @@ async function executeSchematic(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
delete options._;
|
delete options._;
|
||||||
const logger = createConsoleLogger(true, process.stdout, process.stderr);
|
|
||||||
|
// Add support for interactive prompts
|
||||||
|
if (!options.noInteractive && options.interactive !== false) {
|
||||||
|
workflow.registry.usePromptProvider(createPromptProvider());
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await workflow
|
await workflow
|
||||||
|
|||||||
0
scripts/format.sh
Normal file → Executable file
0
scripts/format.sh
Normal file → Executable file
Loading…
x
Reference in New Issue
Block a user