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