This is a series of posts that, if you follow through, will help you acquire the necessary knowledge to write your first schematics and even publish them to npm with ng-add support!

Let's start!

What are schematics, you ask?

Schematics are code generators based on descriptive code. Basically, you write some descriptions of what you need and artifacts are generated. Those artifacts could be more code, templates, etc

What problems can I solve with schematics?

With Schematics you will be able to automate a lot of tasks across your projects or organization, allowing you to establish patterns and enforce best practices.

You will become more productive and reduce manual tasks, especially those around setup.

You won't need to write or read so much documentation!

Additionally, if you write a library, you will automate steps to have it working, which makes it more attractive to other developers, that do not need to perform them every time they install it.

In short, Schematics help with

  • structure standardization
  • enforcing patterns
  • enforcing best practices
  • enforcing naming conventions
  • reuse implementations
  • automate tasks

Main advantages of Schematics

So schematics as code and other artifacts generators help us setup and configure a new project (or parts of it) in a standardized and automated way, with the following advantages

  • they're extensible and atomic
  • they're safe and synchronous
  • they're implemented in debug mode by default

Extensible and atomic

Schematics are organized in collections and can be combined or chained, but apply transformations in an atomic way.

Safe and synchronous

By being atomic, and because of their synchronous nature, Schematics are safe. They're executed one after another, which means errors are easily traceable.

Default debug mode

When executed from the Schematics CLI, they're dry-run, which means that by default, none of the transformations is really applied to the file system.

Important vocabulary

It is difficult to learn Schematics without being familiar with its API and vocabulary first. Let's start with the vocabulary you will see in repeated over and over when we start the practical lessons.

Source, or ./files

The Tree or source is the VIRTUAL tree composed by a base (files that actually do exist, and are identical to our file system's content) and the staging area (where all transformations are applied), plus some metadata necessary to work with all.

For example, when we want our schematic to create new files in our system, we create a /files folder at the root of our schematic, with contents identical to what we want to be replicated.

We will call this folder files simply because by default, the typescript compiler will ignore this folder and never transpile it. If we want to call it something else, we need to configure the tsconfig.json file, to know that and exclude that folder.

Rule{}

The Rule object defines a function that takes a tree as an argument and returns a new tree, after all the transformations have been applied.

We can also use Observables, and return the Observable of a Tree.

index.ts

It's a Rule factory that acts as entry point for our schematic. You find this file at the root of the schematic. It will always return a Rule.

It runs always in a context, that provides the metadata and utilities (ie: logging), necessary.

SchematicContext

This object represents the context in which the schematic runs, as explained before.

Action

Action is the most atomic transformation you can apply to a tree.

collection.json

A set of definitions for one or several schematics, where we find the declarations and values for the description, the path to the factory (or entry point for each schematic), the path to its validation schema (when it has one), and its aliases (when it has them)

Aliases

Aliases are as expected, an alternative string you can call the schematic with to invoke its execution.

Each schematic may have one or several aliases.

"aliases": ["alias"]

schema.json

It's the validation schema for the schematic and its descriptor properties. It's optional, but recommended!

Options

Configuration options you can pass to the schematic, for example --name

Prompts

Prompts allow the schematic interact with the user via the CLI. They're part of the schema.json

The virtual tree

The virtual tree is an abstraction of the file system of the project we want to transform, consisting of the base (the existing files), a staging area where the actions to applied (transformations) are applied, and the metadata derived of the context.

Important!

It is very important to understand that the transformations applied do not really modify the base directly! They're applied to the files in the staging area.

To understand this concept, you can think of git, and how every diff, every modification you do of a file, is not really effective unless you commit it to the index. And it does not really affect the upstream unless you push it and merge it!

In schematics, it works like this:

Tansformations applied in the staging area, schematics

Actions

All transformations applied to a tree are essentially atomic actions.

These actions have four main types: CreateFileAction, DeleteFileAction, OverwriteFileAction, RenameFileAction

You can find the actual implementation for each action type, exploring the implementation in your local setup, at node_modules/@angular-devkit/schematics/src/tree/action.js

Until here, a bit of theory. We will dive a bit deeper in the API, in the next post!