🏖️ How To Create Your First Custom Angular Schematics With Ease🛠️

It can be easy — piece of cake if you will (📸by Gianna Ciaramello️)

I got very excited when Angular & CLI team announced that they are working on Schematics.

Automatic generation and updating of a code base in organized well defined manner sounds like a lot less tedious work for the developers

Lots of stuff is possible with the help of schematics already. From official initiatives like being able to ng update your project dependencies and ng generate stuff like components or pipes, through semi official (ex Angular team) stuff like nx with schematics for generating services for popular ngrx state management library to small custom one-off schematics which are starting to pop up on npm.

Possible use-cases and benefits of Angular Schematics

Schematics have a huge advantage compared to more traditional approach to dealing with typing heavy tasks like using IDE templates or macros in that they are easily distributed and semantically versioned.

Schematics can also be used to easily introduce and enforce project wide conventions. This can in turn greatly reduce ramp up time for new developers joining ongoing projects.

Instead of trying to decipher outdated documentation they could just generate project specific stuff like entire app skeletons with environment specific configurations or whole feature skeletons with backend integrations and dummy screens.

Then they can focus on what really matters — implementing real features for the end users!

What we will learn

  • what are schematics and collections
  • how to create new schematics collection
  • simplest way to implement new custom schematic
  • how to test our new schematic with real local Angular CLI project
  • how to publish our new custom schematics collection to npm
  • how to use our new customs schematics collection in other projects
Let’s do this!

What does it mean when we speak about collections and schematics

In this article we will often talk about schematics, collections and schematics collection. Let’s look closer into what these terms mean before we dive deeper…

  • schematics collection ( or just collection as used in this article ) is a project ( npm package ) which contains at least one schematic
  • schematic — is a “recipe” which can be executed by using ng generate <schematic-name> to generate and adjust project files

If we use Angular CLI then we can run many schematics by default because they are included in @schematics/angular collection. This enables us to generate stuff like components, services or pipes out of the box.

We can also install additional collection from npm and execute its schematics by passing additional --collection flag to ng generate like in the following example ng generate <schematic-name> --collection <collection-name> .

How to create new schematics collection

To create our own custom collection we have to install couple of dependencies first. Thanks to Martin Hochel for pointing out that the dependencies have changed since the publication of original article and for the great code example picture!

  • @angular-devkit/schematics , @angular-devkit/schematics-cli and @angular-devkit/core to be able to execute schematics from command line
  • @schematics/schematics this is a collection which contains schematics used to generate new collection projects
  • rxjs is a peer dependency

We can install them globally ( npm i -g ) to be able to run available commands everywhere. To put it all nicely together…

npm i -g @angular-devkit/{schematics,schematics-cli,core} @schematics/schematics

Then we can create our new custom collection with schematics @schematics/schematics:schematic --name collection-name.

I agree, this looks like a pretty funky command 🤷😂

Let’s shed a bit of light onto what’s going on there… The command schematics accepts parameter @schematics/schematics:schematics which consists of two parts, the name of the collection (npm package) @schematics/schematics and the name of the executed schematics which is funnily called schematics in our case. Second parameter --name is used to provide name of our new collection.

Running this command will create a new folder with a project skeleton for developing of our new collection with some dummy schematics examples and useful build and test scripts.

Simplest way to create a new custom schematics

Schematics are pretty powerful and can do many advanced things besides generating new files. In official terms schematics apply rules to the tree representing all existing project files and staging area which is a list of changes that will be applied to these files.

This might sound like a lot of things to learn before being able to leverage schematics in our project. Luckily there is a simpler way…

We can just copy and adjust default Angular schematics to get useful results right now and learn more advanced APIs later when needed

In previous step we have generated skeleton of a new collection project which contains couple of example schematics to help us get started. The first thing we have to do is to have a look in collection.json file which contains definition of all implemented schematics and make some adjustments…

Remove all schematics generated by default and replace them with our new custom service schematics

Then we can copy content of the original Angular service schematics located in node_modules/@schematics/angular/service into our src/my-custom-service .

Relative imports in index.ts will become broken so we have to replace them with absolute ones by replacing ../ with @schematics/angular/ . Typescript compiler should stop complaining and it should be possible to successfully run tests using npm t .

Lets look into the content of files directory. It contains some funny looking directories and files with names like __name@dasherize__.service.ts which are used to enable schematics templating capabilities.

In our example __name__ represents a token which will be replaced by the service name provided in ng generate my-custom-service service-name command and dasherize is one of the provided helper functions which outputs standardized file names converting camelCase into dash-separated file names.

Similarly, the file itself contains template of a service file which will be generated by Angular CLI…

Basic Angular service template ( note that it contains templating part delimited by <%= and %> )

Let’s say that in our project we have a convention that our business services never contain data fetching logic, which is in turn handled by dedicated resource services. In that case we end up with a lot of services which look like this…

