In the previous posts we read an overview of what schematics are and what they're used for, the important vocabulary to follow the next posts, as well as a quick reference to the most important and useful methods from the Schematics API.
Now we will actually write schematics!
Make sure you have the following packages installed at a global level in your computer. Notice that in a real life development context, you may have some of those local to your project. But for the sake of having a stable development environment, we will globally install them.
Now we're ready to...
Generate our first blank schematic
Generating a blank schematic is super straight forward with the schematics-cli.
Go to the folder where you want your schematics to be at and type in your terminal:
As you can already appreciate, we're simply invoking the schematics function to generate a blank schematic, and we're passing the name of the collection, as option.
If we inspect the generated folder, we can verify it's an npm package, featuring a package.json with necessary dependencies, and the
We will also find a
tsconfig.json file, and a
Let's focus in the contents of the
This file features our schematic as the first schematic in the collection
indepth-dev-schematic , of name also
This file is the one read by the schematic-cli and the angular-schematic tool, at the time of running schematics.
Any successive schematics in the same package, need to be added to the collection.
This file is the entry point for the schematic. When a blank schematic is generated, the Rule Factory looks like this
As you can see, the function is named as a camelized form of the schematic name. This function takes options as arguments, and returns a Rule. The Rule is a function that takes the tree and the context (please go to the previous post to learn more!) and returns another tree.
Important things to remember about the entry file index.ts:
- it can feature a rule factory or several
- you don't need to export the function as default
In theory, we could already run this schematic with the schematics-cli, but it will obviously output nothing but a console message `Nothing to be done.`, so let's make it more interesting and use the create method, to create a readme file.
Execute a custom schematic with the schematic-cli
Now let's head back to the terminal and prompt the schematic execution. You must be inside the schematic folder, at root level (or where the package.json is at).
Because you're at root level, you don't need to pass the name of the collection, so it's
. followed by a colon
: and the name of the schematic, in this case `indepth-dev-schematic` . In the future, we will add an alias to the schematic, in order to invoke it with a shorter, or more user friendly name.
Just hit enter and see the magic happen!
The schematic did not generate anything
Do not despair. This is the expected behavior, since schematics run in debug mode, by default, so if you want to make sure that the schematics modify your file system, you need to run them with the
Now you should see the
readme.md file in your file system. Congratulations!
Passing options as arguments from the CLI
Right now we've just hardcoded the values for the file path or name, and the content string. Let's now pass it from the CLI, to achieve a more dynamic output.
In order to do that, let's update the RuleFactory like this:
Now we can generate the schematic, like this
Let's create a model now, so we get rid of `any`
When you generate a blank schematic, options are declared as type
any. That's because the generator has no idea what will be needed. We need to fix that by creating a schema model.
Create a file called
schema.ts at the same level of your
index.ts , and modify it like this.
Now you can add the schema type to the options, like this.
Adding a validation schema to our schematic
If you've read the previous posts, you know you can add a validation schema to your schematic, by creating a
schema.json file at the same level as your entry file. This will serve us to define defaults for our options, flag them as required, make sure we're passing the right types, and even issuing prompts.
Add the following content to the
This schema declares three options as properties of schema option, with id
content are argument vectors, in position 0 and 1, as defaults. They're also required. The third value is the extension and it's not mandatory as user input. It also has a default value.
schema.json will only apply when referenced from the collection. So head to the collection and update it like this
Input prompts for custom schematics
Another important use of the schema, is to create prompts to interact with the user via the CLI. These prompts guarantee a better user experience so developers don't have to read tons of documentation to understand what input the schematic needs, in order to run.
Prompts are of three types,
textual input, either string or number,
decision, or a
boolean maps to
list featuring an
enum with subtypes.
Let's modify the
schema.json to add prompts for the required options.
Aliases for custom schematics
Before we build and run the schematic again, we could optimize it a bit more by defining a shorter alias, since generating with
.:indepth-dev-schematic is a bit long and error prone.
To give it an alias, let's go to the
collection.json again and update it like this.
Please notice that aliases takes an array of strings, so you can define multiple aliases for your schematic.
Now you can execute it from the CLI with
$ schematics .:dive
It should prompt you to pass a name and content as options. It will understand the default for extension is
Generating the schematic from an Angular app
Until now, we are running the schematic from the schematics-cli. But that's no fun. We want to run it in an Angular app!
Let's start by linking the package to our current node version, executing
$ npm link
at the root of our package.
Then generate a new angular app, with the CLI and when done, run
$ npm link indepth-dev-schematic
in the app root folder. This creates a symlink to the schematic package, so you can execute it.
Before we run it, let's update the entry file a bit
With this changes, we make sure we are executing the schematic in an Angular workspace and that the file does not already exist.
Now, after re-building, we can finally go to the app and run
Conclusion (for now!)
Of course, this is a very basic example, and we want to do more exciting things. To do that, we need to set some goals. So in the next post, we will propose a real life problem to solve, and actually solve it with schematics.
See you then.