diff --git a/aio/content/examples/.gitignore b/aio/content/examples/.gitignore index 6d03b437e2..905ed736fe 100644 --- a/aio/content/examples/.gitignore +++ b/aio/content/examples/.gitignore @@ -92,3 +92,6 @@ upgrade-phonecat-3-final/tsconfig-aot.json upgrade-phonecat-3-final/rollup-config.js !upgrade-phonecat-*/**/karma.conf.js !upgrade-phonecat-*/**/karma-test-shim.js + +# schematics +!schematics-for-libraries/projects/my-lib/package.json \ No newline at end of file diff --git a/aio/content/examples/schematics-for-libraries/example-config.json b/aio/content/examples/schematics-for-libraries/example-config.json new file mode 100644 index 0000000000..7f9f83ed6b --- /dev/null +++ b/aio/content/examples/schematics-for-libraries/example-config.json @@ -0,0 +1,3 @@ +{ + "projectType": "schematics" +} \ No newline at end of file diff --git a/aio/content/examples/schematics-for-libraries/projects/my-lib/ng-package.json b/aio/content/examples/schematics-for-libraries/projects/my-lib/ng-package.json new file mode 100644 index 0000000000..7ca31cd528 --- /dev/null +++ b/aio/content/examples/schematics-for-libraries/projects/my-lib/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/my-lib", + "lib": { + "entryFile": "src/public_api.ts" + } +} \ No newline at end of file diff --git a/aio/content/examples/schematics-for-libraries/projects/my-lib/package.json b/aio/content/examples/schematics-for-libraries/projects/my-lib/package.json new file mode 100644 index 0000000000..3607e2c0ce --- /dev/null +++ b/aio/content/examples/schematics-for-libraries/projects/my-lib/package.json @@ -0,0 +1,20 @@ +// #docplaster +// #docregion collection +{ + "name": "my-lib", + "version": "0.0.1", +// #enddocregion collection + "scripts": { + "build": "../../node_modules/.bin/tsc -p tsconfig.schematics.json", + "copy:schemas": "cp --parents schematics/*/schema.json ../../dist/my-lib/", + "copy:files": "cp --parents -p schematics/*/files/** ../../dist/my-lib/", + "copy:collection": "cp schematics/collection.json ../../dist/my-lib/schematics/collection.json", + "postbuild": "npm run copy:schemas && npm run copy:files && npm run copy:collection" + }, + "peerDependencies": { + "@angular/common": "^7.2.0", + "@angular/core": "^7.2.0" + }, +// #docregion collection + "schematics": "./schematics/collection.json" +} \ No newline at end of file diff --git a/aio/content/examples/schematics-for-libraries/projects/my-lib/schematics/collection.1.json b/aio/content/examples/schematics-for-libraries/projects/my-lib/schematics/collection.1.json new file mode 100644 index 0000000000..1d5afc53e2 --- /dev/null +++ b/aio/content/examples/schematics-for-libraries/projects/my-lib/schematics/collection.1.json @@ -0,0 +1,9 @@ +{ + "$schema": "../../../node_modules/@angular-devkit/schematics/collection-schema.json", + "schematics": { + "ng-add": { + "description": "Add my library to the project.", + "factory": "./ng-add/index#ngAdd" + } + } +} \ No newline at end of file diff --git a/aio/content/examples/schematics-for-libraries/projects/my-lib/schematics/collection.json b/aio/content/examples/schematics-for-libraries/projects/my-lib/schematics/collection.json new file mode 100644 index 0000000000..1853903237 --- /dev/null +++ b/aio/content/examples/schematics-for-libraries/projects/my-lib/schematics/collection.json @@ -0,0 +1,14 @@ +{ + "$schema": "../../../node_modules/@angular-devkit/schematics/collection-schema.json", + "schematics": { + "ng-add": { + "description": "Add my library to the project.", + "factory": "./ng-add/index#ngAdd" + }, + "my-service": { + "description": "Generate a service in the project.", + "factory": "./my-service/index#myService", + "schema": "./my-service/schema.json" + } + } +} \ No newline at end of file diff --git a/aio/content/examples/schematics-for-libraries/projects/my-lib/schematics/my-service/files/__name@dasherize__.service.ts.template b/aio/content/examples/schematics-for-libraries/projects/my-lib/schematics/my-service/files/__name@dasherize__.service.ts.template new file mode 100644 index 0000000000..0001ceda9a --- /dev/null +++ b/aio/content/examples/schematics-for-libraries/projects/my-lib/schematics/my-service/files/__name@dasherize__.service.ts.template @@ -0,0 +1,10 @@ +// #docregion template +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; + +@Injectable({ + providedIn: 'root' +}) +export class <%= classify(name) %>Service { + constructor(private http: HttpClient) { } +} \ No newline at end of file diff --git a/aio/content/examples/schematics-for-libraries/projects/my-lib/schematics/my-service/index.1.ts b/aio/content/examples/schematics-for-libraries/projects/my-lib/schematics/my-service/index.1.ts new file mode 100644 index 0000000000..8c82892a6a --- /dev/null +++ b/aio/content/examples/schematics-for-libraries/projects/my-lib/schematics/my-service/index.1.ts @@ -0,0 +1,11 @@ +import { Rule, Tree } from '@angular-devkit/schematics'; + +import { Schema as MyServiceSchema } from './schema'; + +// #docregion factory +export function myService(options: MyServiceSchema): Rule { + return (tree: Tree) => { + return tree; + }; +} +// #enddocregion factory diff --git a/aio/content/examples/schematics-for-libraries/projects/my-lib/schematics/my-service/index.ts b/aio/content/examples/schematics-for-libraries/projects/my-lib/schematics/my-service/index.ts new file mode 100644 index 0000000000..a36cf29acd --- /dev/null +++ b/aio/content/examples/schematics-for-libraries/projects/my-lib/schematics/my-service/index.ts @@ -0,0 +1,66 @@ +// #docplaster +// #docregion schematics-imports, schema-imports, workspace +import { + Rule, Tree, SchematicsException, + apply, url, applyTemplates, move, + chain, mergeWith +} from '@angular-devkit/schematics'; + +import { strings, normalize, experimental } from '@angular-devkit/core'; +// #enddocregion schematics-imports + +import { Schema as MyServiceSchema } from './schema'; +// #enddocregion schema-imports + +export function myService(options: MyServiceSchema): Rule { + return (tree: Tree) => { + const workspaceConfig = tree.read('/angular.json'); + if (!workspaceConfig) { + throw new SchematicsException('Could not find Angular workspace configuration'); + } + + // convert workspace to string + const workspaceContent = workspaceConfig.toString(); + + // parse workspace string into JSON object + const workspace: experimental.workspace.WorkspaceSchema = JSON.parse(workspaceContent); +// #enddocregion workspace +// #docregion project-fallback + if (!options.project) { + options.project = workspace.defaultProject; + } +// #enddocregion project-fallback + +// #docregion project-info + const projectName = options.project as string; + + const project = workspace.projects[projectName]; + + const projectType = project.projectType === 'application' ? 'app' : 'lib'; +// #enddocregion project-info + +// #docregion path + if (options.path === undefined) { + options.path = `${project.sourceRoot}/${projectType}`; + } +// #enddocregion path + +// #docregion template + const templateSource = apply(url('./files'), [ + applyTemplates({ + classify: strings.classify, + dasherize: strings.dasherize, + name: options.name + }), + move(normalize(options.path as string)) + ]); +// #enddocregion template + +// #docregion chain + return chain([ + mergeWith(templateSource) + ]); +// #enddocregion chain +// #docregion workspace + }; +} diff --git a/aio/content/examples/schematics-for-libraries/projects/my-lib/schematics/my-service/schema.json b/aio/content/examples/schematics-for-libraries/projects/my-lib/schematics/my-service/schema.json new file mode 100644 index 0000000000..7ea68d3b62 --- /dev/null +++ b/aio/content/examples/schematics-for-libraries/projects/my-lib/schematics/my-service/schema.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/schema", + "id": "SchematicsMyService", + "title": "My Service Schema", + "type": "object", + "properties": { + "name": { + "description": "The name of the service.", + "type": "string" + }, + "path": { + "type": "string", + "format": "path", + "description": "The path to create the service.", + "visible": false + }, + "project": { + "type": "string", + "description": "The name of the project.", + "$default": { + "$source": "projectName" + } + } + }, + "required": [ + "name" + ] +} \ No newline at end of file diff --git a/aio/content/examples/schematics-for-libraries/projects/my-lib/schematics/my-service/schema.ts b/aio/content/examples/schematics-for-libraries/projects/my-lib/schematics/my-service/schema.ts new file mode 100644 index 0000000000..4389b72f59 --- /dev/null +++ b/aio/content/examples/schematics-for-libraries/projects/my-lib/schematics/my-service/schema.ts @@ -0,0 +1,10 @@ +export interface Schema { + // The name of the service. + name: string; + + // The path to create the service. + path?: string; + + // The name of the project. + project?: string; +} diff --git a/aio/content/examples/schematics-for-libraries/projects/my-lib/schematics/ng-add/index.ts b/aio/content/examples/schematics-for-libraries/projects/my-lib/schematics/ng-add/index.ts new file mode 100644 index 0000000000..f749c7a61f --- /dev/null +++ b/aio/content/examples/schematics-for-libraries/projects/my-lib/schematics/ng-add/index.ts @@ -0,0 +1,10 @@ +import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics'; +import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks'; + +// Just return the tree +export function ngAdd(_options: any): Rule { + return (tree: Tree, _context: SchematicContext) => { + _context.addTask(new NodePackageInstallTask()); + return tree; + }; +} diff --git a/aio/content/examples/schematics-for-libraries/projects/my-lib/src/lib/my-lib.component.spec.ts b/aio/content/examples/schematics-for-libraries/projects/my-lib/src/lib/my-lib.component.spec.ts new file mode 100644 index 0000000000..f3c07b177c --- /dev/null +++ b/aio/content/examples/schematics-for-libraries/projects/my-lib/src/lib/my-lib.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MyLibComponent } from './my-lib.component'; + +describe('MyLibComponent', () => { + let component: MyLibComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ MyLibComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(MyLibComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/aio/content/examples/schematics-for-libraries/projects/my-lib/src/lib/my-lib.component.ts b/aio/content/examples/schematics-for-libraries/projects/my-lib/src/lib/my-lib.component.ts new file mode 100644 index 0000000000..dee805290e --- /dev/null +++ b/aio/content/examples/schematics-for-libraries/projects/my-lib/src/lib/my-lib.component.ts @@ -0,0 +1,19 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'lib-my-lib', + template: ` +