Example of service we want to generate using our custom service schematics

Such service can be generated using template like this…

Adjusted content of __name@dasherize__.service.ts file
Note how we used two different helper function classify and dasherize to transform passed service name to appropriate forms for the usage (class name vs file import path).
There, we just created our first useful custom schematic!

Copying default Angular service schematic has another advantage because it supports all original parameters and flags out of the box. As with template, we can just simply extend list of supported flags to implement new desired functionality.

Let’s say we want to introduce flag --interface to indicate if we want our service to contain interface stub for a corresponding entity. When the flag is passed (variable is set to true) we want our service to look like this…

“Some” will be replaced by passed service name, more realistic example could be UserService with user property which is of type User…

To achieve that we have to add new interface property in schema.json and schema.d.ts files…

schema.json
schema.d.ts
More scaleable approach is to generate schema.d.ts file with help of an utility library but in our case hand editing seems to be straight forward and simple enough

Good, we are now able to use --interface flag without any complaints from Angular CLI but generated service ends up the same in both cases. In the last step we have to adjust service template to make use of our new flag…

Note use of three different helper functions — classify, dasherize and a new one called camelize — to transform name into contextually appropriate form. Also note conditional blocks containing if and the name of evaluated flag…

As we can see, templating supports evaluation of conditional statements with <%= if(variableName) %> content <%= } %> and nested statements. These capabilities are pretty powerful and enable us to create arbitrary complex templates.

Cool! Our schematic is generating an useful service. Now is the time to use it in a real project…

How to test schematics with real Angular CLI projects

Once we created our custom collection we should write corresponding unit tests to make sure everything works as expected.

The next logical step is to try our collection in practice. This can be performed on any local Angular CLI project. First, we have to run npm build to compile Typescript sources of our collection and then run npm link to make it available for linking by other local projects.

Then we can navigate to our target project and run npm link our-collection-name . After successful linking we can execute ng g schematics-name -c our-collection-name to see if it generates files with expected content in expected path.

How to publish custom schematics collection to npm

Custom collection project generated by provided schematics isn’t publishing friendly per se.

It contains build npm script which just compiles Typescript sources in place. Combine that with default .gitignore file which excludes compiled Javascript files and we get nice “module not found” error when we install and try to use collection which was published just with npm publish without any tweaking.

The simplest way to make this work is to remove the rule that ignores generated .js file from .gitignore so that they are published together with Typescript sources.

Be aware that there are more elegant solutions with compiling Typescript sources into a dist folder and publishing just that but hey, this is just a development tool and it works great so that’s good enough!

How to use new custom schematics collection in other projects

This one is straight forward, we just install newly published collection as we would do for any other npm package with npm i -D our-collection-name .

Then we can run ng generate schematics-name --collection our-collection-name . This can be shortened to ng g schematics-name -c our-collection-name which is much easier to type.

Remember that one collection can and probably will contain more than one useful schematic…

Example of a custom schematics collection

One of the reasons I got very interested in Angular Schematics is that I wrote a small state management library for Angular called ngx-model.

Creating new model services involves a bit of repetitive boilerplate because we always have to inject ModelFactory and instantiate Model instance. Additionally, it’s also very helpful to provide a type for our Model in multiple places to get nice code completion and type checking support.

All this can be handled by editor (IDE) templates but not everyone uses the same editor and it would be a nontrivial task to distribute all these templates for every popular editor.

Schematics fit into this scenario much better because they leverage package manager which is used by every frontend developer who we are interested in. A simple npm i -D @angular-extensions/schematics and ng g model my-model -c @angular-extensions/schematics are enough to get the ball rolling.

Ideas on what to generate with our schematics

The ngx-model schematics generate both service and corresponding test files. They contain necessary boilerplate and an extra example method with a corresponding test.

Only thing the developers need to do is to add their own methods following the provided example.

Schematics which generate boilerplate and examples of use have a huge potential to shorten learning curve for new developers joining any existing project

Generating examples of use can also be a great way to spread know-how about the project specific conventions and best practices. Always up to date in a controlled semantically versioned way. This sounds like a pretty awesome solution if you ask me 😉

That’s all for now!

As you might have noticed I am a huge fan of developer productivity and therefore schematics. I see a huge potential in their use and hope that you can use these tips to enhance developer experience in your projects too!

Please, help spread these tips to a wider audience with your 👏 👏 👏 and promote @angular-extensions/schematics with GitHub ⭐⭐⭐ if you’re a ngx-model user, don’t forget to build your own schematics & have fun!

to get notified about the newest blog posts and useful front-end stuff…

Also, feel free to check some other interesting Angular posts…

And never forget, future is bright
Obviously the bright Future (🚀 by SpaceX)
Like what you read? Give Tomas Trajan a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.