Merging Custom Angular Schematics

Michael Warneke
4 min readMar 8, 2018

Since the angular devkit team released a schematic version where you are able to extend your custom schematics, it is quite simple to have it inherit from other schematics. This will allow you to set your default schematics in your angular cli project to your custom one and still be able to “ng generate …” all the other generators from the extended ones.

How was it before?

In the past you were able to link your custom schematics folder to your cli project as descripted in the angular blog by Hans or just copy the folder to the node_modules. But in this case you have to call your generators by adding the project name like

ng g <project-name>:<generator>or adding the collection flagng g <my-generator> --collection <my-collection>

Or you have to install your schematics (via npm or copy folder) into your project and using them as the default ones in the angular-cli.json.

“defaults”: {
“schematics”: {
“collection”: “<my-collection>
},
“styleExt”: “css”,
“component”: {}
}

Than you were able to call your generators just like the cli generators.

ng g <my-generator>

But all the other cli generators are not reachable anymore as your custom collection has no information about class, interface, module, etc.

It was possible to add them individually in your custom collection.json.

“class”: {
“aliases”: [ “cl” ],
"extends": "@schematics/angular:class"
},
...

But the list has to be kept maintained with the current angular generators.

How to use the extends property?

In July 2017 Hans from the angular team raised an issue in the angular devkit to implement the merging of different schematics. His description of how to solve the problem is pretty much what the outcome of the update.

When creating your own schematics you can extend these for example from @schematics/angular to keep all cli generators in place. The extends property can be one string or an array of strings giving the opportunity to extend from multiple schematics. Like in his example.

//Taken from issue #34 of the angular devkit
{
"$schema": "http://schema.angular.io/schematics/collection/2",
"name": "my-com",
"description": "My Company default collection, containing all schematics that are used normally",
"extends": [
"@schematics/angular",
"@my-company/schematics-base",
"@my-company/schematics-pages"
],
"schematics": {
}
}
This would include the base angular schematics, the base my-company schematics and the pages schematics. This helps with separating development of each of those, while the end user can just install and use one collection. The schematics are merged, with names being overridden by pages, then base, then angular.

The only difference I noticed so far (@angular-devkit v0.4.3) is that the overriding is from first to last in that array. Meaning, for example if @my-company/schematics-base is overriding the class generator it will be used instead the one from @schematics/angular.

By doing it this way your custom schematics can be deployed to npm and imported to any cli project (or link or copy the folder manually into node_modules) and used as the default schematics and all generators can be called by just

ng g <any-generator>

If you don’t want to write your own schematics but want to merge multiple third party ones this approach works pretty good as well. Only con is you have to create an empty schematic and merge the libraries you want to use. Than import your empty schematics and viola.

Other possibilities

I started a small project to check if I can even extend public schematics like the ones from @ngrx/schematics and @nrwl/schematics. The project is located at github. It is not completed and I am still playing around with the extends property.

The only thing which can be a problem is that both of the schematics are extending the cli generators individually (discussed above). So in the end the class, module, service, etc generators are used which ever schematic is at the end of the extends array.

"extends": [
"@schematics/angular", //this class generator is overridden
"@nrwl/schematics", //this class generator is overridden
"@ngrx/schematics" //this class generator is used
],
"schematics": {
// my onw schematics
}

In my project I used forked and modified versions of nrwl and ngrx where I changed to the general extends of @schematics/angular. I also released PRs to both (nrwl, ngrx) projects to get this into the official versions. Another possibility for these kinds of third party schematics would be to not extend from the official angular schematics at all. But in this case the user has to create his own schematics and extend it from the third party and the angular schematics to get the same result. Both variations have their cons and pros and I can imagine cases where both of them are suitable.

Maybe it makes sense to treat these schematics like individual modules and be able to import an array into the angular-cli.json. Than the user can easily add and remove the ones he want to use and not, without digging to much into the schematics material.

Steps to write your own

Basically, just follow the blog from Hans here.

Install the @angular-devkit/schematics-cli globally either by npm or yarn or whatever package manger you use. Create your schematics project and add your own schematics if you want to. Extend your project from any third party and angular schematics. Publish your project, link it or copy the folder into your cli project and start using your custom schematics and/or enjoy the merging of different third parties.

--

--