{"id":2387,"date":"2017-12-01T08:21:04","date_gmt":"2017-12-01T07:21:04","guid":{"rendered":"https:\/\/www.angulararchitects.io\/?p=2387"},"modified":"2017-12-01T08:21:04","modified_gmt":"2017-12-01T07:21:04","slug":"automatically-updating-angular-modules-with-schematics-and-the-cli","status":"publish","type":"post","link":"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/","title":{"rendered":"Automatically Updating Angular Modules With Schematics And The CLI"},"content":{"rendered":"<div class=\"article\">\n<hr>\n<p><b>Table of Contents<\/b><\/p>\n<p>This blog post is part of an article series.<\/p>\n<ul>\n<li><a href=\"https:\/\/www.angulararchitects.io\/post\/2017\/10\/29\/generating-custom-code-with-the-angular-cli-and-schematics.aspx\" rel=\"nofollow\">Part I: Generating Custom Code With The Angular CLI And Schematics<\/a><\/li>\n<li><a href=\"https:\/\/www.angulararchitects.io\/post\/2017\/12\/01\/generating-angular-code-with-schematics-part-ii-modifying-ngmodules.aspx\" rel=\"nofollow\">Part II: Automatically Updating Angular Modules With Schematics And The CLI<\/a><\/li>\n<li><a href=\"https:\/\/www.angulararchitects.io\/post\/2018\/01\/02\/angular-cli-and-schematics-part-iii-typescripts-compiler-api.aspx\" rel=\"nofollow\">Part III: Extending Existing Code With The TypeScript Compiler API<\/a><\/li>\n<li><a href=\"https:\/\/www.angulararchitects.io\/post\/2018\/03\/20\/custom-schematics-part-iv-frictionless-library-setup-with-the-angular-cli-and-schematics.aspx\" target=\"_blank\" rel=\"noopener\">Part IV:&nbsp;Frictionless Library Setup with the Angular CLI and Schematics<\/a><\/li>\n<li><a href=\"https:\/\/www.angulararchitects.io\/post\/2018\/04\/17\/seamlessly-updating-your-angular-libraries-with-ng-update.aspx\">Part V: Seamlessly Updating your Angular Libraries with ng update<\/a><\/li>\n<\/ul>\n<hr>\n<p><b>Update, 2018-05-09: <\/b>Updated for newest CLI version<\/p>\n<blockquote><p>\nThanks to <a href=\"https:\/\/twitter.com\/hanslatwork\">Hans Larsen<\/a> from the Angular CLI Team for providing valuable feedback\n<\/p><\/blockquote>\n<p>In my last blog article, I've shown <a href=\"https:\/\/www.angulararchitects.io\/post\/2017\/10\/29\/generating-custom-code-with-the-angular-cli-and-schematics.aspx\">how to leverage Schematics, the Angular CLI's code generator, to scaffold custom components<\/a>. This article goes one step further and shows how to register generated building blocks like Components, Directives, Pipes, or Services with an existing <code>NgModule<\/code>. For this I'll extend the example from the last article that generates a <code>SideMenuComponent<\/code>. The <a href=\"https:\/\/github.com\/manfredsteyer\/schematics-sample\">source code shown here<\/a> can also be found in my <a href=\"https:\/\/github.com\/manfredsteyer\/schematics-sample\">GitHub repository<\/a>.<\/p>\n<blockquote><p>\nSchematics is currently experimental and can change in future.<br \/>\n<img decoding=\"async\" width=\"300\" src=\"https:\/\/i.imgur.com\/y8LIiVg.png\" alt=\"Angular Labs\">\n<\/p><\/blockquote>\n<h2 id=\"goal\">Goal<\/h2>\n<p>To register the generated <code>SideMenuComponent<\/code> we need to perform several tasks. For instance, we have to lookup the file with respective <code>NgModule<\/code>. After this, we have to insert several lines into this file:<\/p>\n<pre class=\"hljs\"><code><div><span class=\"hljs-keyword\">import<\/span> { NgModule } from <span class=\"hljs-string\">'@angular\/core'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { CommonModule } from <span class=\"hljs-string\">'@angular\/common'<\/span>;\n\n<span class=\"hljs-comment\">\/\/ Add this line to reference component<\/span>\n<span class=\"hljs-keyword\">import<\/span> { SideMenuComponent } from <span class=\"hljs-string\">'.\/side-menu\/side-menu.component'<\/span>;\n\n@NgModule({\n  imports: [\n    CommonModule\n  ],\n\n  <span class=\"hljs-comment\">\/\/ Add this Line<\/span>\n  declarations: [SideMenuComponent],\n\n  <span class=\"hljs-comment\">\/\/ Add this Line if we want to export the component too<\/span>\n  exports: [SideMenuComponent]\n})\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">class<\/span> CoreModule { }\n<\/div><\/code><\/pre>\n<p>As you've seen in the last listing, we have to create an <code>import<\/code> statement at the beginning of the file. And then we have to add the imported component to the <code>declarations<\/code> array and - if the caller requests it - to the <code>exports<\/code> array too. If those arrays don't exist, we have to create them too.<\/p>\n<p>The good message is, that the Angular CLI contains existing code for such tasks. Hence, we don't have to build everything from scratch. The next section shows some of those existing utility functions.<\/p>\n<h2 id=\"utility-functions-provided-by-the-angular-cli\">Utility Functions provided by the Angular CLI<\/h2>\n<p>The Schematics Collection <code>@schematics\/angular<\/code> used by the Angular CLI for generating stuff like components or services turns out to be a real gold mine for modifying existing <code>NgModules<\/code>. For instance, you find some function to look up modules within <code>@schematics\/angular\/utility\/find-module<\/code>. The following table shows two of them which I will use in the course of this article:<\/p>\n<table>\n<thead>\n<tr>\n<th>Function<\/th>\n<th>Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>findModuleFromOptions<\/td>\n<td>Looks up the current module file. For this, it starts in a given folder and looks for a file with the suffix <code>.module.ts<\/code> while the suffix <code>.routing.module.ts<\/code> is not accepted. If nothing has been found in the current folder, its parent folders are searched.<\/td>\n<\/tr>\n<tr>\n<td>buildRelativePath<\/td>\n<td>Builds a relative path that points from one file to another one. This function comes in handy for generating the <code>import<\/code> statement pointing from the module file to the file with the component to register.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Another file containing useful utility functions is <code>@schematics\/angular\/utility\/ast-utils<\/code>. It helps with modifying existing <code>TypeScript<\/code> files by leveraging services provided by the TypeScript compiler. The next table shows some of its functions used here:<\/p>\n<table>\n<thead>\n<tr>\n<th>Function<\/th>\n<th>Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>addDeclarationToModule<\/td>\n<td>Adds a component, directive or pipe to the <code>declarations<\/code> array of an <code>NgModule<\/code>. If necessary, this array is created<\/td>\n<\/tr>\n<tr>\n<td>addExportToModule<\/td>\n<td>Adds an export to the <code>NgModule<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>There are also other methods that add entries to the other sections of an <code>NgModule<\/code> (<code>addImportToModule<\/code>, <code>addProviderToModule<\/code>, <code>addBootstrapToModule<\/code>).<\/p>\n<p>Please note, that those files are currently not part of the package's public API. Therefore, they can change in future. To be on the safe side, <a href=\"https:\/\/twitter.com\/hanslatwork\">Hans Larsen<\/a> from the Angular CLI Team suggested to fork it. <a href=\"https:\/\/github.com\/manfredsteyer\/devkit\">My fork<\/a> of the <a href=\"https:\/\/github.com\/angular\/devkit\">DevKit Repository<\/a> containing those functions can be found <a href=\"https:\/\/github.com\/manfredsteyer\/devkit\">here<\/a>.<\/p>\n<p>After forking, I've copied the contents of the folder <code>packages\\schematics\\angular\\utility<\/code> containing the functions in question to the folder <a href=\"https:\/\/github.com\/manfredsteyer\/custom-schematics-modifying-ngmodules\/tree\/master\/nav\/src\/schematics-angular-utils\"><code>schematics-angular-utils<\/code> in my project<\/a> and adjusted some <code>import<\/code> statements. For the time being, you can also copy <a href=\"https:\/\/github.com\/manfredsteyer\/custom-schematics-modifying-ngmodules\/tree\/master\/nav\/src\/schematics-angular-utils\">my folder with this adjustments<\/a> for your own projects. I think that sooner or later the API will stabilize and be published as a public one so that we don't need this workaround.<\/p>\n<h2 id=\"creating-a-rule-for-adding-a-declaration-to-an-ngmodule\">Creating a Rule for adding a declaration to an NgModule<\/h2>\n<p>After we've seen that there are handy utility functions, let's use them to build a <code>Rule<\/code> for our endeavor.  For this, we use a folder <code>utils<\/code> with the following two files:<\/p>\n<p><img decoding=\"async\" width=\"300\" src=\"https:\/\/i.imgur.com\/aFaE7ZU.png\" alt=\"Utils for custom Rule\"><\/p>\n<p>The file <code>add-to-module-context.ts<\/code> gets a context class holding data for the planned modifications:<\/p>\n<pre class=\"hljs\"><code><div><span class=\"hljs-keyword\">import<\/span> * as ts from <span class=\"hljs-string\">'typescript'<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">class<\/span> AddToModuleContext {\n    <span class=\"hljs-comment\">\/\/ source of the module file<\/span>\n    source: ts.SourceFile;\n\n    <span class=\"hljs-comment\">\/\/ the relative path that points from  <\/span>\n    <span class=\"hljs-comment\">\/\/ the module file to the component file<\/span>\n    relativePath: <span class=\"hljs-built_in\">string<\/span>;\n\n    <span class=\"hljs-comment\">\/\/ name of the component class<\/span>\n    classifiedName: <span class=\"hljs-built_in\">string<\/span>;\n}\n<\/div><\/code><\/pre>\n<p>In the other file, <code>ng-module-utils.ts<\/code>, a factory function for the needed rule is created:<\/p>\n<pre class=\"hljs\"><code><div><span class=\"hljs-keyword\">import<\/span> { Rule, Tree, SchematicsException } from <span class=\"hljs-string\">'@angular-devkit\/schematics'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { AddToModuleContext } from <span class=\"hljs-string\">'.\/add-to-module-context'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> * as ts from <span class=\"hljs-string\">'typescript'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { dasherize, classify } from <span class=\"hljs-string\">'@angular-devkit\/core'<\/span>;\n\n<span class=\"hljs-keyword\">import<\/span> { ModuleOptions, buildRelativePath } from <span class=\"hljs-string\">'..\/schematics-angular-utils\/find-module'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { addDeclarationToModule, addExportToModule } from <span class=\"hljs-string\">'..\/schematics-angular-utils\/ast-utils'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { InsertChange } from <span class=\"hljs-string\">'..\/schematics-angular-utils\/change'<\/span>;\n\n<span class=\"hljs-keyword\">const<\/span> stringUtils = { dasherize, classify };\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">addDeclarationToNgModule<\/span>(<span class=\"hljs-params\">options: ModuleOptions, exports: <span class=\"hljs-built_in\">boolean<\/span><\/span>): <span class=\"hljs-title\">Rule<\/span> <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> (host: Tree) =&gt; {\n   [...]\n  };\n}\n<\/div><\/code><\/pre>\n<p>This function takes an <code>ModuleOptions<\/code> instance that describes the <code>NgModule<\/code> in question. It can be deduced by the options object containing the command line arguments the caller passes to the CLI.<\/p>\n<p>It also takes a flag <code>exports<\/code> that indicates whether the declared component should be exported too. The returned <code>Rule<\/code> is just a function that gets a <code>Tree<\/code> object representing the part of the file system it modifies. For implementing this <code>Rule<\/code> I've looked up the implementation of similar rules within the CLI's Schematics in <code>@schematics\/angular<\/code> and \"borrowed\" the patterns found there. Especially the <code>Rule<\/code> triggered by <code>ng generated component<\/code> was very helpful for this.<\/p>\n<p>Before we discuss how this function is implemented, let's have a look at some helper functions I've put in the same file. The first one collects the <code>context<\/code> information we've talked about before:<\/p>\n<pre class=\"hljs\"><code><div><span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">createAddToModuleContext<\/span>(<span class=\"hljs-params\">host: Tree, options: ModuleOptions<\/span>): <span class=\"hljs-title\">AddToModuleContext<\/span> <\/span>{\n\n  <span class=\"hljs-keyword\">const<\/span> result = <span class=\"hljs-keyword\">new<\/span> AddToModuleContext();\n\n  <span class=\"hljs-keyword\">if<\/span> (!options.module) {\n    <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> SchematicsException(<span class=\"hljs-string\"><code>Module not found.<\/code><\/span>);\n  }\n\n  <span class=\"hljs-comment\">\/\/ Reading the module file<\/span>\n  <span class=\"hljs-keyword\">const<\/span> text = host.read(options.module);\n\n  <span class=\"hljs-keyword\">if<\/span> (text === <span class=\"hljs-literal\">null<\/span>) {\n    <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> SchematicsException(<span class=\"hljs-string\"><code>File &lt;span class=&quot;hljs-subst&quot;&gt;${options.module}&lt;\/span&gt; does not exist.<\/code><\/span>);\n  }\n\n  <span class=\"hljs-keyword\">const<\/span> sourceText = text.toString(<span class=\"hljs-string\">'utf-8'<\/span>);\n  result.source = ts.createSourceFile(options.module, sourceText, ts.ScriptTarget.Latest, <span class=\"hljs-literal\">true<\/span>);\n\n  <span class=\"hljs-keyword\">const<\/span> componentPath = <span class=\"hljs-string\"><code>\/&lt;span class=&quot;hljs-subst&quot;&gt;${options.sourceDir}&lt;\/span&gt;\/&lt;span class=&quot;hljs-subst&quot;&gt;${options.path}&lt;\/span&gt;\/<\/code><\/span>\n              + stringUtils.dasherize(options.name) + <span class=\"hljs-string\">'\/'<\/span>\n              + stringUtils.dasherize(options.name)\n              + <span class=\"hljs-string\">'.component'<\/span>;\n\n  result.relativePath = buildRelativePath(options.module, componentPath);\n\n  result.classifiedName = stringUtils.classify(<span class=\"hljs-string\"><code>&lt;span class=&quot;hljs-subst&quot;&gt;${options.name}&lt;\/span&gt;Component<\/code><\/span>);\n\n  <span class=\"hljs-keyword\">return<\/span> result;\n\n}\n<\/div><\/code><\/pre>\n<p>The second helper function is <code>addDeclaration<\/code>. It delegates to <code>addDeclarationToModule<\/code> located within the package <code>@schematics\/angular<\/code> to add the component to the module's <code>declarations<\/code> array:<\/p>\n<pre class=\"hljs\"><code><div><span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">addDeclaration<\/span>(<span class=\"hljs-params\">host: Tree, options: ModuleOptions<\/span>) <\/span>{\n\n  <span class=\"hljs-keyword\">const<\/span> context = createAddToModuleContext(host, options);\n  <span class=\"hljs-keyword\">const<\/span> modulePath = options.module || <span class=\"hljs-string\">''<\/span>;\n\n  <span class=\"hljs-keyword\">const<\/span> declarationChanges = addDeclarationToModule(\n                  context.source,\n                  modulePath,\n                  context.classifiedName,\n                  context.relativePath);\n\n  <span class=\"hljs-keyword\">const<\/span> declarationRecorder = host.beginUpdate(modulePath);\n  <span class=\"hljs-keyword\">for<\/span> (<span class=\"hljs-keyword\">const<\/span> change of declarationChanges) {\n    <span class=\"hljs-keyword\">if<\/span> (change <span class=\"hljs-keyword\">instanceof<\/span> InsertChange) {\n      declarationRecorder.insertLeft(change.pos, change.toAdd);\n    }\n  }\n  host.commitUpdate(declarationRecorder);\n};\n<\/div><\/code><\/pre>\n<p>The <code>addDeclarationToModule<\/code> function takes the retrieved context information and the <code>modulePath<\/code> from the passed <code>ModuleOptions<\/code>. Instead of directly updating the module file it returns an array with necessary modifications. These are iterated and applied to the module file within a transaction, started with <code>beginUpdate<\/code> and completed with <code>commitUpdate<\/code>.<\/p>\n<p>The second helper function is <code>addExport<\/code>. It adds the component to the module's <code>exports<\/code> array and works exactly like the <code>addDeclaration<\/code>:<\/p>\n<pre class=\"hljs\"><code><div><span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">addExport<\/span>(<span class=\"hljs-params\">host: Tree, options: ModuleOptions<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> context = createAddToModuleContext(host, options);\n  <span class=\"hljs-keyword\">const<\/span> modulePath = options.module || <span class=\"hljs-string\">''<\/span>;\n\n  <span class=\"hljs-keyword\">const<\/span> exportChanges = addExportToModule(\n                context.source,\n                modulePath,\n                context.classifiedName,\n                context.relativePath);\n\n  <span class=\"hljs-keyword\">const<\/span> exportRecorder = host.beginUpdate(modulePath);\n\n  <span class=\"hljs-keyword\">for<\/span> (<span class=\"hljs-keyword\">const<\/span> change of exportChanges) {\n    <span class=\"hljs-keyword\">if<\/span> (change <span class=\"hljs-keyword\">instanceof<\/span> InsertChange) {\n      exportRecorder.insertLeft(change.pos, change.toAdd);\n    }\n  }\n  host.commitUpdate(exportRecorder);\n};\n<\/div><\/code><\/pre>\n<p>Now, as we've looked at these helper function, let's finish the implementation of our <code>Rule<\/code>:<\/p>\n<pre class=\"hljs\"><code><div><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">addDeclarationToNgModule<\/span>(<span class=\"hljs-params\">options: ModuleOptions, exports: <span class=\"hljs-built_in\">boolean<\/span><\/span>): <span class=\"hljs-title\">Rule<\/span> <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> (host: Tree) =&gt; {\n    addDeclaration(host, options);\n    <span class=\"hljs-keyword\">if<\/span> (exports) {\n      addExport(host, options);\n    }\n    <span class=\"hljs-keyword\">return<\/span> host;\n  };\n}\n<\/div><\/code><\/pre>\n<p>As you've seen, it just delegates to <code>addDeclaration<\/code> and <code>addExport<\/code>. After this, it returns the modified file tree represented by the variable <code>host<\/code>.<\/p>\n<h2 id=\"extending-the-used-options-class-and-its-json-schema\">Extending the used Options Class and its JSON schema<\/h2>\n<p>Before we put our new <code>Rule<\/code> in place, we have to extend the class <code>MenuOptions<\/code> which describes the passed (command line) arguments. As usual in Schematics, it's defined in the file <code>schema.ts<\/code>. For our purpose, it gets two new properties:<\/p>\n<pre class=\"hljs\"><code><div><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">interface<\/span> MenuOptions {\n  name?: <span class=\"hljs-built_in\">string<\/span>;\n  project?: <span class=\"hljs-built_in\">string<\/span>;\n  path?: <span class=\"hljs-built_in\">string<\/span>;\n  <span class=\"hljs-keyword\">module<\/span>?: string;\n\n    \/\/ New Properties:\n  <span class=\"hljs-keyword\">module<\/span>?: string;\n  export?: boolean;\n}\n<\/div><\/code><\/pre>\n<p>The property <code>module<\/code> holds the path for the module file to modify and <code>export<\/code> defines whether the generated component should be exported too.<\/p>\n<p>After this, we have to declare these additional property in the file <code>schema.json<\/code>:<\/p>\n<pre class=\"hljs\"><code><div>{\n    <span class=\"hljs-attr\">\"$schema\"<\/span>: <span class=\"hljs-string\">\"http:\/\/json-schema.org\/schema\"<\/span>,\n    <span class=\"hljs-attr\">\"id\"<\/span>: <span class=\"hljs-string\">\"SchemanticsForMenu\"<\/span>,\n    <span class=\"hljs-attr\">\"title\"<\/span>: <span class=\"hljs-string\">\"Menu Schema\"<\/span>,\n    <span class=\"hljs-attr\">\"type\"<\/span>: <span class=\"hljs-string\">\"object\"<\/span>,\n    <span class=\"hljs-attr\">\"properties\"<\/span>: {\n      [...]\n      <span class=\"hljs-attr\">\"module\"<\/span>:  {\n        <span class=\"hljs-attr\">\"type\"<\/span>: <span class=\"hljs-string\">\"string\"<\/span>,\n        <span class=\"hljs-attr\">\"description\"<\/span>: <span class=\"hljs-string\">\"The declaring module.\"<\/span>,\n        <span class=\"hljs-attr\">\"alias\"<\/span>: <span class=\"hljs-string\">\"m\"<\/span>\n      },\n      <span class=\"hljs-attr\">\"export\"<\/span>: {\n        <span class=\"hljs-attr\">\"type\"<\/span>: <span class=\"hljs-string\">\"boolean\"<\/span>,\n        <span class=\"hljs-attr\">\"default\"<\/span>: <span class=\"hljs-literal\">false<\/span>,\n        <span class=\"hljs-attr\">\"description\"<\/span>: <span class=\"hljs-string\">\"Export component from module?\"<\/span>\n      }\n    }\n  }\n\n<\/div><\/code><\/pre>\n<p>As mentioned in the <a href=\"https:\/\/www.angulararchitects.io\/post\/2017\/10\/29\/generating-custom-code-with-the-angular-cli-and-schematics.aspx\">last blog article<\/a>, we also could generate the file <code>schema.ts<\/code> with the information provided by <code>schema.json<\/code>.<\/p>\n<h2 id=\"calling-the-rule\">Calling the Rule<\/h2>\n<p>Now, as we've created our rule, let's put it in place. For this, we have to call it within the <code>Rule<\/code>  function in <code>index.ts<\/code>:<\/p>\n<pre class=\"hljs\"><code><div><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> (<span class=\"hljs-params\">options: MenuOptions<\/span>): <span class=\"hljs-title\">Rule<\/span> <\/span>{\n\n    <span class=\"hljs-keyword\">return<\/span> (host: Tree, context: SchematicContext) =&gt; {\n\n      options.path = options.path ? normalize(options.path) : options.path;\n\n      <span class=\"hljs-comment\">\/\/ Infer module path, if not passed:<\/span>\n      options.module = options.module || findModuleFromOptions(host, options) || <span class=\"hljs-string\">''<\/span>;\n\n      [...]\n\n      <span class=\"hljs-keyword\">const<\/span> rule = chain([\n        branchAndMerge(chain([\n\n          [...]\n\n          <span class=\"hljs-comment\">\/\/ Call new rule<\/span>\n          addDeclarationToNgModule(options, options.export)\n\n        ])),\n      ]);\n\n      <span class=\"hljs-keyword\">return<\/span> rule(host, context);\n\n    }\n}\n<\/div><\/code><\/pre>\n<p>As the passed <code>MenuOptions<\/code> object is structurally compatible to the needed <code>ModuleOptions<\/code> we can directly pass it to <code>addDeclarationToNgModule<\/code>. This is the way, the CLI currently deals with option objects.<\/p>\n<p>In addition to that, we infer the module path at the beginning using <code>findModuleFromOptions<\/code>.<\/p>\n<h2 id=\"testing-the-extended-schematic\">Testing the extended Schematic<\/h2>\n<p>To try the modified Schematic out, compile it and copy everything to the <code>node_modules<\/code> folder of an example application. As in the <a href=\"https:\/\/www.angulararchitects.io\/post\/2017\/10\/29\/generating-custom-code-with-the-angular-cli-and-schematics.aspx\">former blog article<\/a>, I've decided to copy it to <code>node_modules\/nav<\/code>. Please make sure to exclude the collection's <code>node_modules<\/code> folder, so that there is no folder <code>node_modules\/nav\/node_modules<\/code>.<\/p>\n<p>After this, switch to the example application's root, generate a module <code>core<\/code> and navigate to its folder:<\/p>\n<pre><code>ng g module core\ncd src\\app\\core\n<\/code><\/pre>\n<p>Now call the custom Schematic:<\/p>\n<pre style=\"line-height: 1.42857;\"><code>ng g nav:menu side-menu --menu-service --export<\/code><\/pre>\n<p>This not only generates the <code>SideMenuComponent<\/code> but also registers it with the <code>CoreModule<\/code>:<\/p>\n<pre class=\"hljs\"><code><div><span class=\"hljs-keyword\">import<\/span> { NgModule } from <span class=\"hljs-string\">'@angular\/core'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { CommonModule } from <span class=\"hljs-string\">'@angular\/common'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { SideMenuComponent } from <span class=\"hljs-string\">'.\/side-menu\/side-menu.component'<\/span>;\n\n@NgModule({\n  imports: [\n    CommonModule\n  ],\n  declarations: [SideMenuComponent],\n  exports: [SideMenuComponent]\n})\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">class<\/span> CoreModule { }\n<\/div><\/code><\/pre>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Table of Contents This blog post is part of an article series. Part I: Generating Custom Code With The Angular CLI And Schematics Part II: Automatically Updating Angular Modules With Schematics And The CLI Part III: Extending Existing Code With The TypeScript Compiler API Part IV:&nbsp;Frictionless Library Setup with the Angular CLI and Schematics Part [&hellip;]<\/p>\n","protected":false},"author":9,"featured_media":2997,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_price":"","_stock":"","_tribe_ticket_header":"","_tribe_default_ticket_provider":"","_ticket_start_date":"","_ticket_end_date":"","_tribe_ticket_show_description":"","_tribe_ticket_show_not_going":false,"_tribe_ticket_use_global_stock":"","_tribe_ticket_global_stock_level":"","_global_stock_mode":"","_global_stock_cap":"","_tribe_rsvp_for_event":"","_tribe_ticket_going_count":"","_tribe_ticket_not_going_count":"","_tribe_tickets_list":"[]","_tribe_ticket_has_attendee_info_fields":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-2387","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-unkategorisiert"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.1.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Automatically Updating Angular Modules With Schematics And The CLI - ANGULARarchitects<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Automatically Updating Angular Modules With Schematics And The CLI - ANGULARarchitects\" \/>\n<meta property=\"og:description\" content=\"Table of Contents This blog post is part of an article series. Part I: Generating Custom Code With The Angular CLI And Schematics Part II: Automatically Updating Angular Modules With Schematics And The CLI Part III: Extending Existing Code With The TypeScript Compiler API Part IV:&nbsp;Frictionless Library Setup with the Angular CLI and Schematics Part [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/\" \/>\n<meta property=\"og:site_name\" content=\"ANGULARarchitects\" \/>\n<meta property=\"article:published_time\" content=\"2017-12-01T07:21:04+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/04\/blog-2355684-1280.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1280\" \/>\n\t<meta property=\"og:image:height\" content=\"853\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Manfred Steyer, GDE\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@daniel\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Manfred Steyer, GDE\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/\"},\"author\":{\"name\":\"Manfred Steyer, GDE\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/15628efa7af4475ffaaeeb26c5112951\"},\"headline\":\"Automatically Updating Angular Modules With Schematics And The CLI\",\"datePublished\":\"2017-12-01T07:21:04+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/\"},\"wordCount\":1194,\"publisher\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/04\/blog-2355684-1280.jpg\",\"articleSection\":[\"Unkategorisiert\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/\",\"url\":\"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/\",\"name\":\"Automatically Updating Angular Modules With Schematics And The CLI - ANGULARarchitects\",\"isPartOf\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/04\/blog-2355684-1280.jpg\",\"datePublished\":\"2017-12-01T07:21:04+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/#primaryimage\",\"url\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/04\/blog-2355684-1280.jpg\",\"contentUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/04\/blog-2355684-1280.jpg\",\"width\":1280,\"height\":853},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.angulararchitects.io\/en\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Automatically Updating Angular Modules With Schematics And The CLI\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#website\",\"url\":\"https:\/\/www.angulararchitects.io\/en\/\",\"name\":\"ANGULARarchitects\",\"description\":\"AngularArchitects.io\",\"publisher\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.angulararchitects.io\/en\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#organization\",\"name\":\"ANGULARarchitects\",\"alternateName\":\"SOFTWAREarchitects\",\"url\":\"https:\/\/www.angulararchitects.io\/en\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/07\/AA-Logo-RGB-horizontal-inside-knowledge-black.svg\",\"contentUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/07\/AA-Logo-RGB-horizontal-inside-knowledge-black.svg\",\"width\":644,\"height\":216,\"caption\":\"ANGULARarchitects\"},\"image\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/github.com\/angular-architects\",\"https:\/\/www.linkedin.com\/company\/angular-architects\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/15628efa7af4475ffaaeeb26c5112951\",\"name\":\"Manfred Steyer, GDE\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/a0b59539674d8b71ea1c1f4764b11244b5f499203f1d11b40f37d8f3f90be033?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/a0b59539674d8b71ea1c1f4764b11244b5f499203f1d11b40f37d8f3f90be033?s=96&d=mm&r=g\",\"caption\":\"Manfred Steyer, GDE\"},\"sameAs\":[\"https:\/\/x.com\/daniel\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Automatically Updating Angular Modules With Schematics And The CLI - ANGULARarchitects","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/","og_locale":"en_US","og_type":"article","og_title":"Automatically Updating Angular Modules With Schematics And The CLI - ANGULARarchitects","og_description":"Table of Contents This blog post is part of an article series. Part I: Generating Custom Code With The Angular CLI And Schematics Part II: Automatically Updating Angular Modules With Schematics And The CLI Part III: Extending Existing Code With The TypeScript Compiler API Part IV:&nbsp;Frictionless Library Setup with the Angular CLI and Schematics Part [&hellip;]","og_url":"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/","og_site_name":"ANGULARarchitects","article_published_time":"2017-12-01T07:21:04+00:00","og_image":[{"width":1280,"height":853,"url":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/04\/blog-2355684-1280.jpg","type":"image\/jpeg"}],"author":"Manfred Steyer, GDE","twitter_card":"summary_large_image","twitter_creator":"@daniel","twitter_misc":{"Written by":"Manfred Steyer, GDE","Est. reading time":"9 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/#article","isPartOf":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/"},"author":{"name":"Manfred Steyer, GDE","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/15628efa7af4475ffaaeeb26c5112951"},"headline":"Automatically Updating Angular Modules With Schematics And The CLI","datePublished":"2017-12-01T07:21:04+00:00","mainEntityOfPage":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/"},"wordCount":1194,"publisher":{"@id":"https:\/\/www.angulararchitects.io\/en\/#organization"},"image":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/#primaryimage"},"thumbnailUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/04\/blog-2355684-1280.jpg","articleSection":["Unkategorisiert"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/","url":"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/","name":"Automatically Updating Angular Modules With Schematics And The CLI - ANGULARarchitects","isPartOf":{"@id":"https:\/\/www.angulararchitects.io\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/#primaryimage"},"image":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/#primaryimage"},"thumbnailUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/04\/blog-2355684-1280.jpg","datePublished":"2017-12-01T07:21:04+00:00","breadcrumb":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/#primaryimage","url":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/04\/blog-2355684-1280.jpg","contentUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/04\/blog-2355684-1280.jpg","width":1280,"height":853},{"@type":"BreadcrumbList","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/automatically-updating-angular-modules-with-schematics-and-the-cli\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.angulararchitects.io\/en\/"},{"@type":"ListItem","position":2,"name":"Automatically Updating Angular Modules With Schematics And The CLI"}]},{"@type":"WebSite","@id":"https:\/\/www.angulararchitects.io\/en\/#website","url":"https:\/\/www.angulararchitects.io\/en\/","name":"ANGULARarchitects","description":"AngularArchitects.io","publisher":{"@id":"https:\/\/www.angulararchitects.io\/en\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.angulararchitects.io\/en\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.angulararchitects.io\/en\/#organization","name":"ANGULARarchitects","alternateName":"SOFTWAREarchitects","url":"https:\/\/www.angulararchitects.io\/en\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/logo\/image\/","url":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/07\/AA-Logo-RGB-horizontal-inside-knowledge-black.svg","contentUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/07\/AA-Logo-RGB-horizontal-inside-knowledge-black.svg","width":644,"height":216,"caption":"ANGULARarchitects"},"image":{"@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/github.com\/angular-architects","https:\/\/www.linkedin.com\/company\/angular-architects\/"]},{"@type":"Person","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/15628efa7af4475ffaaeeb26c5112951","name":"Manfred Steyer, GDE","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/a0b59539674d8b71ea1c1f4764b11244b5f499203f1d11b40f37d8f3f90be033?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/a0b59539674d8b71ea1c1f4764b11244b5f499203f1d11b40f37d8f3f90be033?s=96&d=mm&r=g","caption":"Manfred Steyer, GDE"},"sameAs":["https:\/\/x.com\/daniel"]}]}},"_links":{"self":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts\/2387","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/users\/9"}],"replies":[{"embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/comments?post=2387"}],"version-history":[{"count":0,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts\/2387\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/media\/2997"}],"wp:attachment":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/media?parent=2387"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/categories?post=2387"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/tags?post=2387"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}