🏖️ How To Create Your First Custom Angular Schematics With Ease🛠️
ng add-able library so that we can
ng add @angular-extension/model
- generate model services with tests using
ng g @angular-schematics/model:model path/my-service
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/coreto be able to execute schematics from command line
@schematics/schematicsthis is a collection which contains schematics used to generate new collection projects
rxjsis 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…
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…
Then we can copy content of the original Angular service schematics located in
node_modules/@schematics/angular/service into our
Relative imports in
index.ts will become broken so we have to replace them with absolute ones by replacing
@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…
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…
Such service can be generated using template like this…
Note how we used two different helper function
dasherizeto 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…
To achieve that we have to add new
interface property in
More scaleable approach is to generate
schema.d.tsfile 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…
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.
Follow me on Twitter to get notified about the newest blog posts and interesting frontend stuff
How to publish custom schematics collection to npm
Custom collection project generated by provided schematics isn’t publishing friendly per se.
build npm script which just compiles Typescript sources in place. Combine that with default
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!
Also, feel free to check some other interesting Angular posts…
How to handle state in your Angular applications in standardized way with simple API and immutable datamedium.com
Managing multiple requests with RxJS can be done in multiple ways. Each with its pros & cons. Learn when to use…medium.com
Slow internet is a fact of life in many places around the world. Prompt users to wait instead of leave with nice…medium.com
And never forget, future is bright