Custom Schematics
Bo Vandersteene
@reibo_bo
Setup a javascript project manually
- Compiler / Transpiler
- Package manager and packages
- Build chain optimised for bundle size, performance, etc.
- Testing tools including code coverage


Angular CLI goals
- Ease of use and development
- Extensibility and reusability
- Atomicity
- Asynchronicity
What are shematics
- Scaffolding tools used by angular CLI
- Schematics: The whole project
- Schematics: Code generator
- Collection: Set of Schematics
Who is using it
- Angular CLI
- RxJs
Shematics are atomic

Shematics are atomic
Guarantee not possible that something breaks
project is left behind in unkown state
Howto create a shematic
Just use another shematic
npm i -g @angular-devkit/schematics-cli
schematics blank --name=hello-world
schematics schematic --name=hello-world
Contain sample code
Project structure
Use same version as your CLI-generated project!
One folder for each schematic
{
"$schema": "./node_modules/@angular-devkit/schematics/collection-schema.json",
"schematics": {
"my-schematic": {
"description": "An example schematic",
"factory": "./my-schematic/index#mySchematic"
},
"my-other-schematic": {
"description": "A schematic that uses another schematics.",
"factory": "./my-other-schematic"
},
"my-full-schematic": {
"description": "A schematic using a source and a schema to validate options.",
"factory": "./my-full-schematic",
"schema": "./my-full-schematic/schema.json"
},
...
}
Collections
export default function (options: any): Rule {
....
}
Rule factory
Options passed at the command line
return (tree: Tree, context: SchematicContext) => {
context.logger.info('My Schematic: ' + JSON.stringify(options));
tree.create('hello', 'world');
return tree;
};
Use Parameters

{
"$schema": "http://json-schema.org/schema",
"id": "header",
"title": "Hello world header",
"type": "object",
"properties": {
"index": {
"type": "number",
"default": 1
},
"name": {
"type": "string"
},
"brand": {
"type": "string",
"default": "reibo"
}
},
"required": [
"name"
]
}
export interface MenuOptions {
readonly name: string;
readonly appRoot: string;
readonly path: string;
readonly sourceDir: string;
readonly brand: string
}
schema.ts
schema.json
"header": {
"description": "Header schematic",
"factory": "./header-schematic/index#headerSchematic",
"schema": "./header-schematic/schema.json",
},
Register schematic in collections.json
Templates
Templates
- Create Files folder
- Template files with procedures
TODODODODODOD!!!qs``
Use another schematic
export default function (options: any): Rule {
return chain([
(tree: Tree, context: SchematicContext) => {
context.logger.info('My Other Schematic: ' + JSON.stringify(options));
schematic('my-schematic', { option: true }),
(tree: Tree) => {
tree.rename('hello', 'allo');
}
]);
}
export function myComponent(options: any): Rule {
return chain([
externalSchematic('@schematics/angular', 'component', options),
(tree: Tree, _context: SchematicContext) => {
tree.getDir(options.sourceDir)
.visit(filePath => {
if (!filePath.endsWith('.ts')) {
return;
}
const content = tree.read(filePath);
if (!content) {
return;
}
// Prevent from writing license to files that already have one.
if (content.indexOf(licenseText) == -1) {
tree.overwrite(filePath, licenseText + content);
}
});
return tree;
},
]);
}
scaffolding complete applications
Cover all cases
What changes
Define model to describe variation points
Write and test generator
Conclusion
- Automate boring tasks!
- Official solution in ng world
- CLI, Nx, Ngrx, ...
- Staging area
- Templates
- Rules
- Create own or tweak existing
deck
By Bo Vandersteene
deck
- 157