To prepare

  1. Global installation@angular-devkit/schematics-cliTo use theschematicsThe command
$ npm install -g @angular-devkit/schematics-cli
Copy the code
  1. Create a newSchematicsproject
$ schematics blank <schematic-name>
Copy the code

Calling this command into the generated Schematics project root directory will quickly add a blank schematic template named schematic-name> with the corresponding basic information in collection.json.

steps

Create a Schematics starter project

$ schematics blank my-schematics
$ cd my-schematics
$ npm i
Copy the code

1. Schematics files

/src/collection.json

The collection.json file is the main definition file for Schematics as a whole, and contains definitions for all the available schematic templates in the library.

If you look at the @Schematics/Angular package provided by default in Angular CLI-generated projects, you’ll see that collection.json contains common commands to generate components or services. In other words, we can generate just about anything with Schematics.

{
  "$schema": ".. /node_modules/@angular-devkit/schematics/collection-schema.json"."schematics": {
    "my-schematics": {
      "description": "A blank schematic."."factory": "./my-schematics/index#mySchematics"}}}Copy the code
  • description: Describes the Schematic template
  • factory: specifies the Schematic template entry. As you can see from this file, the generated Schematics initial project provides one with the same name by defaultmy-schematicsTemplate, pointing to./my-schematics/indexThe file is not specifically directedmySchematicsFunction. You can also use it only"factory": "./my-schematics/index", you need toindex.tsIn theexport function mySchematics(){}Change toexport default function(){}.

Additional attributes:

  • aliases(Optional) : Specify one or more aliases for the Schematic template, represented as a string array.
  • schema(Optional) : Specifies the individual schema for each Schematic template and all available command-line option parameters.

Also, note that package.json in Schematics engineering has a schematic property pointing to the collection.json file.

index.ts

import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';
// You don't need to export this function by default. You can have more than one rule factory in the same file
// This is a schematic factory function that ultimately returns a rule
export function mySchematics(_options: any) :Rule {
  return (tree: Tree, _context: SchematicContext) = > {
    // Schematic rule is called by Tree and schematic context
    // The rule adds the transformation of the file to the Tree, and returns the processed Tree to the next rule. That is, schematic rules are composable
    return tree;
  };
}
Copy the code

schema.json(Manually created if necessary)

{
  "$schema": "http://json-schema.org/schema"."$id": "MyFirstSchematic"."title": "Hello Option Schema"."type": "object"."description": "My First Schematic"."properties": {
    "name": {                               / / parameter name
      "type": "string".// Parameter type
      "description": "The name of file".// Parameter description
      "$default": {                         // Set this parameter to default
        "$source": "argv".// From the command line
        "index": 0                          // The default location in the command.
        // For example: schematics.:my-schematics Mirai (default position)
        // Schematics.:my-schematics --name=Mirai
      },
      "x-prompt": "Who do we want to greet?" // Interactive prompt when the location parameter is not passed}},"required": [
    "name"]}Copy the code

2. Schematics

factory

The factory function will take some custom _options arguments and return a rule.

Why do we need factory functions instead of enforcing a rule directly: We want the Schematic template to have the flexibility to adapt rules to a range of requirements, so we need a function that takes a custom _options parameter

Rule

Rules are invoked through Tree and SchematicContext, and other rules that have already been implemented can be invoked. Once invoked, the rule adjusts the tree and returns it for further processing.

Tree

Schematics is all about code generation and changes to existing files.

Tree is a virtual representation of each file in the workspace. Using a virtual tree instead of manipulating files directly has some advantages: 1) We only commit changes to the tree if every schematic works successfully. 2) In debug mode (with the –dry-run flag), you can preview changes to the file without affecting the actual file system. 3) I/O operations occur only after the entire process is completed.


3. Experience Schematics with a simple example

Let’s start with the default generated/SRC/my-Schematics template.

//index.ts
export function mySchematics(_options: any) :Rule {
  return (tree: Tree, _context: SchematicContext) = > {
    tree.create('hello.js'.`console.log('Hello Schematics'); `);
    return tree;
  };
}
Copy the code

Build and run under the current project root:

$ npm run build
$ schematics .:my-schematics
Copy the code

Result: CREATE hello.js (32 bytes) is displayed but no actual file is generated.

Cause: Schematics is called in debug mode using a relative path by default. Add –debug=false or –dry-run=false to disable debug mode each time you use schematics.

Call schematics.:my-schematics –debug=false, and a hello.js file with console.log(‘ hello schematics ‘) is generated. .


4. Pass custom options to Schematics

Create schema.json under/SRC/my-Schematics and add the following code. Here we use a custom name parameter as an example.

