{"id":377,"date":"2020-04-27T13:36:00","date_gmt":"2020-04-27T13:36:00","guid":{"rendered":"https:\/\/staging.infragistics.com\/blogs\/?p=377"},"modified":"2025-02-19T14:20:34","modified_gmt":"2025-02-19T14:20:34","slug":"angular-schematics-for-libraries","status":"publish","type":"post","link":"https:\/\/www.infragistics.com\/blogs\/angular-schematics-for-libraries","title":{"rendered":"Angular Schematics for Libraries: Keeping Your Projects Up-to-Date"},"content":{"rendered":"\n<p>Angular schematics have been around for some time now, and I think most of us have gotten used to working with them and enjoying their many benefits. From running a simple ng new to creating complex schematics that automate workflow and project setup, the schematics engine is a big part of any Angular application&#8217;s lifecycle.<\/p>\n\n\n\n<p><strong><em>But what about an Angular library? <\/em><\/strong><\/p>\n\n\n\n<p>At Infragistics, we take great pride in developing and maintaining our open source <a href=\"https:\/\/github.com\/IgniteUI\/igniteui-angular\" rel=\"noopener\">Angular component library<\/a>. But with the library gaining more and more users, and the ever-evolving nature of Angular, we needed to provide an easy way to keep projects up-to- date. This is where, as with most things Angular, the schematics come into play.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"ng-add-ng-update-and-more\"><strong>ng add, ng update and more<\/strong><\/h2>\n\n\n\n<p>In this blog, we\u2019ll show you how to set up your library so that it takes full advantage of Angular CLI\u2019s ng add and ng update commands. We will do this by defining schematic collections in a specific way.<\/p>\n\n\n\n<p><span class=\"TextRun  BCX0 SCXW120011599\" lang=\"EN-US\"><span class=\"NormalTextRun CommentStart  BCX0 SCXW120011599\">Disclaimer:<\/span><\/span><span class=\"EOP  BCX0 SCXW120011599\">&nbsp;<\/span><\/p>\n\n\n\n<p>In order to take full advantage of this post, ideally you should already be familiar with the basics of <a href=\"https:\/\/angular.io\/guide\/schematics\" rel=\"noopener\">Angular schematics<\/a>, and you might be interested in some of the <a href=\"https:\/\/medium.com\/@chrisbautistaaa\/angular-schematics-going-a-bit-more-in-depth-f4858cd26fab\" rel=\"noopener\">other<\/a> <a href=\"https:\/\/medium.com\/rocket-fuel\/angular-schematics-simple-schematic-76be2aa72850\" rel=\"noopener\">great<\/a> <a href=\"https:\/\/medium.com\/@tomastrajan\/total-guide-to-custom-angular-schematics-5c50cf90cdb4\" rel=\"noopener\">posts<\/a> on Medium.<\/p>\n\n\n\n<p>To borrow from a recent angular.io article:<\/p>\n\n\n\n<p>&nbsp;<em>A schematic is a template-based code generator that supports complex logic. It is a set of instructions for transforming a software project by generating or modifying code. Schematics are packaged into <\/em><a href=\"https:\/\/angular.io\/guide\/glossary#collection\" rel=\"noopener\"><em>collections<\/em><\/a><em> and installed with npm.<\/em><\/p>\n\n\n\n<p class=\"text--align-center\"><a class=\"trackBlogCTA ui-btn ui-btn--default ui-btn--sm\" title=\"Button \/ Ignite UI for Angular \/ Try It Now\" href=\"\/products\/ignite-ui-angular\/download\">Try Ignite UI for Angular<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"what-are-angular-schematics\"><strong>What are Angular Schematics?<\/strong><\/h2>\n\n\n\n<p><span class=\"EOP SCXW6502503 BCX0\"><span class=\"TextRun  BCX0 SCXW50738636\" lang=\"EN-US\"><span class=\"NormalTextRun  BCX0 SCXW50738636\">Schematics&nbsp;<\/span><span class=\"NormalTextRun ContextualSpellingAndGrammarErrorV2  BCX0 SCXW50738636\">are<\/span><span class=\"NormalTextRun  BCX0 SCXW50738636\">&nbsp;the building block of&nbsp;<\/span><\/span><span class=\"TextRun  BCX0 SCXW50738636\" lang=\"EN-US\"><span class=\"NormalTextRun  BCX0 SCXW50738636\">the&nbsp;<\/span><\/span><span class=\"TextRun  BCX0 SCXW50738636\" lang=\"EN-US\"><span class=\"NormalTextRun  BCX0 SCXW50738636\">Angular CLI. They\u2019re executable sets of instructions that perform manipulations on existing files or generate files\/content.<\/span><\/span><span class=\"TextRun  BCX0 SCXW50738636\" lang=\"EN-US\"><span class=\"NormalTextRun  BCX0 SCXW50738636\">&nbsp;If you\u2019re an Angular dev, you\u2019ve most probably used created a component by running:<\/span><\/span><span class=\"EOP  BCX0 SCXW50738636\">&nbsp;<\/span><\/span><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">ng g c [component name] <\/pre>\n\n\n\n<p>Schematics are a huge part of the Angular ecosystem and understanding them better can&nbsp;greatly improve both&nbsp;your&nbsp;and your&nbsp;users\u2019&nbsp;lives.&nbsp;<\/p>\n\n\n\n<p>We\u2019ll go over a quick angular schematic tutorial so you can get familiar with the basics before we take a deeper plunge.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"authoring-angular-schematics\"><strong>Authoring Angular Schematics<\/strong><\/h2>\n\n\n\n<p>You can quickly start authoring your own schematics by taking advantage of&nbsp;Angular\u2019s&nbsp;own <a title=\"@angular-devkit\/schematics-cli\" href=\"https:\/\/www.npmjs.com\/package\/@angular-devkit\/schematics-cli\" target=\"_blank\" rel=\"noopener noreferrer\">schematic cli<\/a>.&nbsp;&nbsp;<\/p>\n\n\n\n<p>Just run the following to install it globally:&nbsp;<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">npm install -g @angular-devkit\/schematics-cli<\/pre>\n\n\n\n<p><span class=\"TextRun  BCX0 SCXW213775211\" lang=\"EN-US\"><span class=\"NormalTextRun  BCX0 SCXW213775211\">And then create a ready-to-use blank example schematic by calling:<\/span><\/span><span class=\"EOP  BCX0 SCXW213775211\">&nbsp;<\/span><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">schematics blank --name=intro-schematic<\/pre>\n\n\n\n<p>If you go over the files generated, you can go through them to find out how exactly schematics are exposed to the used.&nbsp;<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>&nbsp;In the&nbsp;package.json&nbsp;file, you can see there\u2019s a \u201cschematics\u201d property,&nbsp;pointiong&nbsp;to a \u201ccollection.json\u201d&nbsp;<\/li>\n\n\n\n<li>&nbsp;Following that path, you can inspect that file &#8211; it\u2019s a&nbsp;pretty standard&nbsp;.json file, with one key thing &#8211; a \u201cschematics\u201d property, which is a list of all the schematics that are exposed to users.&nbsp;&nbsp;<br>Right after running the example command from above, the list should only have one entry &#8211; \u201cIntro schematics\u201d. The entry contains a short description and a ref to a \u201cfactory\u201d &#8211; this is where the schematic\u2019s body is defined.&nbsp;<\/li>\n\n\n\n<li>&nbsp;In the referred `index.ts` file, the schematics \u201cbody\u201d is defined &#8211; a `Rule` that will be executed in the consuming project\u2019s context and where&nbsp;all of&nbsp;your custom logic will&nbsp;reside&nbsp;<\/li>\n<\/ol>\n\n\n\n<p>You can now call&nbsp;you&nbsp;example from outside the project by&nbsp;calling:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">ng g [path-to-collection.json]:intro-schematics<\/pre>\n\n\n\n<p><span class=\"TextRun  BCX0 SCXW48890096\" lang=\"EN-US\"><span class=\"NormalTextRun  BCX0 SCXW48890096\">But that\u2019s not the only way to call schematics. Angular have exposed c<\/span><\/span><span class=\"TextRun  BCX0 SCXW48890096\" lang=\"EN-US\"><span class=\"NormalTextRun  BCX0 SCXW48890096\">onvenient \u201chooks\u201d for developers that can further automate the experience for your users.<\/span><\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"angular-schematic-entry-points\"><strong>Angular Schematic entry points<\/strong><\/h2>\n\n\n\n<p>Aside from calling an Angular schematic with the usual&nbsp;<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">ng g my-custom-library:schematics [args]<\/pre>\n\n\n\n<p>Angular\u2019s CLI also provides two other entry points for your custom library workflows &#8211; ng add and ng update. If you are not familiar with these ng commands, you can learn more about them <a href=\"https:\/\/angular.io\/cli\/add\" rel=\"noopener\">here<\/a> and <a href=\"https:\/\/angular.io\/cli\/update\" rel=\"noopener\">here<\/a>. In an Angular application that&#8217;s using your library, these function similarly to npm&#8217;s postinstall hook. They are called automatically by the Angular CLI &#8211; when calling<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">ng add my-custom-library<\/pre>\n\n\n\n<p>Or<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">ng update my-custom-library<\/pre>\n\n\n\n<p>respectively.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"migration-schematics\"><strong>Migration Schematics<\/strong><\/h2>\n\n\n\n<p>One of the main benefits in using Angular\u2019s CLI is updating your package dependencies while minimizing the need to manually workaround breaking changes or deprecations. All of this can be automated by defining migration schematics for your library!<\/p>\n\n\n\n<p>A migration schematic is run each time a newer version of your library is added to the consuming application via ng update your-custom-library. In a migration schematic, you can not only define what changes your migration schematics should perform, but also specify the scope of the migration (which version it affects).<\/p>\n\n\n\n<p><strong>Adding migration schematics<\/strong><\/p>\n\n\n\n<p>Defining migration schematics is done in a similar way to defining a normal schematic \u200a\u2014\u200a you have to create a function that returns a Rule. That rule can manipulate the work tree, log stuff and\/or anything else that you can do with Javascript. The more specific part is making sure that the Angular CLI calls the schematic on the ng update hook.<\/p>\n\n\n\n<p><strong>Defining the schematics collection<\/strong><\/p>\n\n\n\n<p>First, you need to define a schematic collection.json file. The name doesn&#8217;t matter. In our library\u2019s case, we&#8217;ve named it <a href=\"https:\/\/github.com\/IgniteUI\/igniteui-angular\/blob\/master\/projects\/igniteui-angular\/migrations\/migration-collection.json\" rel=\"noopener\">migration-collection.json<\/a>, as we have multiple schematic collections and this makes it easier to tell which is which.<\/p>\n\n\n\n<p>The structure of your collection.json should look something like this:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">{\n    \"schematics\": {\n        \"migration-01\": {\n            \/\/  Migration name, no strict naming, must be unique\n            \"version\": \"2.0.0\", \/\/ The target version\n                \"description\": \"Updates my-custom-library from v1 to v2\", \/\/ A short description, not mandatory\n                \"factory\": \".\/update-2\" \/\/ The update schematic factory\n        }\n\n        ,\n        \"migration-02\": {\n            \"version\": \"3.0.0\",\n                \"description\": \"Updates my-custom-library from v2 to v3\",\n                \"factory\": \".\/update-3\"\n        }\n\n        ,\n\n        ...\n    }\n}<\/pre>\n\n\n\n<p>The schematics object houses all of your update schematics definitions. Each definition is under a named property (which has to be unique) and for each one, you have to specify the version in which the &#8220;changes&#8221; are introduced and the factory for the schematic that will be run on the working tree. The version attribute is used to determine when you schematic needs to be run.<\/p>\n\n\n\n<p>For example, let&#8217;s say you have an app consuming my-custom-library@1.0.0. With the above schematics definition, if you would run ng update my-custom-library@2.0.0, only the defined &#8220;version&#8221;: &#8220;6.0.0&#8221;schematic would be run. When running<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">ng update my-custom-library@3.0.0<\/pre>\n\n\n\n<p>both 2.0.0 and 3.0.0 migration schematics would be run.<\/p>\n\n\n\n<p>The actual definition of the migration schematics (for v2.0.0, for example) is in .\/update-2\/index.ts can be like any other schematic. A very basic implementation would be this one:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">export default function(): Rule {\n  return (host: Tree, context: SchematicContext) => {\n    const version = `1.0.0` \/\/ You can get this dynamically from the package.json\n    context.logger.info(`Applying migration for custom library to version ${version}`);\n\n    return host;\n  };\n}<\/pre>\n\n\n\n<p>You can find the definition for one of the latest migration schematics in igniteui-angular <a href=\"https:\/\/github.com\/IgniteUI\/igniteui-angular\/blob\/master\/projects\/igniteui-angular\/migrations\/update-9_0_0\/index.ts\" rel=\"noopener\">here<\/a>.<\/p>\n\n\n\n<p><strong><em>Disclaimer<\/em><\/strong><em>: In our library\u2019s schematic implementation we are making <\/em><a href=\"https:\/\/github.com\/IgniteUI\/igniteui-angular\/blob\/master\/projects\/igniteui-angular\/migrations\/common\/UpdateChanges.ts\" rel=\"noopener\"><em>heavy use<\/em><\/a><em> of the TypeScript language service for manipulating files. I\u2019m sorry for not going into details, but that would warrant a post of its own. If you have any questions, feel free to reach out in the comments and I\u2019ll try to answer as best as I can.<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"attaching-schematics-collection-to-ng-update-hook\"><strong>Attaching schematics collection to ng-update hook<\/strong><\/h2>\n\n\n\n<p>Once the migration collection.json is created and the migration schematics are defined, all that&#8217;s left is to properly attach them to the ng-update hook. All you need to do for that is to go over to your library&#8217;s package.json and add the following \u201cng-update\u201d property:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">{\n    \"name\": \"my-custom-library\",\n    \"version\": \"2.0.0\",\n    ... \"ng-update\": {\n        \"migrations\": \".\/migrations\/migration-collection.json\"\n    }\n}<\/pre>\n\n\n\n<p>&nbsp;<\/p>\n\n\n\n<p>That\u2019s it! Now every time someone runs ng update my-custom-library, the Angular CLI and the schematics that you\u2019ve carefully crafted will take care of any pesky breaking changes or deprecations that a user might otherwise miss!<\/p>\n\n\n\n<p><strong>ng-add<\/strong><\/p>\n\n\n\n<p>The other helpful entry point that the Angular CLI provides is the ng add hook. When you define an ng add schematic, it is run automatically as soon as a user adds your library to their consuming project by running<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">ng add [custom-library]<\/pre>\n\n\n\n<p>You can think of it as something akin to npm&#8217;s postinstall hook.<\/p>\n\n\n\n<p>Defining an ng add schematic for your library is the best way to make sure that its users will have an easy first-time experience with it. Through the schematics, you can automate some mandatory initial setup, add\/update packages or simply log a big &#8220;thank you!&#8221; to all your users! \ud83d\ude42<\/p>\n\n\n\n<p>In our library, we&#8217;ve added an ng add schematic that installs our <a href=\"https:\/\/github.com\/IgniteUI\/igniteui-cli\" rel=\"noopener\">IgniteUI CLI<\/a> to the project workspace so users can take full advantage of our components suite via our CLI.<br>We make some initial transformations to the workspace (adding a custom .json file needed for our CLI to run), add some styles and packages (for our components to properly render) and even call some schematics (schematiception!) from our CLI, where we&#8217;ve offloaded some of the Angular CLI specific logic.<\/p>\n\n\n\n<p>All this (and more!) can be done automatically, simply by calling ng add &#8211; that, in my opinion, is the Angular CLI&#8217;s true charm.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"create-ng-add-schematic\"><strong>Create ng-add schematic<\/strong><\/h2>\n\n\n\n<p>To add an ng add schematic to your library, you first need to define it. As with any other schematic, it needs to be part of a collection. If your project already exposes schematics, you can add it to the existing collection under the name ng-add. If not, you can create the collection from scratch:<\/p>\n\n\n\n<p>In your library\u2019s root folder:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">mkdir schematics &amp;&amp; cd schematics\n\necho blank > collection.json\n\nmkdir ng-add<\/pre>\n\n\n\n<p>Open the newly created collection.json, modify it to point to the definition of the ng-add schematic<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">{\n    \"$schema\": \"..\/..\/..\/node_modules\/@angular-devkit\/schematics\/collection-schema.json\",\n    \"schematics\": {\n        \"ng-add\": {\n            \"description\": \"Installs the needed dependencies onto the host application.\",\n                \"factory\": \".\/ng-add\/index\",\n                \"schema\": \".\/ng-add\/schema.json\"\n        }\n    }\n}<\/pre>\n\n\n\n<p>Under schematics\/ng-add\/index.ts you can create the implementation of the ng-add schematic just as you would with any other schematic. For example, to display a simple &#8220;Thank you!&#8221; message to your users, you can do the following:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">export default function (options: Options): Rule {\n\treturn (_tree: Tree, context: SchematicContext) => {\n\t\tcontext.logger.info(`Thank you for using our custom library! You're great!`);\n\t};\n}<\/pre>\n\n\n\n<p>The implementation of IgniteUI Angular&#8217;s ng-add schematic can be found <a href=\"https:\/\/github.com\/IgniteUI\/igniteui-angular\/blob\/master\/projects\/igniteui-angular\/schematics\/ng-add\/index.ts\" rel=\"noopener\">here<\/a>.<\/p>\n\n\n\n<p><strong>Include in package.json<\/strong><\/p>\n\n\n\n<p>Once you\u2019re done with the implementation of the schematic, you have to include the collection definition in your library\u2019s package.json. If your library already exposes a schematics collection, you&#8217;ve got this covered! If not, you just need to add a &#8220;schematics&#8221; property, pointing to the location of your newly created collection.json:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">{\n    \"project\": \"my-custom-library\",\n    \"version\": \"2.0.0\",\n    ... \"schematics\": \".\/schematics\/collection.json\"\n}<\/pre>\n\n\n\n<p>You can find this part of the setup reflected on our library repo.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"bundling-your-schematics\"><strong>Bundling your schematics<\/strong><\/h2>\n\n\n\n<p>You have to make sure that the schematics you&#8217;ve defined (both migrations and ng-add collections) are properly shipped with your library package. To do this, you will need to define a separate build task for your schematics (executed after the main build task has run), with outDir specified to point to the proper location in your project&#8217;s dist folder (so the collection.json files have the same paths, relative to the package.json). Finally, you will need to explicitly copy any files that are excluded by the compiler (for example, any .json files!).<\/p>\n\n\n\n<p>Assuming that the output directory for your compiled projects is ..\/dist (so your project\u2019s bundled files would be under ..\/dist\/my-custom-lib\/) your schematic\u2019s compilation output will have to be ..\/dist\/schematics (for the default schematic collection, containing ng-add) and ..\/dist\/migrations (for the migration schematic collection)<\/p>\n\n\n\n<p>To do this, you must first define a tsconfig.json file for your schematics collections (located in .\/schematics\/ or .\/migrations, respectively). For example, the content of the file for the core schematics collection (.\/schematics) would be something like this:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">{\n   \"compilerOptions\": {\n\t\"target\": \"es6\",\n\t\"module\": \"commonjs\",\n\t\"sourceMap\": false,\n\t\"composite\": true,\n\t\"declaration\": true,\n\t\"outDir\": \"..\/..\/..\/dist\/my-custom-lib\/schematics\/\"\n   }\n}<\/pre>\n\n\n\n<p>Then, in your project\u2019s package.json, define a script that builds your schematics and another one that copies the files:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">{\n   \"name\": \"my-custom-library\",\n   ...\n   \"scripts\": {\n      \"build:schematics\": \"tsc --project migrations\/tsconfig.json\",\n      \"copy:schematics:collection\": \"cp --parents migrations\/*\/collection.json ..\/..\/dist\/my-custom-lib\/\"\n   },\n   ...\n}<\/pre>\n\n\n\n<p>The same goes for the migrations &#8211; a separate script for TypeScript compile and for copying the files.&nbsp;<\/p>\n\n\n\n<p>For the Ignite UI for Angular repo, you can check the links to see the implementation of the <a href=\"https:\/\/github.com\/IgniteUI\/igniteui-angular\/blob\/master\/package.json#L27\" rel=\"noopener\">default schematics<\/a> collection and the <a href=\"https:\/\/github.com\/IgniteUI\/igniteui-angular\/blob\/master\/package.json#L26\" rel=\"noopener\">migrations<\/a>. (Since we\u2019re using gulp as a build tool, we\u2019ve defined <a href=\"https:\/\/github.com\/IgniteUI\/igniteui-angular\/blob\/master\/gulpfile.js#L128\" rel=\"noopener\">separate tasks<\/a> there for copying the collection.json files)<\/p>\n\n\n\n<p><strong>Running ng-add and ng-update schematics locally<\/strong><\/p>\n\n\n\n<p>Before you publish your library package with your new and shiny ng update and ng add functionality, you might want to verify that the schematics are performing the proper workplace transformations. Since, in the end, both of these are just basic schematic implementations, you can run them as you would any other &#8211; by using ng g!<\/p>\n\n\n\n<p>After building your library files and schematics + migrations, you can go into your specified output directory (where your bundle\u2019s package.json is located) and pack it<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">npm pack<\/pre>\n\n\n\n<p><strong>Running ng-add<\/strong><\/p>\n\n\n\n<p>To check how your ng-add is command is performing inside of a new project, you can do the following:<\/p>\n\n\n\n<p>Create a new project using the Angular CLI<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">ng g my-test-project --routing=true<\/pre>\n\n\n\n<p>Once the project is created, you can go into the project folder and install your package manually from the .tgz file:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">npm i my-custom-library.tgz<\/pre>\n\n\n\n<p>Then, simply run<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">ng g my-custom-library:ng-add<\/pre>\n\n\n\n<p>and review the workplace change once it&#8217;s finished &#8211; that&#8217;s what your package&#8217;s ng-add will do!<\/p>\n\n\n\n<p><strong>Running migrations<\/strong><\/p>\n\n\n\n<p>For testing migrations, you can follow the same steps as the above, though you\u2019ll have to specify the path to the migration schematics collection.json (as it&#8217;s different from the default schematics collection of the project).<\/p>\n\n\n\n<p>Let\u2019s say your latest migration schematic which you want to test is named update-1. Once you&#8217;ve manually installed your .tgz file, simply run:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">ng g \".\/node_modules\/my-custom-library\/migration-collection.json:update-1\"<\/pre>\n\n\n\n<p>This will apply all of the workplace changes that your latest migration schematic would apply.<\/p>\n\n\n\n<p><strong>Closing thoughts<\/strong><\/p>\n\n\n\n<p>Hopefully, this post has been helpful to you and has cleared up some things about Angular CLI\u2019s ng add and ng update functionality. Angular&#8217;s schematics are now a solid part of their projects&#8217; ecosystem and will surely continue improving. With <a href=\"https:\/\/www.youtube.com\/watch?v=_LPzY9GrNwY\" rel=\"noopener\">more<\/a> and <a href=\"https:\/\/www.youtube.com\/watch?v=YyhLdDCend4\" rel=\"noopener\">more<\/a> developers using them and raising awareness of them, now is a great time for libraries to start adopting schematics. Why not automate both you and your users worries away? \ud83d\ude42<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"\/products\/ignite-ui-angular\/download\"><img decoding=\"async\" src=\"https:\/\/static.infragistics.com\/marketing\/Blog-in-content-ads\/Ignite-UI-Angular\/ignite-ui-angular-you-get-ad.gif\" alt=\"Ignite UI for Angular\"\/><\/a><\/figure>\n\n\n\n<p>If you have any questions, feel free to reach out in the comments.<\/p>\n\n\n\n<p>Thanks for reading!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>What are angular schematics and what are their benefits? Learn how to improve your library with Angular schematics by taking full advantage of ng add and ng update.<\/p>\n","protected":false},"author":101,"featured_media":1424,"comment_status":"publish","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[],"class_list":["post-377","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-angular"],"_links":{"self":[{"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/posts\/377","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/users\/101"}],"replies":[{"embeddable":true,"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/comments?post=377"}],"version-history":[{"count":3,"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/posts\/377\/revisions"}],"predecessor-version":[{"id":1987,"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/posts\/377\/revisions\/1987"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/media\/1424"}],"wp:attachment":[{"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/media?parent=377"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/categories?post=377"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/tags?post=377"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}