+ my-lib works! +

+ `, + styles: [] +}) +export class MyLibComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/aio/content/examples/schematics-for-libraries/projects/my-lib/src/lib/my-lib.module.ts b/aio/content/examples/schematics-for-libraries/projects/my-lib/src/lib/my-lib.module.ts new file mode 100644 index 0000000000..b48e140f60 --- /dev/null +++ b/aio/content/examples/schematics-for-libraries/projects/my-lib/src/lib/my-lib.module.ts @@ -0,0 +1,10 @@ +import { NgModule } from '@angular/core'; +import { MyLibComponent } from './my-lib.component'; + +@NgModule({ + declarations: [MyLibComponent], + imports: [ + ], + exports: [MyLibComponent] +}) +export class MyLibModule { } diff --git a/aio/content/examples/schematics-for-libraries/projects/my-lib/src/lib/my-lib.service.spec.ts b/aio/content/examples/schematics-for-libraries/projects/my-lib/src/lib/my-lib.service.spec.ts new file mode 100644 index 0000000000..d580b96d47 --- /dev/null +++ b/aio/content/examples/schematics-for-libraries/projects/my-lib/src/lib/my-lib.service.spec.ts @@ -0,0 +1,12 @@ +import { TestBed } from '@angular/core/testing'; + +import { MyLibService } from './my-lib.service'; + +describe('MyLibService', () => { + beforeEach(() => TestBed.configureTestingModule({})); + + it('should be created', () => { + const service: MyLibService = TestBed.get(MyLibService); + expect(service).toBeTruthy(); + }); +}); diff --git a/aio/content/examples/schematics-for-libraries/projects/my-lib/src/lib/my-lib.service.ts b/aio/content/examples/schematics-for-libraries/projects/my-lib/src/lib/my-lib.service.ts new file mode 100644 index 0000000000..b204cb9bdb --- /dev/null +++ b/aio/content/examples/schematics-for-libraries/projects/my-lib/src/lib/my-lib.service.ts @@ -0,0 +1,9 @@ +import { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root' +}) +export class MyLibService { + + constructor() { } +} diff --git a/aio/content/examples/schematics-for-libraries/projects/my-lib/src/public_api.ts b/aio/content/examples/schematics-for-libraries/projects/my-lib/src/public_api.ts new file mode 100644 index 0000000000..0b6a50ce9b --- /dev/null +++ b/aio/content/examples/schematics-for-libraries/projects/my-lib/src/public_api.ts @@ -0,0 +1,7 @@ +/* + * Public API Surface of my-lib + */ + +export * from './lib/my-lib.service'; +export * from './lib/my-lib.component'; +export * from './lib/my-lib.module'; diff --git a/aio/content/examples/schematics-for-libraries/projects/my-lib/tsconfig.lib.json b/aio/content/examples/schematics-for-libraries/projects/my-lib/tsconfig.lib.json new file mode 100644 index 0000000000..3fe337fcf5 --- /dev/null +++ b/aio/content/examples/schematics-for-libraries/projects/my-lib/tsconfig.lib.json @@ -0,0 +1,32 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/lib", + "target": "es2015", + "module": "es2015", + "moduleResolution": "node", + "declaration": true, + "sourceMap": true, + "inlineSources": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "importHelpers": true, + "types": [], + "lib": [ + "dom", + "es2018" + ] + }, + "angularCompilerOptions": { + "annotateForClosureCompiler": true, + "skipTemplateCodegen": true, + "strictMetadataEmit": true, + "fullTemplateTypeCheck": true, + "strictInjectionParameters": true, + "enableResourceInlining": true + }, + "exclude": [ + "src/test.ts", + "**/*.spec.ts" + ] +} diff --git a/aio/content/examples/schematics-for-libraries/projects/my-lib/tsconfig.schematics.json b/aio/content/examples/schematics-for-libraries/projects/my-lib/tsconfig.schematics.json new file mode 100644 index 0000000000..4722c6029a --- /dev/null +++ b/aio/content/examples/schematics-for-libraries/projects/my-lib/tsconfig.schematics.json @@ -0,0 +1,35 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "lib": [ + "es2018", + "dom" + ], + "declaration": true, + "module": "commonjs", + "moduleResolution": "node", + "noEmitOnError": true, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true, + "noImplicitThis": true, + "noUnusedParameters": true, + "noUnusedLocals": true, + "rootDir": "schematics", + "outDir": "../../dist/my-lib/schematics", + "skipDefaultLibCheck": true, + "skipLibCheck": true, + "sourceMap": true, + "strictNullChecks": true, + "target": "es6", + "types": [ + "jasmine", + "node" + ] + }, + "include": [ + "schematics/**/*" + ], + "exclude": [ + "schematics/*/files/**/*" + ] +} \ No newline at end of file diff --git a/aio/content/examples/schematics-for-libraries/projects/my-lib/tsconfig.spec.json b/aio/content/examples/schematics-for-libraries/projects/my-lib/tsconfig.spec.json new file mode 100644 index 0000000000..16da33db07 --- /dev/null +++ b/aio/content/examples/schematics-for-libraries/projects/my-lib/tsconfig.spec.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "src/test.ts" + ], + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/aio/content/examples/schematics-for-libraries/src/app/app.component.ts b/aio/content/examples/schematics-for-libraries/src/app/app.component.ts new file mode 100644 index 0000000000..7befb56b70 --- /dev/null +++ b/aio/content/examples/schematics-for-libraries/src/app/app.component.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-root', + template: ` +

