{"id":2921,"date":"2019-07-27T19:22:51","date_gmt":"2019-07-27T17:22:51","guid":{"rendered":"https:\/\/www.angulararchitects.io\/?p=2921"},"modified":"2019-07-27T19:22:51","modified_gmt":"2019-07-27T17:22:51","slug":"architecture-with-ivy-a-possible-future-without-angular-modules","status":"publish","type":"post","link":"https:\/\/www.angulararchitects.io\/en\/blog\/architecture-with-ivy-a-possible-future-without-angular-modules\/","title":{"rendered":"Architecture with Ivy: A possible future without Angular Modules"},"content":{"rendered":"<div class=\"article\">\n<p>This article is part of an series:<\/p>\n<ul>\n<li >Part 1: A possible future without Angular Modules (this one)<\/li>\n<li ><a  href=\"https:\/\/www.angulararchitects.io\/aktuelles\/architecture-with-angular-ivy-part-2-higher-order-and-dynamic-components\/\"><span style=\"color: #e5253!important\">Part 2: Higher order and dynamic Components<\/span><\/a><\/li>\n<\/ul>\n<hr \/>\n<p>&nbsp;<\/p>\n<p>As there is already a module system in EcmaScript, the need for Angular Modules (NgModules) can be confusing. Hence, this is also always a big topic in my <a href=\"https:\/\/www.angulararchitects.io\/schulungen\/angular\">Angular workshops<\/a>. Fortunately, for Angular Ivy NgModules are optional - at least beyond the covers.<\/p>\n<p>In this post I want to show:<\/p>\n<ul>\n<li>? How a possible future without (with optional) NgModules could look like<\/li>\n<li>? How we can prepare for this future already today<\/li>\n<\/ul>\n<p>The <a href=\"https:\/\/github.com\/manfredsteyer\/angular-without-modules\">source code<\/a> used for the examples can be found <a href=\"https:\/\/github.com\/manfredsteyer\/angular-without-modules\">here<\/a>.<\/p>\n<blockquote><p>\nThanks to Angular's <a href=\"https:\/\/twitter.com\/mgechev\">Minko Gechev<\/a> for reviewing this article.\n<\/p><\/blockquote>\n<p class=\"disclaimer\"><b>DISCLAIMER<\/b>: The examples here are an <em>experiment<\/em> showing a possible direction Angular might be heading to. Hence, it's not production ready and it <em>does not<\/em> reflect the Angular teams's official vision. Nethertheless, it shows what's possible with Ivy and it leads to a conclusion about <em>how we can prepare already today<\/em> for a future without <code>NgModules<\/code>.\n<\/p>\n<h2 id=\"A-little-history\">A little history<\/h2>\n<p>When Angular -- back than called Angular 2 -- was envisioned, the team didn't plan to implement an own module system. While this was necessary in the times of AngularJS 1.x, the idea for Angular (2+) was to just leverage EcmaScript modules introduced in 2015.<\/p>\n<p>And so, Angular Modules have been among several AngularJS 1.x aspects that should have been skipped in the upcoming version of Google's SPA flagship. The following graphic, taken out of <a href=\"https:\/\/twitter.com\/igorminar?lang=de\">Igor Minar<\/a>'s and <a href=\"https:\/\/twitter.com\/tbosch1009?lang=de\">Tobias Bosch<\/a>'s presentation at ngEurope 2014 in Paris emphasizes this:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/07\/a.png\" alt=\"\" width=\"274\" height=\"300\" class=\"alignnone size-full wp-image-2924\" \/><\/p>\n<p>However, during the development of Angular it became obvious, that Angular Modules can come in handy for several reasons. One reason was lazy loading; another reason was the need to provide context for the Angular compiler. This is because the compiler needs to know which components, directives, and pipes are available within a template.<\/p>\n<p>On the contrary, Ivy has a different strategy to define the compilation context -- at least under the covers. The next section gives some details about this.<\/p>\n<h2 id=\"Compilation-Context-for-Ivy\">Compilation Context for Ivy<\/h2>\n<p>One of the benefits of Ivy is that it produces simpler code. During compilation, it just adds a static <code>ngComponentDef<\/code> property to components. This property contains a definition object describing the component for the compiler.<\/p>\n<p>Similarly, the compiler adds also such a definition to directives and pipes. They are called <code>ngDirectiveDef<\/code> and <code>ngPipeDef<\/code>.<\/p>\n<p>You can even access it at runtime:<\/p>\n<pre><div><span class=\"hljs-keyword\">const<\/span> def: ComponentDef&lt;AppComponent&gt; = AppComponent[<span class=\"hljs-string\">'ngComponentDef'<\/span>];\n<span class=\"hljs-built_in\">console<\/span>.debug(<span class=\"hljs-string\">'def'<\/span>, def);\n<\/div><\/pre>\n<p>The respective console output would look like this:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/07\/b.png\" alt=\"\" width=\"466\" height=\"874\" class=\"alignnone size-full wp-image-2925\" srcset=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/07\/b.png 466w, https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/07\/b-160x300.png 160w\" sizes=\"auto, (max-width: 466px) 100vw, 466px\" \/><\/p>\n<p>As you see here, these properties contain everything Angular needs to know when executing the component. Perhaps you've noticed the <code>directiveDefs<\/code> and <code>pipeDefs<\/code> properties. They contain the compilation context for the template we've talked about above.<\/p>\n<p>The first one points to an array of definitions for directives and components. Saying this, a component definition is just a special kind of a directive definition. Alternatively, <code>directiveDefs<\/code> can point to a factory function returning such an array.<\/p>\n<p>The <code>pipeDefs<\/code> property does the same for pipe definitions.<\/p>\n<p>This way, Angular knows which (sub-)components, directives, and pipes are available in a component's template.<\/p>\n<p>Now, you might wonder how those properties are filled with the right values. In order to prevent breaking changes, the Ivy compiler just looks up the necessary entries in the component's module as well as in all other modules imported there. After this, it adds the found components, directives, and pipes to <code>directiveDefs<\/code> or <code>pipeDefs<\/code>.<\/p>\n<p>However, if we wanted to use Ivy without modules, we could directly populate these two property. The next section provides some information about this idea.<\/p>\n<h2 id=\"Compilation-Context-without-NgModules\">Compilation Context without NgModules<\/h2>\n<p>Technically, it's possible to directly add the compilation context to <code>directiveDefs<\/code> and <code>pipeDefs<\/code>. Unfortunately, these properties are not part of Angular's public API currently.<\/p>\n<p>This is for a reason: First of all, the Angular team concentrates on making sure Ivy is completely backwards compatible. Only than, they will introduce new features based upon Ivy step by step.<\/p>\n<p>When that happens, the <code>Component<\/code> decorator might get some additional properties for this reason.<\/p>\n<p>As the next section shows, we can already have a short look into this possible future today.<\/p>\n<h2 id=\"Directly-providing-the-compilation-context\">Directly providing the compilation context<\/h2>\n<p>As directly providing the compilation context is not possible with public APIs today, this section directly leverages the available private ones. Of course, they can change and hence the techniques outlined here are <strong>not feasible for production<\/strong> code.<\/p>\n<p>Nethertheless, this experiment shows how modern Angular code might look like in the future. It also leads to a conclusion that tells us, how we can prepare for this future.<\/p>\n<p>To demonstrate how to directly provide the compilation context, I'm using a simple example here. It just contains a <code>tabbed-pane<\/code> which displays one of several <code>tab<\/code>s at a time:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/07\/c.png\" alt=\"\" width=\"627\" height=\"467\" class=\"alignnone size-full wp-image-2926\" srcset=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/07\/c.png 627w, https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/07\/c-600x447.png 600w, https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/07\/c-300x223.png 300w\" sizes=\"auto, (max-width: 627px) 100vw, 627px\" \/><\/p>\n<p>The example's <code>AppComponent<\/code> uses them:<\/p>\n<pre><div><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">tabbed-pane<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">tab<\/span> <span class=\"hljs-attr\">title<\/span>=<span class=\"hljs-string\">\"Tab 1\"<\/span>&gt;<\/span>\n    Lorem ipsum ...\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">tab<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">tab<\/span> <span class=\"hljs-attr\">title<\/span>=<span class=\"hljs-string\">\"Tab 2\"<\/span>&gt;<\/span>\n    Lorem ipsum ...\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">tab<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">tab<\/span> <span class=\"hljs-attr\">title<\/span>=<span class=\"hljs-string\">\"Tab 3\"<\/span>&gt;<\/span>\n    Lorem ipsum ...\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">tab<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">tabbed-pane<\/span>&gt;<\/span>\n<\/div><\/pre>\n<p>For showing and hiding the tabs, the <code>TabbedPaneComponent<\/code> uses Angular's <code>*ngIf<\/code> directive and for displaying the link it uses <code>*ngFor<\/code>.<\/p>\n<p>If we want to provide the compilation context directly to these components, we need to get hold of the respective definition objects. For this, I've created a helper function:<\/p>\n<pre><div><span class=\"hljs-keyword\">import<\/span> { Type } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@angular\/core\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { \u0275ComponentDef <span class=\"hljs-keyword\">as<\/span> ComponentDef } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@angular\/core'<\/span>;\n\n[...]\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">getComponentDef<\/span>&lt;<span class=\"hljs-title\">T<\/span>&gt;(<span class=\"hljs-params\">t: Type&lt;T&gt;<\/span>): <span class=\"hljs-title\">ComponentDef<\/span>&lt;<span class=\"hljs-title\">T<\/span>&gt; <\/span>{\n  <span class=\"hljs-keyword\">if<\/span> (t[<span class=\"hljs-string\">'ngComponentDef'<\/span>]) {\n    <span class=\"hljs-keyword\">return<\/span> t[<span class=\"hljs-string\">'ngComponentDef'<\/span>] <span class=\"hljs-keyword\">as<\/span> ComponentDef&lt;T&gt;;\n  }\n\n  <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Error<\/span>(<span class=\"hljs-string\">'No Angular definition found for '<\/span> + t.name);\n}\n<\/div><\/pre>\n<p>As you might have noticed, the <code>ComponentDef<\/code> class is prefixed with the <code>\u0275<\/code> sign. This denotes that the class is still part of Angular's private API.<\/p>\n<p>I've written similar helper functions for getting <code>DirectiveDef<\/code>s and <code>PipeDef<\/code>s:<\/p>\n<pre><div><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">getDirectiveDef<\/span>&lt;<span class=\"hljs-title\">T<\/span>&gt;(<span class=\"hljs-params\">t: Type&lt;T&gt;<\/span>): <span class=\"hljs-title\">DirectiveDef<\/span>&lt;<span class=\"hljs-title\">T<\/span>&gt; <\/span>{\n\n    <span class=\"hljs-keyword\">if<\/span> (t[<span class=\"hljs-string\">'ngDirectiveDef'<\/span>]) {\n      <span class=\"hljs-keyword\">return<\/span> t[<span class=\"hljs-string\">'ngDirectiveDef'<\/span>] <span class=\"hljs-keyword\">as<\/span> DirectiveDef&lt;T&gt;;\n    }\n\n    <span class=\"hljs-comment\">\/\/ A Component(Def) is also a Directive(Def)<\/span>\n    <span class=\"hljs-keyword\">if<\/span> (t[<span class=\"hljs-string\">'ngComponentDef'<\/span>]) {\n      <span class=\"hljs-keyword\">return<\/span> t[<span class=\"hljs-string\">'ngComponentDef'<\/span>] <span class=\"hljs-keyword\">as<\/span> ComponentDef&lt;T&gt;;\n    }\n\n    <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Error<\/span>(<span class=\"hljs-string\">'No Angular definition found for '<\/span> + t.name);\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">getPipeDef<\/span>&lt;<span class=\"hljs-title\">T<\/span>&gt;(<span class=\"hljs-params\">t: Type&lt;T&gt;<\/span>): <span class=\"hljs-title\">PipeDef<\/span>&lt;<span class=\"hljs-title\">T<\/span>&gt; <\/span>{\n\n  <span class=\"hljs-keyword\">if<\/span> (t[<span class=\"hljs-string\">'ngPipeDef'<\/span>]) {\n    <span class=\"hljs-keyword\">return<\/span> t[<span class=\"hljs-string\">'ngPipeDef'<\/span>] <span class=\"hljs-keyword\">as<\/span> PipeDef&lt;T&gt;;\n  }\n\n  <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Error<\/span>(<span class=\"hljs-string\">'No Angular definition found for '<\/span> + t.name);\n}\n<\/div><\/pre>\n<p>Similarly, I've written helper functions for getting all the definition objects from an array of directives and an array of pipes:<\/p>\n<pre><div><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">getDirectiveDefs<\/span>(<span class=\"hljs-params\">types: Type&lt;<span class=\"hljs-built_in\">any<\/span>&gt;[]<\/span>): <span class=\"hljs-title\">DirectiveDef<\/span>&lt;<span class=\"hljs-title\">any<\/span>&gt;[] <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> types.map(<span class=\"hljs-function\"><span class=\"hljs-params\">t<\/span> =&gt;<\/span> getDirectiveDef(t));\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">getPipeDefs<\/span>(<span class=\"hljs-params\">types: Type&lt;<span class=\"hljs-built_in\">any<\/span>&gt;[]<\/span>): <span class=\"hljs-title\">PipeDef<\/span>&lt;<span class=\"hljs-title\">any<\/span>&gt;[] <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> types.map(<span class=\"hljs-function\"><span class=\"hljs-params\">t<\/span> =&gt;<\/span> getPipeDef(t));\n}\n<\/div><\/pre>\n<p>Please note that the former one is also respecting component definitions, as a component definition is a special kind of a directive definition. Technically, <code>ComponentDef<\/code> even inherits <code>DirectiveDef<\/code>.<\/p>\n<p>Using these helpers, we can easily add the compilation context to our components:<\/p>\n<pre><div><span class=\"hljs-meta\">@Component<\/span>({ [...] })\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">class<\/span> AppComponent {\n  title = <span class=\"hljs-string\">'demo'<\/span>;\n}\n\n<span class=\"hljs-comment\">\/\/ Adding compilation context<\/span>\n<span class=\"hljs-keyword\">const<\/span> def = getComponentDef(AppComponent);\n\ndef.directiveDefs = [\n  getDirectiveDef(TabComponent), \n  getDirectiveDef(TabbedPaneComponent)\n];\n<\/div><\/pre>\n<p>For the sake of simplicity, I'm overwriting the <code>directiveDefs<\/code> property here. This means that values the compiler placed there after traversing possibly existing modules are overwritten too.<\/p>\n<p>Of course, adding the same definition objects time and again to different consuming objects is annoying. However, we could group components belonging together using a central array:<\/p>\n<pre><div><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> TABBEND_PANE_COMPONENTS = [\n    TabbedPaneComponent,\n    TabComponent\n];\n<\/div><\/pre>\n<p>To import this array, we can use our <code>getDirectiveDef<\/code> helper function:<\/p>\n<pre><div>def.directiveDefs = [\n  ...getDirectiveDefs(TABBEND_PANE_COMPONENTS)\n];\n<\/div><\/pre>\n<p>Similarly to this, I've written a file exporting all the directives I need from <code>@angular\/common<\/code>:<\/p>\n<pre><div><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> COMMON_DIRECTIVES = [\n    NgIf,\n    NgForOf,\n    <span class=\"hljs-comment\">\/\/ etc.<\/span>\n];\n<\/div><\/pre>\n<p>This one is used for the <code>TabbedPaneComponent<\/code>:<\/p>\n<pre><div><span class=\"hljs-meta\">@Component<\/span>({ [...] })\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">class<\/span> TabbedPaneComponent <span class=\"hljs-keyword\">implements<\/span> AfterContentInit {\n    [...]\n}\n\n<span class=\"hljs-keyword\">const<\/span> def = getDef(TabbedPaneComponent);\n\ndef.directiveDefs = [\n     ...getDefs(COMMON_DIRECTIVES)\n];\n<\/div><\/pre>\n<p>Of course, as we have just two components, this is not a big win here but in bigger scenarios with lots of components using such an array comes quite in handy.<\/p>\n<p>As patching a component after defining it is somewhat brutal, the next section shows a better way.<\/p>\n<h2 id=\"Providing-the-compilation-context-with-a-decorator\">Providing the compilation context with a decorator<\/h2>\n<p>To add the compilation context to components in a way we are more used to as Angular developers, I've written a simple decorator:<\/p>\n<pre><div><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">interface<\/span> ComponentDepsConfig {\n  directives?: Type&lt;<span class=\"hljs-built_in\">any<\/span>&gt;[];\n  pipes?: Type&lt;<span class=\"hljs-built_in\">any<\/span>&gt;[];\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">ComponentDeps<\/span>(<span class=\"hljs-params\">config: ComponentDepsConfig<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-function\">(<span class=\"hljs-params\">component<\/span>) =&gt;<\/span> {\n\n    <span class=\"hljs-keyword\">const<\/span> def = getComponentDef(component);\n\n    def.directiveDefs = [\n      ...getDirectiveDefs(config.directives || [])\n    ];\n\n    def.pipeDefs = [\n      ...getPipeDefs(config.pipes || [])\n    ];\n\n  }\n}\n<\/div><!--more-->\n\n<\/pre>\n<p>To be more precise, this is a factory for a decorator. It takes a config object containing the compilation context and returns a decorator for a component. This decorator adds the context to the component's definition.<\/p>\n<p>Now, let's apply this decorator to our components:<\/p>\n<pre><div><span class=\"hljs-meta\">@Component<\/span>({ [...] })\n<span class=\"hljs-meta\">@ComponentDeps<\/span>({\n  directives: [ \n    ...TABBEND_PANE_COMPONENTS\n  ]\n})\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">class<\/span> AppComponent {\n  title = <span class=\"hljs-string\">'demo'<\/span>;\n}\n<\/div><\/pre>\n<p>This looks a lot like the envisioned possible future where the component decorator directly takes the compilation context. Also, Angular's <a href=\"https:\/\/twitter.com\/mgechev\">Minko Gechev<\/a> created a <a href=\"https:\/\/github.com\/mgechev\/angular-ivy-demo\">prototype of Angular<\/a> which uses this idea. It's Component decorator come with a <code>deps<\/code> property that serves the same purpose. One more time, this is all is about showing what's possible and it doesn't reflect the Angular teams's official vision.<\/p>\n<p>However, now the question is what can we learn from this case study. The next section provides an answer.<\/p>\n<h2 id=\"Preparing-for-a-possible-future-without-with-optional-NgModules\">Preparing for a possible future without (with optional) NgModules<\/h2>\n<p>In this article, we've seen that we need a compilation context. If we don't have something like <code>NgModules<\/code> we could assign it directly to our components. This is already possible by using internal APIs and the respective properties might eventually be exposed a part of Angular's public API.<\/p>\n<p>We've also seen that even in this case, it's in handy to group components, directives, or pipes belonging together. For this reason we've used a simple array:<\/p>\n<pre><div><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> TABBEND_PANE_COMPONENTS = [\n    TabbedPaneComponent,\n    TabComponent\n];\n<\/div><\/pre>\n<p>Interestingly, this array look like the <code>export<\/code> part of an NgModule. However, this is pure EcmaScript which makes its simpler and easier to understand.<\/p>\n<p>Also, it's obvious that even in a future without <code>NgModules<\/code> we need a way to group parts of our code. We will also need some kind of information hiding which means we have to define public and private parts of our APIs. Fortunately, this can also be accomplished with pure EcmaScript by using barrels.<\/p>\n<p>For instance, in my case study, the <code>tabbed-pane<\/code> folder has the following <code>index.ts<\/code>:<\/p>\n<pre><div><span class=\"hljs-keyword\">export<\/span> * <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/tab.component'<\/span>;\n<span class=\"hljs-keyword\">export<\/span> * <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/tabbed-pane.component'<\/span>;\n\n<span class=\"hljs-comment\">\/\/ array with components<\/span>\n<span class=\"hljs-keyword\">export<\/span> * <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/components'<\/span>; \n<\/div><\/code><\/pre>\n<p>The <code>app.component.ts<\/code> imports this barrel:<\/p>\n<pre><div><span class=\"hljs-keyword\">import<\/span> { TABBEND_PANE_COMPONENTS } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/tabbed-pane'<\/span>;\n<\/div><\/pre>\n<p>We can even go one step further and use a monorepo with different libraries. Each library gets a barrel which defines the public API. Thanks to the Angular CLI creating libraries to group your code is very easy. It's just a matter of one command (<code>ng generate lib my-lib<\/code>) and it also makes your code more reusable.<\/p>\n<p>Furthermore, when using <a href=\"https:\/\/nx.dev\">Nrwl's Nx<\/a> for creating an Angular CLI based monorepo, you can also <a href=\"https:\/\/www.angulararchitects.io\/post\/2019\/03\/04\/sustainable-angular-architectures-with-strategic-design-and-monorepos-part-2-implementation.aspx\">define access restrictions between your libraries<\/a>. Also, it contains linting rules preventing that someone uses private parts of your APIs by bypassing their barrels.<\/p>\n<p>This all leads to my advice for preparing for this possible future without (with optional) Angular modules.<\/p>\n<h2 id=\"Conclusion\">Conclusion<\/h2>\n<p>As you have seen here, we can already today&nbsp;prepare for a possible future without (with optional) NgModules. It's as easy as that:<\/p>\n<ol>\n<li>Cut your application into libraries and use barrels to define their public APIs.<\/li>\n<li>When NgModules become optional, replace them with an their <code>export<\/code> arrays.<\/li>\n<\/ol>\n<p>Finally, let me tell you the best: Regardless, if this possible future will happen or not, this advice makes a lot of sense anyway, because cutting your application into tiny libraries with a public and a private part leads to a more robust architecture.\n<\/p><\/div>\n","protected":false},"excerpt":{"rendered":"<p>For Ivy, NgModules are optional. This allows us to structure Angular applications with pure EcmaScript techniques like barrels and packages.<\/p>\n","protected":false},"author":9,"featured_media":2922,"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-2921","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>Architecture with Ivy: A possible future without Angular Modules - 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\/aktuelles\/architecture-with-ivy-a-possible-future-without-angular-modules\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Architecture with Ivy: A possible future without Angular Modules - ANGULARarchitects\" \/>\n<meta property=\"og:description\" content=\"For Ivy, NgModules are optional. This allows us to structure Angular applications with pure EcmaScript techniques like barrels and packages.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/architecture-with-ivy-a-possible-future-without-angular-modules\/\" \/>\n<meta property=\"og:site_name\" content=\"ANGULARarchitects\" \/>\n<meta property=\"article:published_time\" content=\"2019-07-27T17:22:51+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/07\/architecture-with-angular-ivy-part-1-a-possible-future-without-ngmodules1.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"640\" \/>\n\t<meta property=\"og:image:height\" content=\"426\" \/>\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:image\" content=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/07\/architecture-with-angular-ivy-part-1-a-possible-future-without-ngmodules1.jpg\" \/>\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=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/architecture-with-ivy-a-possible-future-without-angular-modules\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/architecture-with-ivy-a-possible-future-without-angular-modules\/\"},\"author\":{\"name\":\"Manfred Steyer, GDE\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/15628efa7af4475ffaaeeb26c5112951\"},\"headline\":\"Architecture with Ivy: A possible future without Angular Modules\",\"datePublished\":\"2019-07-27T17:22:51+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/architecture-with-ivy-a-possible-future-without-angular-modules\/\"},\"wordCount\":1625,\"publisher\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/architecture-with-ivy-a-possible-future-without-angular-modules\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/07\/architecture-with-angular-ivy-part-1-a-possible-future-without-ngmodules1.jpg\",\"articleSection\":[\"Unkategorisiert\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/architecture-with-ivy-a-possible-future-without-angular-modules\/\",\"url\":\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/architecture-with-ivy-a-possible-future-without-angular-modules\/\",\"name\":\"Architecture with Ivy: A possible future without Angular Modules - ANGULARarchitects\",\"isPartOf\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/architecture-with-ivy-a-possible-future-without-angular-modules\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/architecture-with-ivy-a-possible-future-without-angular-modules\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/07\/architecture-with-angular-ivy-part-1-a-possible-future-without-ngmodules1.jpg\",\"datePublished\":\"2019-07-27T17:22:51+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/architecture-with-ivy-a-possible-future-without-angular-modules\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/architecture-with-ivy-a-possible-future-without-angular-modules\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/architecture-with-ivy-a-possible-future-without-angular-modules\/#primaryimage\",\"url\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/07\/architecture-with-angular-ivy-part-1-a-possible-future-without-ngmodules1.jpg\",\"contentUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/07\/architecture-with-angular-ivy-part-1-a-possible-future-without-ngmodules1.jpg\",\"width\":640,\"height\":426},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/aktuelles\/architecture-with-ivy-a-possible-future-without-angular-modules\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.angulararchitects.io\/en\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Architecture with Ivy: A possible future without Angular Modules\"}]},{\"@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":"Architecture with Ivy: A possible future without Angular Modules - 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\/aktuelles\/architecture-with-ivy-a-possible-future-without-angular-modules\/","og_locale":"en_US","og_type":"article","og_title":"Architecture with Ivy: A possible future without Angular Modules - ANGULARarchitects","og_description":"For Ivy, NgModules are optional. This allows us to structure Angular applications with pure EcmaScript techniques like barrels and packages.","og_url":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/architecture-with-ivy-a-possible-future-without-angular-modules\/","og_site_name":"ANGULARarchitects","article_published_time":"2019-07-27T17:22:51+00:00","og_image":[{"width":640,"height":426,"url":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/07\/architecture-with-angular-ivy-part-1-a-possible-future-without-ngmodules1.jpg","type":"image\/jpeg"}],"author":"Manfred Steyer, GDE","twitter_card":"summary_large_image","twitter_image":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/07\/architecture-with-angular-ivy-part-1-a-possible-future-without-ngmodules1.jpg","twitter_creator":"@daniel","twitter_misc":{"Written by":"Manfred Steyer, GDE","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/architecture-with-ivy-a-possible-future-without-angular-modules\/#article","isPartOf":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/architecture-with-ivy-a-possible-future-without-angular-modules\/"},"author":{"name":"Manfred Steyer, GDE","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/15628efa7af4475ffaaeeb26c5112951"},"headline":"Architecture with Ivy: A possible future without Angular Modules","datePublished":"2019-07-27T17:22:51+00:00","mainEntityOfPage":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/architecture-with-ivy-a-possible-future-without-angular-modules\/"},"wordCount":1625,"publisher":{"@id":"https:\/\/www.angulararchitects.io\/en\/#organization"},"image":{"@id":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/architecture-with-ivy-a-possible-future-without-angular-modules\/#primaryimage"},"thumbnailUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/07\/architecture-with-angular-ivy-part-1-a-possible-future-without-ngmodules1.jpg","articleSection":["Unkategorisiert"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/architecture-with-ivy-a-possible-future-without-angular-modules\/","url":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/architecture-with-ivy-a-possible-future-without-angular-modules\/","name":"Architecture with Ivy: A possible future without Angular Modules - ANGULARarchitects","isPartOf":{"@id":"https:\/\/www.angulararchitects.io\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/architecture-with-ivy-a-possible-future-without-angular-modules\/#primaryimage"},"image":{"@id":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/architecture-with-ivy-a-possible-future-without-angular-modules\/#primaryimage"},"thumbnailUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/07\/architecture-with-angular-ivy-part-1-a-possible-future-without-ngmodules1.jpg","datePublished":"2019-07-27T17:22:51+00:00","breadcrumb":{"@id":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/architecture-with-ivy-a-possible-future-without-angular-modules\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.angulararchitects.io\/en\/aktuelles\/architecture-with-ivy-a-possible-future-without-angular-modules\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/architecture-with-ivy-a-possible-future-without-angular-modules\/#primaryimage","url":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/07\/architecture-with-angular-ivy-part-1-a-possible-future-without-ngmodules1.jpg","contentUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2019\/07\/architecture-with-angular-ivy-part-1-a-possible-future-without-ngmodules1.jpg","width":640,"height":426},{"@type":"BreadcrumbList","@id":"https:\/\/www.angulararchitects.io\/en\/aktuelles\/architecture-with-ivy-a-possible-future-without-angular-modules\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.angulararchitects.io\/en\/"},{"@type":"ListItem","position":2,"name":"Architecture with Ivy: A possible future without Angular Modules"}]},{"@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\/2921","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=2921"}],"version-history":[{"count":0,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts\/2921\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/media\/2922"}],"wp:attachment":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/media?parent=2921"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/categories?post=2921"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/tags?post=2921"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}