{"id":5338,"date":"2021-09-08T12:20:58","date_gmt":"2021-09-08T10:20:58","guid":{"rendered":"https:\/\/www.angulararchitects.io\/?p=5338"},"modified":"2021-09-08T12:20:58","modified_gmt":"2021-09-08T10:20:58","slug":"tutorial-first-steps-with-nx-and-angular-architecture","status":"publish","type":"post","link":"https:\/\/www.angulararchitects.io\/en\/blog\/tutorial-first-steps-with-nx-and-angular-architecture\/","title":{"rendered":"Tutorial &#8211; First Steps with Nx and Angular Architecture"},"content":{"rendered":"<style>\n.wso-softwarearchitekt-news-padding ul li, .wso-softwarearchitekt-news-padding ul li a { line-height: 100% !important; }\n.stoerer-blog h3 {color:#ffffff!important; padding-top: 5px;}\n.stoerer-blog { background-color:#e5253f; padding:2%;}\n.stoerer-blog p, .stoerer-blog p a {color:#ffffff !important;}\n<\/style>\n<p><em>Contents<\/em><\/p>\n<ul>\n<li>Prerequisites<\/li>\n<li>Setting up Your Nx Workspace\n<ul>\n<li>Generating a New Nx Workspace<\/li>\n<li>Implementing Your Data Library<\/li>\n<li>Implementing a Feature Library<\/li>\n<li>Consuming your Feature Library<\/li>\n<\/ul>\n<\/li>\n<li>Leveraging Nx Features\n<ul>\n<li>Creating a Dependency Graph<\/li>\n<li>Using the Build Cache<\/li>\n<li>E2E-Testing with Cypress: A Sneak Peek<\/li>\n<li>Access Restrictions<\/li>\n<\/ul>\n<\/li>\n<li>Final Finishing Touches<\/li>\n<li>What's next ?!<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p>Nx is a famous extension for the Angular CLI provided by former Angular core team members. It's a great solution (not only) for structuring big enterprise-scale applications.<\/p>\n<p>This tutorial shows how to get started with Nx. It starts from scratch with an empty Nx workspace. You learn the following things:<\/p>\n<ul>\n<li>Creating a new Nx workspace<\/li>\n<li>Using the dependency graph<\/li>\n<li>Visualizing changed libs and using the build cache<\/li>\n<li>A sneak peek into E2E testing with Cypress<\/li>\n<li>Enforcing your architecture via access restrictions (for me, the most important aspect)<\/li>\n<\/ul>\n<p>At the end, you will have a structure like this:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2021\/09\/final-graph.png\" alt=\"Final Dependency Graph\" \/><\/p>\n<p>Also, thanks to access restrictions, your architecture will be protected. Hence, if a library is not intended to access another library, you will get an error like this one:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2021\/09\/lint.png\" alt=\"nx lint\" \/><\/p>\n<p>Of course, you get the same error in your editor\/ IDE if it supports eslint. However, as this also works on the command line, you can automate this check and e. g. prevent merging code into your main branch if it violates your architecture, or as I put it: No broken windows anymore!<\/p>\n<p>Btw: You can find the <a href=\"https:\/\/github.com\/manfredsteyer\/nx-intro\">source code<\/a> of this tutorial's solution in my <a href=\"https:\/\/github.com\/manfredsteyer\/nx-intro\">GitHub account<\/a>. For the sake of retracing, there is one separate for each of the below sections.<\/p>\n<h2>Prerequisites<\/h2>\n<p>For this tutorial, you need the following software packages:<\/p>\n<ul>\n<li>Editor like <a href=\"https:\/\/code.visualstudio.com\/\">Visual Studio Code<\/a> <\/li>\n<li><a href=\"https:\/\/git-scm.com\/\">Git Client<\/a><\/li>\n<li><a href=\"https:\/\/nodejs.org\/en\/\">NodeJS<\/a> in current LTS-Version<\/li>\n<li>Angular CLI (<code>npm i -g @angular\/cli<\/code>)<\/li>\n<li>Nx CLI (<code>npm i -g @nrwl\/cli<\/code>)<\/li>\n<\/ul>\n<h2>Setting up Your Nx Workspace<\/h2>\n<p>In this section, you generate an Nx workspace from scratch and add a data access library as well as two feature libraries. <\/p>\n<blockquote><p>\nWhile these tasks are quite &quot;mechanical&quot;, they will help you to understand how everything fits together. In practice, you can automate such tasks with code generators and Nx plugins like <a href=\"https:\/\/www.npmjs.com\/package\/@angular-architects\/ddd\">@angular-architects\/ddd<\/a>.\n<\/p><\/blockquote>\n<p><strong>Remark:<\/strong> While we use a rather simple application here, the project setup we are showing is intended for huge enterprise-scale applications. Please keep this in mind when it feels a bit over-engineered. <\/p>\n<p><strong>Hint:<\/strong> Also, it's a good idea to use your editor's features to jump between files. Visual Studio Code e. g. provides the shortcut <code>CTRL-p<\/code> for quickly jumping to other files.<\/p>\n<h3>Generating a New Nx Workspace<\/h3>\n<p>Now, let scaffold an empty Nx workspace:<\/p>\n<ol>\n<li>\nUse <code>npm init<\/code> to generate a new Nx Workspace:<\/p>\n<pre><code class=\"language-bash\">npm init nx-workspace my-project<\/code><\/pre>\n<p>Answer the questions you get as follows:<\/p>\n<ul>\n<li>What to create in the new workspace: <em>angular<\/em><\/li>\n<li>Application name: <em>flight-app<\/em><\/li>\n<li>Default stylesheet format: <em>scss<\/em><\/li>\n<li>Use Nx Cloud: <em>No<\/em><\/li>\n<\/ul>\n<p>Generating the workspace will take one minute or two.\n<\/li>\n<li>\nSwitch into the generated project:<\/p>\n<pre><code class=\"language-bash\">cd my-project<\/code><\/pre>\n<\/li>\n<li>\nGenerate some libraries:<\/p>\n<pre><code class=\"language-bash\">ng g lib flight-data --buildable\nng g lib feature-search --buildable\nng g lib feature-upgrade --buildable<\/code><\/pre>\n<p><em>Hint:<\/em> The buildable switch allows to build each library separately. This in turn allows chaching each library so that it doesn't need to be rebuild as long as it doesn't change.<\/p>\n<p><em>Hint:<\/em> There is also a directory switch allowing you to subdivide your apps and libs into sub-directories. Each sub-directory can reflect a part (a sub-domain) of your solution.\n<\/li>\n<li>\nOpen your workspace in your editor. You should see the following generated structure:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2021\/09\/generated-workspace.png\" alt=\"Generated Workspace\" \/>\n<\/li>\n<\/ol>\n<h3>Implementing Your Data Library<\/h3>\n<p>The first library we add is for data access:<\/p>\n<ol>\n<li>\nIn your <code>folder libs\/flight-data\/src\/lib<\/code>, add a subfolder <code>model<\/code>:\n<\/li>\n<li>\nAdd a file <code>flight.ts<\/code> to your newly created <code>model<\/code> folder:<\/p>\n<pre><code class=\"language-typescript\">\/\/ libs\/flight-data\/src\/lib\/model\/flight.ts\n\nexport interface Flight {\n    id: number;\n    from: string;\n    to: string;\n    date: string;\n}<\/code><\/pre>\n<\/li>\n<li>\nGenerate a <code>FlightDataService<\/code> in your <code>flight-data<\/code> library:<\/p>\n<pre><code class=\"language-bash\">ng g service flight-data --project flight-data<\/code><\/pre>\n<\/li>\n<li>\nImplement your <code>FlightDataService<\/code> as follows:<\/p>\n<pre><code class=\"language-typescript\">\/\/ libs\/flight-data\/src\/lib\/flight-data.service.ts\n\nimport { Injectable } from '@angular\/core';\nimport { Observable, of } from 'rxjs';\nimport { Flight } from '.\/model\/flight';\n\n@Injectable({ providedIn: 'root' })\nexport class FlightDataService {\n\n    load(): Observable<Flight[]> {\n\n        return of([\n            { id: 1, from: 'Frankfurt', to: 'Mallorca', date: new Date().toISOString() },\n            { id: 2, from: 'Frankfurt', to: 'Barcelona', date: new Date().toISOString() },\n            { id: 3, from: 'Frankfurt', to: 'Ibiza', date: new Date().toISOString() },\n        ]);\n    }\n}<\/code><\/pre>\n<\/li>\n<li>\nExport your model and your service via the library's <code>index.ts<\/code>:<\/p>\n<pre><code class=\"language-typescript\">\/\/ libs\/flight-data\/src\/index.ts\n\nexport * from '.\/lib\/flight-data.module';\n\n\/\/ Add these lines:\nexport * from '.\/lib\/flight-data.service';\nexport * from '.\/lib\/model\/flight';<\/code><\/pre>\n<\/li>\n<\/ol>\n<p>Now, we have our data access lib in place. In the next section, we will use it on one of our feature libraries.<\/p>\n<div class=\"stoerer-blog\" >\n<h3>Angular Architecture Workshop (Online)<\/h3>\n<p>This topic is one of the many topics we cover in our <a href=\"https:\/\/www.angulararchitects.io\/en\/angular-workshops\/advanced-angular-enterprise-architecture-incl-ivy\/\" target=\"_blank\" rel=\"noopener\">Angular Architecture Workshop<\/a>. You can book a ticket for one of our public online workshops or a dedicated workshop for your whole team.<\/p>\n<\/div>\n<h3>Implementing a Feature Library<\/h3>\n<p>Now, let's add two further library for features:<\/p>\n<ol>\n<li>\nIn your <code>feature-search<\/code> library, generate a new <code>FlightSearchComponent<\/code>:<\/p>\n<pre><code class=\"language-bash\">ng g c flight-search --project feature-search --export<\/code><\/pre>\n<\/li>\n<li>\nImplement your component so that it displays the flights provided from your <code>FlightDataService<\/code> in a table.<\/p>\n<pre><code class=\"language-typescript\">\/\/  libs\/feature-search\/src\/lib\/flight-search\/flight-search.component.ts\n\nimport { Component } from '@angular\/core';\n\n\/\/ You might need to add this by hand:\nimport { FlightDataService } from '@my-project\/flight-data';\n\n@Component({\n    selector: 'my-project-flight-search',\n    templateUrl: '.\/flight-search.component.html',\n    styleUrls: ['.\/flight-search.component.scss']\n})\nexport class FlightSearchComponent {\n\n    flightList$ = this.flightService.load();\n\n    constructor(private flightService: FlightDataService) {\n    }\n\n}<\/code><\/pre>\n<pre><code class=\"language-javascript\">&lt;h1&gt;Flights&lt;\/h1&gt;\n\n&lt;table class=&quot;table&quot;&gt;\n    &lt;tr *ngFor=&quot;let flight of flightList$ | async&quot;&gt;\n        &lt;td&gt;{{flight.id}}&lt;\/td&gt;\n        &lt;td&gt;{{flight.from}}&lt;\/td&gt;\n        &lt;td&gt;{{flight.to}}&lt;\/td&gt;\n        &lt;td&gt;{{flight.date | date}}&lt;\/td&gt;\n    &lt;\/tr&gt;\n&lt;\/table&gt;<\/code><\/pre>\n<pre><code class=\"language-css\">\/* libs\/feature-search\/src\/lib\/flight-search\/flight-search.component.scss *\/ \n\ntd {\n    border: 1px solid black;\n    padding: 10px;\n}<\/code><\/pre>\n<\/li>\n<li>\nExport your new component via your feature library's <code>index.ts<\/code>:<\/p>\n<pre><code class=\"language-typescript\">\/\/ libs\/feature-search\/src\/index.ts\n\nexport * from '.\/lib\/feature-search.module';\n\n\/\/ Add this line:\nexport * from '.\/lib\/flight-search\/flight-search.component';<\/code><\/pre>\n<\/li>\n<\/ol>\n<h3>Consuming your Feature Library<\/h3>\n<p>As we have everything in place now, let's consume a feature in our app:<\/p>\n<ol>\n<li>\nSwitch to your <code>flight-app<\/code> and import the <code>FeatureSearchModule<\/code> into your <code>AppModule<\/code>:<\/p>\n<pre><code class=\"language-typescript\">\/\/ apps\/flight-app\/src\/app\/app.module.ts\n\nimport { NgModule } from '@angular\/core';\nimport { BrowserModule } from '@angular\/platform-browser';\nimport { AppComponent } from '.\/app.component';\n\n\/\/ You might need to add this line by hand:\nimport { FeatureSearchModule } from '@my-project\/feature-search';\n\n@NgModule({\n    imports: [BrowserModule, \n        \/\/ Import FeatureSearchModule\n        FeatureSearchModule\n    ],\n    declarations: [AppComponent],\n    providers: [],\n    bootstrap: [AppComponent],\n})\nexport class AppModule {}<\/code><\/pre>\n<\/li>\n<li>\nCall your feature component in your <code>app.component.html<\/code>. For this, replace the whole content with the following one:<\/p>\n<pre><code class=\"language-html\">&lt;my-project-flight-search&gt;&lt;\/my-project-flight-search&gt;<\/code><\/pre>\n<\/li>\n<li>\nStart your application:<\/p>\n<pre><code class=\"language-bash\">ng serve flight-app -o<\/code><\/pre>\n<p>The result should look as follows:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2021\/09\/result.png\" alt=\"Result\" \/><\/p>\n<p>Frankly, this is quite a simple application. However, it's complex enogh to show how Nx helps with building enterprise-scale Angular applications.\n<\/li>\n<\/ol>\n<h2>Leveraging Nx Features<\/h2>\n<p>Now, we can finally play around with the cool features provided by Nx.<\/p>\n<h3>Creating a Dependency Graph<\/h3>\n<p>Let's start with generating a dependency graph. <\/p>\n<ol>\n<li>\nCall the following command to display a dependency graph for your solution:<\/p>\n<pre><code class=\"language-bash\">nx dep-graph<\/code><\/pre>\n<p>To see the whole dependency graph, click <code>Select All<\/code> on the left:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2021\/09\/graph.png\" alt=\"Dependency Graph\" \/><\/p>\n<p>Obviously, the feature-upgrade library hasn't been used so far. We'll do this in another exercise.\n<\/li>\n<li>\nImportant: Close the process that started <code>nx dep-graph<\/code>, because otherwise it blocks a TCP port we need for showing further dependency graphs.\n<\/li>\n<li>\nOpen your <code>nx.json<\/code> in your workspace's root directory. Make sure, the <code>defaultBase<\/code> property contains the name of your main git branch (default <code>master<\/code>; I and many others prefer <code>main<\/code>):<\/p>\n<pre><code class=\"language-json\">{\n    \"npmScope\": \"my-project\",\n    \"affected\": {\n        \"defaultBase\": \"main\"\n    },\n    [...]\n}<\/code><\/pre>\n<\/li>\n<li>\nAdd all your files and commit them via git:<\/p>\n<pre><code class=\"language-bash\">git add *\ngit commit -m \"Creating a Dependency Graph\"<\/code><\/pre>\n<\/li>\n<li>\nChange your file <code>libs\/feature-search\/src\/lib\/feature-search.module.ts<\/code> by adding a line break to the end.\n<\/li>\n<li>\nCreate a dependency graph showing all affected libraries:<\/p>\n<pre><code class=\"language-bash\">nx affected:dep-graph<\/code><\/pre>\n<p>By clicking &quot;Select All&quot; you display all libraries and applications. The changed one and the ones affected by the change are red; the others are black:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2021\/09\/affected-graph.png\" alt=\"Affected Dep-Graph\" \/>\n<\/li>\n<li>\nYou can get the same information on your console using the following commands:<\/p>\n<pre><code class=\"language-bash\">nx affected:apps\nnx affected:libs<\/code><\/pre>\n<\/li>\n<\/ol>\n<h3>Using the Build Cache<\/h3>\n<p>Thanks to the build cache, you only need to rebuild (retest and relint) the changed parts of your repo.<\/p>\n<ol>\n<li>\nBuild your application:<\/p>\n<pre><code class=\"language-bash\">nx build flight-app<\/code><\/pre>\n<\/li>\n<li>\nBuild it again and see that now the result is taken out of the cache:<\/p>\n<pre><code class=\"language-bash\">nx build flight-app<\/code><\/pre>\n<\/li>\n<li>\nOnce again, change your file <code>libs\/feature-search\/src\/lib\/feature-search.module.ts<\/code> by adding a line break to the end.\n<\/li>\n<li>\nBuild your application again and see that now only the changed lib and the app that was affected by this change (as it uses the lib) is rebuild:<\/p>\n<pre><code class=\"language-bash\">nx build flight-app<\/code><\/pre>\n<\/li>\n<\/ol>\n<p><strong>Hint:<\/strong> By default, you find your build cache in the folder <code>node_modules\\.cache\\nx<\/code>.<\/p>\n<h3>E2E-Testing with Cypress: A Sneak Peek<\/h3>\n<p>One of the cool things of Nx is that it automatically integrates famous community solutions and de-facto standards like Cypress for E2E testing. Here, you get a sneak peak of it:<\/p>\n<ol>\n<li>\nUpdate the E2E test for your <code>AppComponent<\/code> as follows:<\/p>\n<pre><code class=\"language-typescript\">\/\/ apps\/flight-app-e2e\/src\/integration\/app.spec.ts\n\ndescribe('flight-app', () => {\n    beforeEach(() => cy.visit('\/'));\n\n    it('should display welcome message', () => {\n\n        cy.get('h1').contains('Flights');\n        cy.screenshot('result');\n        cy.get('table').screenshot('table');\n\n    });\n});<\/code><\/pre>\n<\/li>\n<li>\nRun your e2e test:<\/p>\n<pre><code class=\"language-bash\">nx e2e<\/code><\/pre>\n<\/li>\n<li>\nMake sure the test passes and have a look to the generated screenshots and the recorded video (you find the paths on command line).<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2021\/09\/cypress.png\" alt=\"Cypress Result\" \/>\n<\/li>\n<\/ol>\n<h3>Access Restrictions<\/h3>\n<p>This is the most important feature for sustainable enterprise-scale architectures: Access Restrictions. They prevent coupling between libraries. For this, you define which library is allows to access which other libraries:<\/p>\n<ol>\n<li>\nOpen your <code>nx.json<\/code> in your project's root and add the following tags:<\/p>\n<pre><code class=\"language-json\">[...]\n\"projects\": {\n    \"feature-search\": {\n        \"tags\": [\"feature\"]\n    },\n    \"feature-upgrade\": {\n        \"tags\": [\"feature\"]\n    },\n    \"flight-app\": {\n        \"tags\": [\"app\"]\n    },\n    \"flight-app-e2e\": {\n        \"tags\": [],\n        \"implicitDependencies\": [\"flight-app\"]\n    },\n    \"flight-data\": {\n        \"tags\": [\"data\"]\n    }\n}\n[...]<\/code><\/pre>\n<\/li>\n<li>\nAdd the following constraints to your <code>.eslintrc.json<\/code>:<\/p>\n<pre><code class=\"language-json\">\"@nrwl\/nx\/enforce-module-boundaries\": [\n    \"error\",\n    {\n        \"enforceBuildableLibDependency\": true,\n        \"allow\": [],\n        \"depConstraints\": [\n            {\n                \"sourceTag\": \"app\",\n                \"onlyDependOnLibsWithTags\": [\"feature\"]\n            },\n            {\n                \"sourceTag\": \"feature\",\n                \"onlyDependOnLibsWithTags\": [\"data\"]\n            },\n            {\n                \"sourceTag\": \"data\",\n                \"onlyDependOnLibsWithTags\": [\"util\"]\n            }\n        ]\n    }\n]<\/code><\/pre>\n<\/li>\n<li>\nImport the <code>FeatureUpgradeModule<\/code> into your <code>FlightDataModule<\/code> to break your architecture:<\/p>\n<pre><code class=\"language-typescript\">\/\/ libs\/flight-data\/src\/lib\/flight-data.module.ts\n\nimport { NgModule } from '@angular\/core';\nimport { CommonModule } from '@angular\/common';\n\n\/\/ You might need to add this by hand:\nimport { FeatureUpgradeModule } from '@my-project\/feature-upgrade';\n\n@NgModule({\n    imports: [\n        CommonModule,\n        \/\/ Import FeatureUpgradeModule \n        \/\/ (to break your architecture) \n        FeatureUpgradeModule\n    ],\n})\nexport class FlightDataModule {}<\/code><\/pre>\n<\/li>\n<li>\nStart the linter to get informed about your constraint violation:<\/p>\n<pre><code class=\"language-bash\">nx lint flight-data<\/code><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2021\/09\/lint.png\" alt=\"nx lint\" \/><\/p>\n<p>If you have an eslint plugin installed, you should get the same linting error in your editor. You might need to restart your editor so that the changed configuration files are reloaded and respected.\n<\/li>\n<\/ol>\n<h2>Final Finishing Touches<\/h2>\n<p>Now, let's correct the incorrect access paths introduced in the last section and finish our tutorial.<\/p>\n<ol>\n<li>\nRemove the <code>FeatureUpgradeModule<\/code> from the <code>FlightDataModule<\/code> to get rid of the linting error you got in the last section: <\/p>\n<pre><code class=\"language-typescript\">\/\/ libs\/flight-data\/src\/lib\/flight-data.module.ts\n\nimport { NgModule } from '@angular\/core';\nimport { CommonModule } from '@angular\/common';\n\n\/\/ Remove this:\n\/\/ import { FeatureUpgradeModule } from '@my-project\/feature-upgrade';\n\n@NgModule({\nimports: [\n    CommonModule,\n    \/\/ Remove this: \n    \/\/FeatureUpgradeModule\n],\n})\nexport class FlightDataModule {}<\/code><\/pre>\n<\/li>\n<li>\nImport the <code>FlightDataModule<\/code> into the <code>FeatureUpgradeModule<\/code>:<\/p>\n<pre><code class=\"language-typescript\">\/\/ libs\/feature-upgrade\/src\/lib\/feature-upgrade.module.ts\n\nimport { NgModule } from '@angular\/core';\nimport { CommonModule } from '@angular\/common';\n\n\/\/ You might need to add this by hand:\nimport { FlightDataModule } from '@my-project\/flight-data';\n\n@NgModule({\nimports: [\n    CommonModule,\n    \/\/ Add this line:\n    FlightDataModule\n],\n})\nexport class FeatureUpgradeModule {}<\/code><\/pre>\n<\/li>\n<li>\nAlso, import the <code>FeatureUpgradeModule<\/code> into your <code>AppModule<\/code>:<\/p>\n<pre><code class=\"language-typescript\">\/\/ apps\/flight-app\/src\/app\/app.module.ts\n\nimport { NgModule } from '@angular\/core';\nimport { BrowserModule } from '@angular\/platform-browser';\nimport { AppComponent } from '.\/app.component';\n\nimport { FeatureSearchModule } from '@my-project\/feature-search';\n\n\/\/ You might need to add this line by hand:\nimport { FeatureUpgradeModule } from '@my-project\/feature-upgrade';\n\n@NgModule({\n    imports: [\n        BrowserModule, \n        FeatureSearchModule,\n\n        \/\/ Add this line:\n        FeatureUpgradeModule\n    ],\n    declarations: [AppComponent],\n    providers: [],\n    bootstrap: [AppComponent],\n})\nexport class AppModule {}<\/code><\/pre>\n<\/li>\n<li>\nGenerate a dependency graph:<\/p>\n<pre><code class=\"language-bash\">nx dep-graph<\/code><\/pre>\n<p>It should have the following final structure:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2021\/09\/final-graph.png\" alt=\"Final Dependency Graph\" \/>\n<\/li>\n<\/ol>\n<h2>What's next ?!<\/h2>\n<p>So far, we've seen how to use Nx for building enterprise-scale Angular applications. However, there are some unanswered questions:<\/p>\n<ul>\n<li>According to which criteria can we sub-divide a huge application into libraries and sub-domains?<\/li>\n<li>Which access restrictions make sense?<\/li>\n<li>Which proven patterns should we use?<\/li>\n<li>How can we evolve our solution towards micro frontends?<\/li>\n<\/ul>\n<p>Our free eBook (about 100 pages) covers all these questions and more:<\/p>\n<p><a href=\"https:\/\/www.angulararchitects.io\/book\"><img decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2020\/12\/cover-small.png\" alt=\"free ebook\"><\/a><\/p>\n<p>Feel free to <a href=\"https:\/\/www.angulararchitects.io\/book\">download it here<\/a> now!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Learn to build sustainable Angular architectures!<\/p>\n","protected":false},"author":9,"featured_media":5339,"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-5338","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>Tutorial - First Steps with Nx and Angular Architecture - 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\/tutorial-first-steps-with-nx-and-angular-architecture\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Tutorial - First Steps with Nx and Angular Architecture - ANGULARarchitects\" \/>\n<meta property=\"og:description\" content=\"Learn to build sustainable Angular architectures!\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.angulararchitects.io\/en\/blog\/tutorial-first-steps-with-nx-and-angular-architecture\/\" \/>\n<meta property=\"og:site_name\" content=\"ANGULARarchitects\" \/>\n<meta property=\"article:published_time\" content=\"2021-09-08T10:20:58+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2021\/09\/imageonline-co-add-text-twitter.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1024\" \/>\n\t<meta property=\"og:image:height\" content=\"536\" \/>\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=\"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\/blog\/tutorial-first-steps-with-nx-and-angular-architecture\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/tutorial-first-steps-with-nx-and-angular-architecture\/\"},\"author\":{\"name\":\"Manfred Steyer, GDE\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/15628efa7af4475ffaaeeb26c5112951\"},\"headline\":\"Tutorial &#8211; First Steps with Nx and Angular Architecture\",\"datePublished\":\"2021-09-08T10:20:58+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/tutorial-first-steps-with-nx-and-angular-architecture\/\"},\"wordCount\":1367,\"publisher\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/tutorial-first-steps-with-nx-and-angular-architecture\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2021\/09\/shutterstock-367937186-small.jpg\",\"articleSection\":[\"Unkategorisiert\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/tutorial-first-steps-with-nx-and-angular-architecture\/\",\"url\":\"https:\/\/www.angulararchitects.io\/en\/blog\/tutorial-first-steps-with-nx-and-angular-architecture\/\",\"name\":\"Tutorial - First Steps with Nx and Angular Architecture - ANGULARarchitects\",\"isPartOf\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/tutorial-first-steps-with-nx-and-angular-architecture\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/tutorial-first-steps-with-nx-and-angular-architecture\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2021\/09\/shutterstock-367937186-small.jpg\",\"datePublished\":\"2021-09-08T10:20:58+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/tutorial-first-steps-with-nx-and-angular-architecture\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.angulararchitects.io\/en\/blog\/tutorial-first-steps-with-nx-and-angular-architecture\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/tutorial-first-steps-with-nx-and-angular-architecture\/#primaryimage\",\"url\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2021\/09\/shutterstock-367937186-small.jpg\",\"contentUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2021\/09\/shutterstock-367937186-small.jpg\",\"width\":1024,\"height\":678},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/tutorial-first-steps-with-nx-and-angular-architecture\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.angulararchitects.io\/en\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Tutorial &#8211; First Steps with Nx and Angular Architecture\"}]},{\"@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":"Tutorial - First Steps with Nx and Angular Architecture - 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\/tutorial-first-steps-with-nx-and-angular-architecture\/","og_locale":"en_US","og_type":"article","og_title":"Tutorial - First Steps with Nx and Angular Architecture - ANGULARarchitects","og_description":"Learn to build sustainable Angular architectures!","og_url":"https:\/\/www.angulararchitects.io\/en\/blog\/tutorial-first-steps-with-nx-and-angular-architecture\/","og_site_name":"ANGULARarchitects","article_published_time":"2021-09-08T10:20:58+00:00","og_image":[{"width":1024,"height":536,"url":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2021\/09\/imageonline-co-add-text-twitter.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":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/tutorial-first-steps-with-nx-and-angular-architecture\/#article","isPartOf":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/tutorial-first-steps-with-nx-and-angular-architecture\/"},"author":{"name":"Manfred Steyer, GDE","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/15628efa7af4475ffaaeeb26c5112951"},"headline":"Tutorial &#8211; First Steps with Nx and Angular Architecture","datePublished":"2021-09-08T10:20:58+00:00","mainEntityOfPage":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/tutorial-first-steps-with-nx-and-angular-architecture\/"},"wordCount":1367,"publisher":{"@id":"https:\/\/www.angulararchitects.io\/en\/#organization"},"image":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/tutorial-first-steps-with-nx-and-angular-architecture\/#primaryimage"},"thumbnailUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2021\/09\/shutterstock-367937186-small.jpg","articleSection":["Unkategorisiert"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/tutorial-first-steps-with-nx-and-angular-architecture\/","url":"https:\/\/www.angulararchitects.io\/en\/blog\/tutorial-first-steps-with-nx-and-angular-architecture\/","name":"Tutorial - First Steps with Nx and Angular Architecture - ANGULARarchitects","isPartOf":{"@id":"https:\/\/www.angulararchitects.io\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/tutorial-first-steps-with-nx-and-angular-architecture\/#primaryimage"},"image":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/tutorial-first-steps-with-nx-and-angular-architecture\/#primaryimage"},"thumbnailUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2021\/09\/shutterstock-367937186-small.jpg","datePublished":"2021-09-08T10:20:58+00:00","breadcrumb":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/tutorial-first-steps-with-nx-and-angular-architecture\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.angulararchitects.io\/en\/blog\/tutorial-first-steps-with-nx-and-angular-architecture\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/tutorial-first-steps-with-nx-and-angular-architecture\/#primaryimage","url":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2021\/09\/shutterstock-367937186-small.jpg","contentUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2021\/09\/shutterstock-367937186-small.jpg","width":1024,"height":678},{"@type":"BreadcrumbList","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/tutorial-first-steps-with-nx-and-angular-architecture\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.angulararchitects.io\/en\/"},{"@type":"ListItem","position":2,"name":"Tutorial &#8211; First Steps with Nx and Angular Architecture"}]},{"@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\/5338","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=5338"}],"version-history":[{"count":0,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts\/5338\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/media\/5339"}],"wp:attachment":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/media?parent=5338"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/categories?post=5338"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/tags?post=5338"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}