Library Schematics

+ `, + styles: [] +}) +export class AppComponent { + title = 'schematics-for-libraries'; +} diff --git a/aio/content/examples/schematics-for-libraries/src/app/app.module.ts b/aio/content/examples/schematics-for-libraries/src/app/app.module.ts new file mode 100644 index 0000000000..f65716351a --- /dev/null +++ b/aio/content/examples/schematics-for-libraries/src/app/app.module.ts @@ -0,0 +1,16 @@ +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule } from '@angular/core'; + +import { AppComponent } from './app.component'; + +@NgModule({ + declarations: [ + AppComponent + ], + imports: [ + BrowserModule + ], + providers: [], + bootstrap: [AppComponent] +}) +export class AppModule { } diff --git a/aio/content/examples/schematics-for-libraries/src/index.html b/aio/content/examples/schematics-for-libraries/src/index.html new file mode 100644 index 0000000000..ddcdfcdbe5 --- /dev/null +++ b/aio/content/examples/schematics-for-libraries/src/index.html @@ -0,0 +1,14 @@ + + + + + SchematicsForLibraries + + + + + + + + + diff --git a/aio/content/examples/schematics-for-libraries/src/main.ts b/aio/content/examples/schematics-for-libraries/src/main.ts new file mode 100644 index 0000000000..c7b673cf44 --- /dev/null +++ b/aio/content/examples/schematics-for-libraries/src/main.ts @@ -0,0 +1,12 @@ +import { enableProdMode } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; +import { environment } from './environments/environment'; + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic().bootstrapModule(AppModule) + .catch(err => console.error(err)); diff --git a/aio/content/examples/schematics-for-libraries/zipper.json b/aio/content/examples/schematics-for-libraries/zipper.json new file mode 100644 index 0000000000..d5e148b7d9 --- /dev/null +++ b/aio/content/examples/schematics-for-libraries/zipper.json @@ -0,0 +1,10 @@ +{ + "description": "Schematics For Libraries", + "files": [ + "!**/*.d.ts", + "!**/*.js", + "!**/*.[1].*", + "**/*.template" + ], + "tags": ["Angular", "Libraries", "Schematics"] +} diff --git a/aio/content/guide/schematics-authoring.md b/aio/content/guide/schematics-authoring.md new file mode 100644 index 0000000000..b2ce1ac70e --- /dev/null +++ b/aio/content/guide/schematics-authoring.md @@ -0,0 +1,194 @@ +# Authoring Schematics + +You can create your own schematics to operate on Angular projects. +Library developers typically package schematics with their libraries in order to integrate them with the Angular CLI. +You can also create stand-alone schematics to manipulate the files and constructs in Angular applications as a way of customizing them for your development environment and making them conform to your standards and constraints. +Schematics can be chained, running other schematics to perform complex operations. + +Manipulating the code in an application has the potential to be both very powerful and correspondingly dangerous. +For example, creating a file that already exists would be an error, and if it was applied immediately, it would discard all the other changes applied so far. +The Angular Schematics tooling guards against side effects and errors by creating a virtual file system. +A schematic describes a pipeline of transformations that can be applied to the virtual file system. +When a schematic runs, the transformations are recorded in memory, and only applied in the real file system once they're confirmed to be valid. + +## Schematics concepts + +The public API for schematics defines classes that represent the basic concepts. + +* The virtual file system is represented by a `Tree`. The `Tree` data structure contains a *base* (a set of files that already exists) and a *staging area* (a list of changes to be applied to the base). +When making modifications, you don't actually change the base, but add those modifications to the staging area. + +* A `Rule` object defines a function that takes a `Tree`, applies transformations, and returns a new `Tree`. The main file for a schematic, `index.ts`, defines a set of rules that implement the schematic's logic. + +* A transformation is represented by an `Action`. There are four action types: `Create`, `Rename`, `Overwrite`, and `Delete`. + +* Each schematic runs in a context, represented by a `SchematicContext` object. + +The context object passed into a rule provides access to utility functions and metadata that the schematic may need to work with, including a logging API to help with debugging. +The context also defines a *merge strategy* that determines how changes are merged from the staged tree into the base tree. A change can be accepted or ignored, or throw an exception. + +### Defining rules and actions + +When you create a new blank schematic with the [Schematics CLI](#cli), the generated entry function is a *rule factory*. +A `RuleFactory`object defines a higher-order function that creates a `Rule`. + + +import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics'; + +// You don't have to export the function as default. +// You can also have more than one rule factory per file. +export function helloWorld(_options: any): Rule { + return (tree: Tree, _context: SchematicContext) => { + return tree; + }; +} + + +Your rules can make changes to your projects by calling external tools and implementing logic. +You need a rule, for example, to define how a template in the schematic is to be merged into the hosting project. + +Rules can make use of utilities provided with the `@schematics/angular` package. Look for helper functions for working with modules, dependencies, TypeScript, AST, JSON, Angular CLI workspaces and projects, and more. + + + +import { + JsonAstObject, + JsonObject, + JsonValue, + Path, + normalize, + parseJsonAst, + strings, +} from '@angular-devkit/core'; + + + +### Defining input options with a schema and interfaces + +Rules can collect option values from the caller and inject them into templates. +The options available to your rules, with their allowed values and defaults, are defined in the schematic's JSON schema file, `/schema.json`. +You can define variable or enumerated data types for the schema using TypeScript interfaces. + +You can see examples of schema files for the Angular CLI command schematics in [`@schematics/angular`](https://github.com/angular/angular-cli/blob/7.0.x/packages/schematics/angular/application/schema.json). + +{@a cli} + +## Schematics CLI + +Schematics come with their own command-line tool. +Using Node 6.9 or above, install the Schematics command line tool globally: + + +npm install -g @angular-devkit/schematics-cli + + +This installs the `schematics` executable, which you can use to create a new schematics collection in its own project folder, add a new schematic to an existing collection, or extend an existing schematic. + +In the following sections, we will create a new schematics collection using the CLI in order to introduce the files and file structure, and some of the basic concepts. + +The most common use of schematics, however, is to integrate an Angular library with the Angular CLI. +You can do this by creating the schematic files directly within the library project in an Angular workspace, without using the Schematics CLI. +See [Schematics for Libraries](guide/schematics-for-libraries). + +### Creating a schematics collection + +The following command creates a new schematic named `hello-world` in a new project folder of the same name. + + +schematics blank --name=hello-world + + +The `blank` schematic is provided by the Schematics CLI. The command creates a new project folder (the root folder for the collection) and an initial named schematic in the collection. + +Go to the collection folder, install your npm dependencies, and open your new collection in your favorite editor to see the generated files. For example, if you are using VSCode: + + +cd hello-world +npm install +npm run build +code . + + +The initial schematic gets the same name as the project folder, and is generated in `src/hello-world`. +You can add related schematics to this collection, and modify the generated skeleton code to define your schematic's functionality. +Each schematic name must be unique within the collection. + +### Running a schematic + +Use the `schematics` command to run a named schematic. +Provide the path to the project folder, the schematic name, and any mandatory options, in the following format. + + +schematics <path-to-schematics-project>:<schematics-name> --<required-option>=<value> + + +The path can be absolute or relative to the current working directory where the command is executed. +For example, to run the schematic we just generated (which has no required options), use the following command. + + +schematics .:hello-world + + +### Adding a schematic to a collection + +To add a schematic to an existing collection, use the same command you use to start a new schematics project, but run the command inside the project folder. + + +cd hello-world +schematics blank --name=goodbye-world + + +The command generates the new named schematic inside your collection, with a main `index.ts` file and its associated test spec. +It also adds the name, description, and factory function for the new schematic to the collection's schema in the `collection.json` file. + +## Collection contents + +The top level of the root project folder for a collection contains configuration files, a `node_modules` folder, and a `src/` folder. +The `src/` folder contains subfolders for named schematics in the collection, and a schema, `collection.json`, which describes the collected schematics. +Each schematic is created with a name, description, and factory function. + + +{ + "$schema": + "../node_modules/@angular-devkit/schematics/collection-schema.json", + "schematics": { + "hello-world": { + "description": "A blank schematic.", + "factory": "./hello-world/index#helloWorld" + } + } +} + + +* The `$schema` property specifies the schema that the CLI uses for validation. +* The `schematics` property lists named schematics that belong to this collection. + Each schematic has a plain-text description, and points to the generated entry function in the main file. +* The `factory` property points to the generated entry function. In this example, you invoke the `hello-world` schematic by calling the `helloWorld()` factory function. +* The optional `schema` property points to a JSON schema file that defines the command-line options available to the schematic. +* The optional `aliases` array specifies one or more strings that can be used to invoke the schematic. + For example, the schematic for the Angular CLI “generate” command has an alias “g”, allowing you to use the command `ng g`. + +### Named schematics + +When you use the Schematics CLI to create a blank schematics project, the new blank schematic is the first member of the collection, and has the same name as the collection. +When you add a new named schematic to this collection, it is automatically added to the `collection.json` schema. + +In addition to the name and description, each schematic has a `factory` property that identifies the schematic’s entry point. +In the example, you invoke the schematic's defined functionality by calling the `helloWorld()` function in the main file, `hello-world/index.ts`. + +
+ overview +
+ +Each named schematic in the collection has the following main parts. + +| | | +| :------------- | :-------------------------------------------| +| `index.ts` | Code that defines the transformation logic for a named schematic. | +| `schema.json` | Schematic variable definition. | +| `schema.d.ts` | Schematic variables. | +| `files/` | Optional component/template files to replicate. | + +It is possible for a schematic to provide all of its logic in the `index.ts` file, without additional templates. +You can create dynamic schematics for Angular, however, by providing components and templates in the `files/` folder, like those in standalone Angular projects. +The logic in the index file configures these templates by defining rules that inject data and modify variables. diff --git a/aio/content/guide/schematics-for-libraries.md b/aio/content/guide/schematics-for-libraries.md new file mode 100644 index 0000000000..34edbfa839 --- /dev/null +++ b/aio/content/guide/schematics-for-libraries.md @@ -0,0 +1,320 @@ +# Schematics for Libraries + +When you create an Angular library, you can provide and package it with schematics that integrate it with the Angular CLI. +With your schematics, your users can use `ng add` to install an initial version of your library, +`ng generate` to create artifacts defined in your library, and `ng update` to adjust their project for a new version of your library that introduces breaking changes. + +All three types of schematics can be part of a collection that you package with your library. + +Download the library schematics project for a completed example of the steps below. + +## Creating a schematics collection + +To start a collection, you need to create the schematic files. +The following steps show you how to add initial support without modifying any project files. + +1. In your library's root folder, create a `schematics/` folder. + +1. In the `schematics/` folder, create an `ng-add/` folder for your first schematic. + +1. At the root level of the `schematics/` folder, create a `collection.json` file. + +1. Edit the `collection.json` file to define the initial schema for your collection. + + + + + * The `$schema` path is relative to the Angular Devkit collection schema. + * The `schematics` object describes the named schematics that are part of this collection. + * The first entry is for a schematic named `ng-add`. It contains the description, and points to the factory function that is called when your schematic is executed. + +1. In your library project's `package.json` file, add a "schematics" entry with the path to your schema file. + The Angular CLI uses this entry to find named schematics in your collection when it runs commands. + + + + +The initial schema that you have created tells the CLI where to find the schematic that supports the `ng add` command. +Now you are ready to create that schematic. + +## Providing installation support + +A schematic for the `ng add` command can enhance the initial installation process for your users. +The following steps will define this type of schematic. + +1. Go to the /schematics/ng-add/ folder. + +1. Create the main file, `index.ts`. + +1. Open `index.ts` and add the source code for your schematic factory function. + + + + +The only step needed to provide initial `ng add` support is to trigger an installation task using the `SchematicContext`. +The task uses the user's preferred package manager to add the library to the project's `package.json` configuration file, and install it in the project’s `node_modules` directory. + +In this example, the function receives the current `Tree` and returns it without any modifications. +If you need to, you can do additional setup when your package is installed, such as generating files, updating configuration, or any other initial setup your library requires. + +## Building your schematics + +To bundle your schematics together with your library, you must configure the library to build the schematics separately, then add them to the bundle. +You must build your schematics *after* you build your library, so they are placed in the correct directory. + +* Your library needs a custom Typescript configuration file with instructions on how to compile your schematics into your distributed library. + +* To add the schematics to the library bundle, add scripts to the library's `package.json` file. + +Assume you have a library project `my-lib` in your Angular workspace. +To tell the library how to build the schematics, add a `tsconfig.schematics.json` file next to the generated `tsconfig.lib.json` file that configures the library build. + +1. Edit the `tsconfig.schematics.json` file to add the following content. + + + + + * The `rootDir` specifies that your `schematics/` folder contains the input files to be compiled. + + * The `outDir` maps to the library's output folder. By default, this is the `dist/my-lib` folder at the root of your workspace. + +1. To make sure your schematics source files get compiled into the library bundle, add the following scripts to the `package.json` file in your library project's root folder (`projects/my-lib`). + + + + + * The `build` script compiles your schematic using the custom `tsconfig.schematics.json` file. + * The `copy:*` statements copy compiled schematic files into the proper locations in the library output folder in order to preserve the file structure. + * The `postbuild` script copies the schematic files after the `build` script completes. + +## Providing generation support + +You can add a named schematic to your collection that lets your users use the `ng generate` command to create an artifact that is defined in your library. + +We'll assume that your library defines a service, `my-service`, that requires some setup. You want your users to be able to generate it using the following CLI command. + + +ng generate my-lib:my-service + + +To begin, create a new subfolder, `my-service`, in the `schematics` folder. + +### Configure the new schematic + +When you add a schematic to the collection, you have to point to it in the collection's schema, and provide configuration files to define options that a user can pass to the command. + +1. Edit the `schematics/collection.json` file to point to the new schematic subfolder, and include a pointer to a schema file that will specify inputs for the new schematic. + + + + +1. Go to the `/schematics/my-service/` folder. + +1. Create a `schema.json` file and define the available options for the schematic. + + + + + * *id* : A unique id for the schema in the collection. + * *title* : A human-readable description of the schema. + * *type* : A descriptor for the type provided by the properties. + * *properties* : An object that defines the available options for the schematic. + + Each option associates key with a type, description, and optional alias. + The type defines the shape of the value you expect, and the description is displayed when the user requests usage help for your schematic. + + See the workspace schema for additional customizations for schematic options. + +1. Create a `schema.ts` file and define an interface that stores the values of the options defined in the `schema.json` file. + + + + + * *name* : The name you want to provide for the created service. + * *path* : Overrides the path provided to the schematic. The default path value is based on the current working directory. + * *project* : Provides a specific project to run the schematic on. In the schematic, you can provide a default if the option is not provided by the user. + +### Add template files + +To add artifacts to a project, your schematic needs its own template files. +Schematic templates support special syntax to execute code and variable substitution. + +1. Create a `files/` folder inside the `schematics/my-service/` folder. + +1. Create a file named `__name@dasherize__.service.ts.template` that defines a template you can use for generating files. This template will generate a service that already has Angular's `HttpClient` injected into its constructor. + + + +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; + +@Injectable({ + providedIn: 'root' +}) +export class <%= classify(name) %>Service { + constructor(private http: HttpClient) { } +} + + + +* The `classify` and `dasherize` methods are utility functions you schematic will use to transform your source template and filename. + +* The `name` is provided as a property from your factory function. It is the same `name` you defined in the schema. + +### Add the factory function + +Now that you have the infrastructure in place, you can define the main function that performs the modifications you need in the user's project. + +The Schematics framework provides a file templating system, which supports both path and content templates. +The system operates on placeholders defined inside files or paths that loaded in the input `Tree`. +It fills these in using values passed into the `Rule`. + +For details of these data structure and syntax, see the [Schematics README](https://github.com/angular/angular-cli/blob/master/packages/angular_devkit/schematics/README.md). + + +1. Create the main file, `index.ts` and add the source code for your schematic factory function. + +1. First, import the schematics definitions you will need. The Schematics framework offers many utility functions to create and use rules when running a schematic. + + + + +1. Import the defined schema interface that provides the type information for your schematic's options. + + + + +1. To build up the generation schematic, start with an empty rule factory. + + + + +This simple rule factory returns the tree without modification. +The options are the option values passed through from the `ng generate` command. + +## Define a generation rule + +We now have the framework in place for creating the code that actually modifies the user's application to set it up for the service defined in your library. + +The Angular workspace where the user has installed your library contains multiple projects (applications and libraries). +The user can specify the project on the command line, or allow it to default. +In either case, your code needs to identify the specific project to which this schematic is being applied, so that you can retrieve information from the project configuration. + +You can do this using the `Tree` object that is passed in to the factory function. +The `Tree` methods give you access to the complete file tree in your workspace, allowing you to read and write files during the execution of the schematic. + +### Get the project configuration + +1. To determine the destination project, use the `Tree.read()` method to read the contents of the workspace configuration file, `angular.json`, at the root of the workspace. + Add the following code to your factory function. + + + + + * Be sure to check that the context exists and throw the appropriate error. + + * After reading the contents into a string, parse the configuration into a JSON object, typed to the `WorkspaceSchema`. + +1. The `WorkspaceSchema` contains all the properties of the workspace configuration, including a `defaultProject` value for determining which project to use if not provided. + We will use that value as a fallback, if no project is explicitly specified in the `ng generate` command. + + + + +1. Now that you have the project name, use it to retrieve the project-specific configuration information. + + + + + The `workspace projects` object contains all the project-specific configuration information. + +1. The `options.path` determines where the schematic template files are moved to once the schematic is applied. + + The `path` option in the schematic's schema is substituted by default with the current working directory. + If the `path` is not defined, use the `sourceRoot` from the project configuration along with the `projectType`. + + + + +### Define the rule + +A `Rule` can use external template files, transform them, and return another `Rule` object with the transformed template. You can use the templating to generate any custom files required for your schematic. + +1. Add the following code to your factory function. + + + + + * The `apply()` method applies multiple rules to a source and returns the transformed source. It takes 2 arguments, a source and an array of rules. + * The `url()` method reads source files from your filesystem, relative to the schematic. + * The `applyTemplates()` method receives an argument of methods and properties you want make available to the schematic template and the schematic filenames. It returns a `Rule`. This is where you define the `classify()` and `dasherize()` methods, and the `name` property. + * The `classify()` method takes a value and returns the value in title case. For example, if the provided name is `my service`, it is returned as `MyService` + * The `dasherize()` method takes a value and returns the value in dashed and lowercase. For example, if the provided name is MyService, it is returned as `my-service. + * The `move` method moves the provided source files to their destination when the schematic is applied. + +1. Finally, the rule factory must return a rule. + + + + + The `chain()` method allows you to combine multiple rules into a single rule, so that you can perform multiple operations in a single schematic. + Here you are only merging the template rules with any code executed by the schematic. + +See a complete exampled of the schematic rule function. + + + + +For more information about rules and utility methods, see [Provided Rules](https://github.com/angular/angular-cli/tree/master/packages/angular_devkit/schematics#provided-rules). + +## Running your library schematic + +After you build your library and schematics, you can install the schematics collection to run against your project. The steps below show you how to generate a service using the schematic you created above. + + +### Build your library and schematics + +From the root of your workspace, run the `ng build` command for your library. + + + + ng build my-lib + + + +Then, you change into your library directory to build the schematic + + + + cd projects/my-lib + npm run build + + + +### Link the library + +Your library and schematics are packaged and placed in the `dist/my-lib` folder at the root of your workspace. For running the schematic, you need to link the library into your `node_modules` folder. From the root of your workspace, run the `npm link` command with the path to your distributable library. + + + +npm link dist/my-lib + + + +### Run the schematic + +Now that your library is installed, you can run the schematic using the `ng generate` command. + + + +ng generate my-lib:my-service --name my-data + + + +In the console, you will see that the schematic was run and the `my-data.service.ts` file was created in your app folder. + + + +CREATE src/app/my-data.service.ts (208 bytes) + + diff --git a/aio/content/guide/schematics.md b/aio/content/guide/schematics.md new file mode 100644 index 0000000000..27612abddc --- /dev/null +++ b/aio/content/guide/schematics.md @@ -0,0 +1,121 @@ +# Schematics + +A schematic is a template-based code generator that supports complex logic. +It is a set of instructions for transforming a software project by generating or modifying code. +Schematics are packaged into [collections](guide/glossary#collection) and installed with npm. + +The schematic collection can be a powerful tool for creating, modifying, and maintaining any software project, but is particularly useful for customizing Angular projects to suit the particular needs of your own organization. +You might use schematics, for example, to generate commonly-used UI patterns or specific components, using predefined templates or layouts. +You can use schematics to enforce architectural rules and conventions, making your projects consistent and inter-operative. + +## Schematics for the Angular CLI + +Schematics are part of the Angular ecosystem. The [Angular CLI](guide/glossary#cli) uses schematics to apply transforms to a web-app project. +You can modify these schematics, and define new ones to do things like update your code to fix breaking changes in a dependency, for example, or to add a new configuration option or framework to an existing project. + +Schematics that are included in the `@schematics/angular` collection are run by default by the commands `ng generate` and `ng add`. +The package contains named schematics that configure the options that are available to the CLI for `ng generate` sub-commands, such as `ng generate component` and `ng generate service`. +The subcommands for `ng generate` are shorthand for the corresponding schematic. You can specify a particular schematic (or collection of schematics) to generate, using the long form: + + +ng generate my-schematic-collection:my-schematic-name + + +—or— + + +ng generate my-schematic-name --collection collection-name + + +### Configuring CLI schematics + +A JSON schema associated with a schematic tells the Angular CLI what options are available to commands and subcommands, and determines the defaults. +These defaults can be overridden by providing a different value for an option on the command line. +See [Workspace Configuration](guide/workspace-config) for information about how you can change the generation option defaults for your workspace. + +The JSON schemas for the default schematics used by the CLI to generate projects and parts of projects are collected in the package [`@schematics/angular`](https://raw.githubusercontent.com/angular/angular-cli/v7.0.0/packages/schematics/angular/application/schema.json). +The schema describes the options available to the CLI for each of the `ng generate` sub-commands, as shown in the `--help` output. + +## Developing schematics for libraries + +As a library developer, you can create your own collections of custom schematics to integrate your library with the Angular CLI. + +* An *add schematic* allows developers to install your library in an Angular workspace using `ng add`. + +* *Generation schematics* can tell the `ng generate` subcommands how to modify projects, add configurations and scripts, and scaffold artifacts that are defined in your library. + +* An *update schematic* can tell the `ng update` command how to update your library's dependencies and adjust for breaking changes when you release a new version. + +For more details of what these look like and how to create them, see: +* [Authoring Schematics](guide/schematics-authoring) +* [Schematics for Libraries](guide/schematics-for-libraries) + +### Add schematics + +An add schematic is typically supplied with a library, so that the library can be added to an existing project with `ng add`. +The `add` command uses your package manager to download new dependencies, and invokes an installation script that is implemented as a schematic. + +For example, the [`@angular/material`](https://material.angular.io/guide/schematics) schematic tells the `add` command to install and set up Angular Material and theming, and register new starter components that can be created with `ng generate`. +You can look at this one as an example and model for your own add schematic. + +Partner and third party libraries also support the Angular CLI with add schematics. +For example, `@ng-bootstrap/schematics` adds [ng-bootstrap](https://ng-bootstrap.github.io/) to an app, and `@clr/angular` installs and sets up [Clarity from VMWare](https://vmware.github.io/clarity/documentation/v1.0/get-started). + +An add schematic can also update a project with configuration changes, add additional dependencies (such as polyfills), or scaffold package-specific initialization code. +For example, the `@angular/pwa` schematic turns your application into a PWA by adding an app manifest and service worker, and the `@angular/elements`  schematic adds the `document-register-element.js` polyfill and dependencies for Angular Elements. + +### Generation schematics + +Generation schematics are instructions for the `ng generate` command. +The documented sub-commands use the default Angular generation schematics, but you can specify a different schematic (in place of a sub-command) to generate an artifact defined in your library. + +Angular Material, for example, supplies generation schematics for the UI components that it defines. +The following command uses one of these schematics to render an Angular Material `` that is pre-configured with a datasource for sorting and pagination. + + +ng generate @angular/material:table + + +### Update schematics + + The `ng update` command can be used to update your workspace's library dependencies. If you supply no options or use the help option, the command examines your workspace and suggests libraries to update. + + +ng update + We analyzed your package.json, there are some packages to update: + + Name Version Command to update + -------------------------------------------------------------------------------- + @angular/cdk 7.2.2 -> 7.3.1 ng update @angular/cdk + @angular/cli 7.2.3 -> 7.3.0 ng update @angular/cli + @angular/core 7.2.2 -> 7.2.3 ng update @angular/core + @angular/material 7.2.2 -> 7.3.1 ng update @angular/material + rxjs 6.3.3 -> 6.4.0 ng update rxjs + + + There might be additional packages that are outdated. + Run "ng update --all" to try to update all at the same time. + + +If you pass the command a set of libraries to update (or the `--all` flag), it updates those libraries, their peer dependencies, and the peer dependencies that depend on them. + +
+ +If there are inconsistencies (for example, if peer dependencies cannot be matched by a simple [semver](https://semver.io/) range), the command generates an error and does not change anything in the workspace. + +We recommend that you do not force an update of all dependencies by default. Try updating specific dependencies first. + +For more about how the `ng update` command works, see [Update Command](https://github.com/angular/angular-cli/blob/master/docs/specifications/update.md). + +
+ +If you create a new version of your library that introduces potential breaking changes, you can provide an *update schematic* to enable the `ng update` command to automatically resolve any such changes in the project being updated. + +For example, suppose you want to update the Angular Material library. + + +ng update @angular/material + + +This command updates both `@angular/material` and its dependency `@angular/cdk` in your workspace's `package.json`. +If either package contains an update schematic that covers migration from the existing version to a new version, the command runs that schematic on your workspace. diff --git a/aio/content/guide/workspace-config.md b/aio/content/guide/workspace-config.md index 6bb1979420..5c67cfbccc 100644 --- a/aio/content/guide/workspace-config.md +++ b/aio/content/guide/workspace-config.md @@ -1,18 +1,18 @@ # Angular Workspace Configuration -A file named `angular.json` at the root level of an Angular [workspace](guide/glossary#workspace) provides workspace-wide and project-specific configuration defaults for build and development tools provided by the Angular CLI. -Path values given in the configuration are relative to the root workspace folder. +A file named `angular.json` at the root level of an Angular [workspace](guide/glossary#workspace) provides workspace-wide and project-specific configuration defaults for build and development tools provided by the Angular CLI. +Path values given in the configuration are relative to the root workspace folder. ## Overall JSON structure -At the top level of `angular.json`, a few properties configure the workspace, and a `projects` section contains the remaining per-project configuration options. +At the top level of `angular.json`, a few properties configure the workspace, and a `projects` section contains the remaining per-project configuration options. * `version`: The configuration-file version. * `newProjectRoot`: Path where new projects are created. Absolute or relative to the workspace folder. * `defaultProject`: Default project name to use in commands, where not provided as an argument. When you use `ng new` to create a new app in a new workspace, that app is the default project for the workspace until you change it here. -* `projects` : Contains a subsection for each project (library, app, e2e test app) in the workspace, with the per-project configuration options. +* `projects` : Contains a subsection for each project (library, app, e2e test app) in the workspace, with the per-project configuration options. -The initial app that you create with `ng new app_name` is listed under "projects", along with its corresponding end-to-end test app: +The initial app that you create with `ng new app_name` is listed under "projects", along with its corresponding end-to-end test app: projects @@ -23,11 +23,11 @@ projects Each additional app that you create with `ng generate application` has a corresponding end-to-end test project, with its own configuration section. -When you create a library project with `ng generate library`, the library project is also added to the `projects` section. +When you create a library project with `ng generate library`, the library project is also added to the `projects` section.
- Note that the `projects` section of the configuration file does not correspond exactly to the workspace file structure. + Note that the `projects` section of the configuration file does not correspond exactly to the workspace file structure. * The initial app created by `ng new` is at the top level of the workspace file structure, along with its e2e app. * Additional apps, e2e apps, and libraries go into a `projects` folder in the workspace. @@ -56,14 +56,14 @@ The following top-level configuration properties are available for each project, | `sourceRoot` | The root folder for this project's source files. | | `projectType` | One of "application" or "library". An application can run independently in a browser, while a library cannot. Both an app and its e2e test app are of type "application".| | `prefix` | A string that Angular prepends to generated selectors. Can be customized to identify an app or feature area. | -| `schematics` | An object containing schematics that customize CLI commands for this project. | +| `schematics` | An object containing configuration defaults that customize the CLI command behavior for this project. See [Schematics Overview](guide/schematics). | | `architect` | An object containing configuration defaults for Architect builder targets for this project. | ## Project tool configuration options Architect is the tool that the CLI uses to perform complex tasks such as compilation and test running, according to provided configurations. The `architect` section contains a set of Architect *targets*. Many of the targets correspond to the CLI commands that run them. Some additional predefined targets can be run using the `ng run` command, and you can define your own targets. -Each target object specifies the `builder` for that target, which is the npm package for the tool that Architect runs. In addition, each target has an `options` section that configure default options for the target, and a `configurations` section that names and specifies alternative configurations for the target. See the example in [Build target](#build-target) below. +Each target object specifies the `builder` for that target, which is the npm package for the tool that Architect runs. In addition, each target has an `options` section that configure default options for the target, and a `configurations` section that names and specifies alternative configurations for the target. See the example in [Build target](#build-target) below. "architect": { @@ -90,11 +90,11 @@ Each target object specifies the `builder` for that target, which is the npm pac * The `architect/extract-i18n` section configures defaults for options of the `ng-xi18n` tool used by the `ng xi18n` command, which extracts marked message strings from source code and outputs translation files. -* The `architect/server` section configures defaults for creating a Universal app with server-side rendering, using the `ng run :server` command. +* The `architect/server` section configures defaults for creating a Universal app with server-side rendering, using the `ng run :server` command. * The `architect/app-shell` section configures defaults for creating an app shell for a progressive web app (PWA), using the `ng run :app-shell` command. -In general, the options for which you can configure defaults correspond to the command options listed in the [CLI reference page](cli) for each command. +In general, the options for which you can configure defaults correspond to the command options listed in the [CLI reference page](cli) for each command. Note that all options in the configuration file must use [camelCase](guide/glossary#case-conventions), rather than dash-case. {@a build-target} @@ -113,15 +113,15 @@ The `architect/build` section configures defaults for options of the `ng build` ### Alternate build configurations -By default, a `production` configuration is defined, and the `ng build` command has `--prod` option that builds using this configuration. The `production` configuration sets defaults that optimize the app in a number of ways, such bundling files, minimizing excess whitespace, removing comments and dead code, and rewriting code to use short, cryptic names ("minification"). +By default, a `production` configuration is defined, and the `ng build` command has `--prod` option that builds using this configuration. The `production` configuration sets defaults that optimize the app in a number of ways, such bundling files, minimizing excess whitespace, removing comments and dead code, and rewriting code to use short, cryptic names ("minification"). -You can define and name additional alternate configurations (such as `stage`, for instance) appropriate to your development process. Some examples of different build configurations are `stable`, `archive` and `next` used by AIO itself, and the individual locale-specific configurations required for building localized versions of an app. For details, see [Internationalization (i18n)](guide/i18n#merge-aot). +You can define and name additional alternate configurations (such as `stage`, for instance) appropriate to your development process. Some examples of different build configurations are `stable`, `archive` and `next` used by AIO itself, and the individual locale-specific configurations required for building localized versions of an app. For details, see [Internationalization (i18n)](guide/i18n#merge-aot). {@a build-props} ### Additional build and test options -The configurable options for a default or targeted build generally correspond to the options available for the [`ng build`](cli/build), [`ng serve`](cli/serve), and [`ng test`](cli/test) commands. For details of those options and their possible values, see the [CLI Reference](cli). +The configurable options for a default or targeted build generally correspond to the options available for the [`ng build`](cli/build), [`ng serve`](cli/serve), and [`ng test`](cli/test) commands. For details of those options and their possible values, see the [CLI Reference](cli). Some additional options (listed below) can only be set through the configuration file, either by direct editing or with the [`ng config`](cli/config) command. diff --git a/aio/content/images/guide/schematics/collection-files.gif b/aio/content/images/guide/schematics/collection-files.gif new file mode 100644 index 0000000000..125406ed4a Binary files /dev/null and b/aio/content/images/guide/schematics/collection-files.gif differ diff --git a/aio/content/navigation.json b/aio/content/navigation.json index 0171498018..a7171846b5 100644 --- a/aio/content/navigation.json +++ b/aio/content/navigation.json @@ -503,6 +503,27 @@ } ] }, + { + "title": "Schematics", + "tooltip": "Understanding schematics.", + "children": [ + { + "url": "guide/schematics", + "title": "Schematics Overview", + "tooltip": "Understand how schematics are used in Angular." + }, + { + "url": "guide/schematics-authoring", + "title": "Authoring Schematics", + "tooltip": "Understand the structure of a schematic." + }, + { + "url": "guide/schematics-for-libraries", + "title": "Schematics for Libraries", + "tooltip": "Use schematics to integrate your library with the Angular CLI." + } + ] + }, { "url": "guide/ivy", "title": "Angular Ivy", @@ -761,4 +782,4 @@ "url": "https://v2.angular.io" } ] -} +} \ No newline at end of file diff --git a/aio/package.json b/aio/package.json index 22a344533f..2a6acf570e 100644 --- a/aio/package.json +++ b/aio/package.json @@ -93,7 +93,6 @@ "classlist.js": "^1.1.20150312", "core-js": "^2.4.1", "rxjs": "^6.3.0", - "tslib": "^1.9.0", "zone.js": "^0.8.26" }, "devDependencies": { @@ -156,6 +155,7 @@ "shelljs": "^0.7.7", "tree-kill": "^1.1.0", "ts-node": "^3.3.0", + "tslib": "^1.9.0", "tslint": "~5.9.1", "typescript": "~3.3.3333", "uglify-js": "^3.0.15", diff --git a/aio/tools/example-zipper/customizer/package-json/schematics.json b/aio/tools/example-zipper/customizer/package-json/schematics.json new file mode 100644 index 0000000000..44e2cc572e --- /dev/null +++ b/aio/tools/example-zipper/customizer/package-json/schematics.json @@ -0,0 +1,24 @@ +{ + "scripts": [ + { "name": "ng", "command": "ng" }, + { "name": "build", "command": "ng build --prod" }, + { "name": "build:lib", "command": "ng build my-lib" }, + { "name": "start", "command": "ng serve" }, + { "name": "test", "command": "ng test" }, + { "name": "lint", "command": "ng lint" }, + { "name": "e2e", "command": "ng e2e" } + ], + "dependencies": [], + "devDependencies": [ + "@angular-devkit/build-angular", + "@angular-devkit/build-ng-packagr", + "@angular/cli", + "@types/jasminewd2", + "jasmine-spec-reporter", + "karma-coverage-istanbul-reporter", + "ng-packagr", + "tsickle", + "tslib", + "ts-node" + ] +} diff --git a/aio/tools/example-zipper/exampleZipper.js b/aio/tools/example-zipper/exampleZipper.js index 3afce755d7..00d713428a 100644 --- a/aio/tools/example-zipper/exampleZipper.js +++ b/aio/tools/example-zipper/exampleZipper.js @@ -102,7 +102,9 @@ class ExampleZipper { 'src/typings.d.ts', 'src/environments/**/*', 'src/tsconfig.*', - 'src/tslint.*' + 'src/tslint.*', + // Only ignore root package.json + '!package.json' ]; var alwaysExcludes = [ '!**/bs-config.e2e.json', @@ -110,7 +112,6 @@ class ExampleZipper { '!**/*zipper.*', '!**/systemjs.config.js', '!**/npm-debug.log', - '!**/package.json', '!**/example-config.json', '!**/wallaby.js', // AoT related files diff --git a/aio/tools/examples/example-boilerplate.js b/aio/tools/examples/example-boilerplate.js index 612243857b..4304264fe4 100644 --- a/aio/tools/examples/example-boilerplate.js +++ b/aio/tools/examples/example-boilerplate.js @@ -88,6 +88,11 @@ BOILERPLATE_PATHS.ivy = { ] }; +BOILERPLATE_PATHS.schematics = [ + ...cliRelativePath, + 'angular.json' +]; + const EXAMPLE_CONFIG_FILENAME = 'example-config.json'; class ExampleBoilerPlate { diff --git a/aio/tools/examples/shared/boilerplate/schematics/angular.json b/aio/tools/examples/shared/boilerplate/schematics/angular.json new file mode 100644 index 0000000000..7923d1b35f --- /dev/null +++ b/aio/tools/examples/shared/boilerplate/schematics/angular.json @@ -0,0 +1,170 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "angular.io-example": { + "root": "", + "sourceRoot": "src", + "projectType": "application", + "prefix": "app", + "schematics": {}, + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "outputPath": "dist", + "index": "src/index.html", + "main": "src/main.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "src/tsconfig.app.json", + "assets": [ + "src/favicon.ico", + "src/assets" + ], + "styles": [ + "src/styles.css" + ], + "scripts": [] + }, + "configurations": { + "production": { + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.prod.ts" + } + ], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "extractCss": true, + "namedChunks": false, + "aot": true, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": true, + "budgets": [ + { + "type": "initial", + "maximumWarning": "2mb", + "maximumError": "5mb" + } + ] + } + } + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "options": { + "browserTarget": "angular.io-example:build" + }, + "configurations": { + "production": { + "browserTarget": "angular.io-example:build:production" + } + } + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "angular.io-example:build" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "src/test.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "src/tsconfig.spec.json", + "karmaConfig": "src/karma.conf.js", + "styles": [ + "src/styles.css" + ], + "scripts": [], + "assets": [ + "src/favicon.ico", + "src/assets" + ] + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "src/tsconfig.app.json", + "src/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "angular.io-example-e2e": { + "root": "e2e/", + "projectType": "application", + "prefix": "", + "architect": { + "e2e": { + "builder": "@angular-devkit/build-angular:protractor", + "options": { + "protractorConfig": "e2e/protractor.conf.js", + "devServerTarget": "angular.io-example:serve" + }, + "configurations": { + "production": { + "devServerTarget": "angular.io-example:serve:production" + } + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": "e2e/tsconfig.e2e.json", + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "my-lib": { + "root": "projects/my-lib", + "sourceRoot": "projects/my-lib/src", + "projectType": "library", + "prefix": "lib", + "architect": { + "build": { + "builder": "@angular-devkit/build-ng-packagr:build", + "options": { + "tsConfig": "projects/my-lib/tsconfig.lib.json", + "project": "projects/my-lib/ng-package.json" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/my-lib/src/test.ts", + "tsConfig": "projects/my-lib/tsconfig.spec.json", + "karmaConfig": "projects/my-lib/karma.conf.js" + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "projects/my-lib/tsconfig.lib.json", + "projects/my-lib/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + } + }, + "defaultProject": "angular.io-example" +}