{
  "$schema": "http://json-schema.org/schema"."$id": "MyFirstSchematic"."title": "Hello Option Schema"."type": "object"."description": "My First Schematic"."properties": {
    "name": {
      "type": "string"."description": "The name of file"."$default": {
        "$source": "argv"."index": 0
      },
      "x-prompt": "Who do we want to greet?"}},"required": [
    "name"]}Copy the code

Introduce the created schema.json in collection.json.

{
  "$schema": ".. /node_modules/@angular-devkit/schematics/collection-schema.json"."schematics": {
    "my-schematics": {
      "description": "A blank schematic."."factory": "./my-schematics/index#mySchematics"."schema": "./my-schematics/schema.json"           // add this}}}Copy the code

We can also create a schema.d.ts to provide code and type checking for our schematics.

export interface Schema{
  name: string;
}
Copy the code

The defined Schema type (function mySchematics(_options: Schema): Rule) is then introduced and used in index.ts.

import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';
import { Schema } from './schema';

export function mySchematics(_options: Schema) :Rule {
  return (tree: Tree, _context: SchematicContext) = > {
    const { name } = _options;
    tree.create('hello.js'.`console.log('Hello ${name}'); `);
    return tree;
  };
}
Copy the code

Debug (delete the hello.js generated last time before debugging) :

$ npm run build
$ schematics .:my-schematics Mirai --debug=false
or
$ schematics .:my-schematics --name=Mirai --debug=false
or
$ schematics .:my-schematics --debug=falseIf the name parameter is not passed,? Whodo we want to greet? 
Copy the code

Js file (CREATE hello.js (27 bytes)) with console.log(‘ hello Mirai’); , parameter passed successfully!


5. Generate more complex schematic templates

Create a new template Component to experience the

.component.ts file generated by the ng g c

command.

Call schematics Blank Component from the root directory, create a files folder under the generate/SRC/Component/folder, and create the __name@dasherize__.component.ts.template file inside. (Create schema.json schema.d.ts in/SRC/Component/folder, add schema properties to collection.json, see previous step)

__(double underscore) is the delimiter that separates the name variable from other ordinary strings. Dasherize is a helper function that takes the value of the name variable and converts it to a kebab case string, and @ is the method that applies the variable to the helper function.

// __name@dasherize__.component.ts.template
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'my-<%= dasherize(name) %>'.templateUrl: './<%= dasherize(name) %>.component.html'.styleUrls: ['./<%= dasherize(name) %>.component.css']})export classThe < %= classify(name) %>Component implements OnInit {

  constructor(){}ngOnInit(){}}Copy the code

Template file writing:

  • The template language uses EJS
  • from@angular-devkit/coreThe introduction ofstrings, use one of themdasherize / classify / underscoreMethods fornameProcess.

EJS label meaning:

  • <% ‘script’ tag, used for process control, no output.
  • <%_ Removes the space before it
  • <%= Output data to template (output is escaped HTML tags)
  • <%- Outputs unescaped data to the template
  • <%# comment tag, no execution, no output
  • <%% outputs the string ‘<%’
  • %> General end tag
  • -%> deletes the newline character immediately following it
  • _%> removes the space after the closing tag
// index.ts
import { Rule, SchematicContext, Tree, mergeWith, applyTemplates, apply, url } from '@angular-devkit/schematics';
import { Schema } from './schema';
import { strings } from '@angular-devkit/core';

export function component(_options: Schema) :Rule {
  return (tree: Tree, _context: SchematicContext) = > {
    return mergeWith(apply(url('./files'), [
      applyTemplates({
        ...strings,
        name: _options.name
      })
    ]))(tree, _context);      //(tree, _context) prevents TS compiler from saying "tree is not used"
  };
}
Copy the code

Change the conversion rule in index.ts:

  • url()Specifies the path to the template file.
  • applyTemplate()Accept arguments and handlers embedded into the template file and delete the conversion file at the same time.templateThe suffix.
  • apply()Apply multiple rules to the template source and return the transformed template.
  • from@angular-devkit/schematicsTo introduce the above methods.

Execute in the current project root path:

$ npm run build
$ schematics .:component --name=UserList --debug=false
Copy the code

The user-list.component file was successfully generated, and you can see that the name parameter in the content is changed to the format corresponding to the UserList passed in.

Finally published to NPM, you can quickly generate custom template code in your project.

conclusion

This is a basic template generation example. Schematics runs inside a Node container, so it’s very playable. You can manipulate files and modify their contents.

See the @Schematics/Angular package, which encapsulates common methods like those in its Utility to specify paths to build files or validate parameters.


reference

Total Guide To Custom Angular Schematics

The Usage of the Schematics was increased in the United States

angular-cli/packages/angular_devkit/schematics

Use Angular Schematics to Simplify Your Life