{"componentChunkName":"component---src-templates-blog-post-js","path":"/multiple-packages-repository-with-angular/","result":{"data":{"site":{"siteMetadata":{"title":"Fabrizio Fortunato","author":"Fabrizio Fortunato","siteUrl":"https://izifortune.com"}},"markdownRemark":{"id":"7aa5be91-d6b0-5f45-959e-8eb737f9f2a8","excerpt":"Managing modules across different applications can be challenging for Angular applications. There are different approaches that you can take that will impact…","html":"<p>Managing modules across different applications can be challenging for Angular applications. There are different approaches that you can take that will impact your code and i’ve discussed some in my previous post the implications as well <a href=\"https://izifortune.com/managing-modules-with-angular/\">Managing Modules with Angular</a>.</p>\n<p><strong><em>Update 16/09/19:</em></strong> I’ve published a new article with an updated view on monorepositories\n<a href=\"https://izifortune.com/share-angular-libraries-with-lerna/\">https://izifortune.com/share-angular-libraries-with-lerna/</a>.</p>\n<p>In here we are going to explore how to manage in monorepository different modules with the ability also to publish them as separate modules.</p>\n<p>I will leverage <a href=\"nrwl.io/nx\">NRWL/Nx</a> an open source toolkit for enterprise Angular applications and <a href=\"https://github.com/dherges/ng-packagr\">ng-packagr</a> a library for compiling your modules following angular format.</p>\n<h2>Why</h2>\n<p><em>Nx</em> really shines for managing monorepositories and the philosophy behind it is to keep all your code in a single place.</p>\n<p>One big problem that you can have with this setup is that different teams may work on different applications and have different releases and timelines. A team should always reduce the impact of their changes to another and if you are sharing libraries with <em>Nx</em> and doing breaking changes on them you will need to take care of refactoring other applications that you hardly have work on.</p>\n<p>That’s why we can use semantic versioning, even if a breaking change its released another app can still use the previous version. Giving time to the team to adapt those changes.</p>\n<h2>Setup</h2>\n<p>Start by installing the latest <em>Nx</em> cli, and the latest <code class=\"language-text\">@angular/cli</code> globally</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">npm</span> <span class=\"token function\">install</span> -g @nrwl/schematics @angular/cli</code></pre></div>\n<p>This will install the <code class=\"language-text\">create-nx-workspace</code> binary. The next step is to create a workspace:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">create-nx-workspace common</code></pre></div>\n<p>The command will create all the necessary files and folders that we will need for our repository.</p>\n<p>If you want to read more about how workspaces works you can\nread their documentation at <a href=\"https://nrwl.io/nx/guide-nx-workspace\">nx-workspaces</a>.</p>\n<p>Now that we have our workspace we can already start adding libraries or applications to our workspace. </p>\n<p>Since we want to use versioning for our libraries that’s where <em>ng-packagr</em> comes into play.\n<em>ng-packagr</em> its a small library that transpile your library using the <a href=\"https://docs.google.com/document/d/1CZC2rcpxffTDfRDs6p1cfbmKNLA6x5O-NtkJglDaBVs/preview\">Angular library format</a>.</p>\n<p>Using what <em>David Herges</em> demonstrated on the following repository <a href=\"https://github.com/dherges/nx-packaged\">https://github.com/dherges/nx-packaged</a> we want to combine <em>Nx</em> and <em>ng-packagr</em> together.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">npm i --save-dev ng-packagr</code></pre></div>\n<p>Let’s generate two libraries in our repository:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">ng generate lib mylib --nomodule\nng generate lib mylib-two</code></pre></div>\n<p><em>Nx</em> extends the <em>@angular/cli</em> schematics making possible to create applications templates while still using the cli.</p>\n<p>The option <code class=\"language-text\">--nomodule</code> will generate a general library not wrapping it in an angular module.</p>\n<p>This will generate our libraries inside the <code class=\"language-text\">libs</code> folder, what we should have is two folders:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">libs/\n  mylib/\n  mylib-two/</code></pre></div>\n<p>What we need to add is a <code class=\"language-text\">package.json</code> inside each library folder:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">{\n  &quot;$schema&quot;: &quot;../../node_modules/ng-packagr/package.schema.json&quot;,\n  &quot;name&quot;: &quot;@common/mylib&quot;,\n  &quot;version&quot;: &quot;0.0.0&quot;,\n  &quot;ngPackage&quot;: {\n    &quot;lib&quot;: {\n      &quot;entryFile&quot;: &quot;index.ts&quot;\n    },\n    &quot;dest&quot;: &quot;@common/mylib&quot;\n  }\n}</code></pre></div>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">{\n  &quot;$schema&quot;: &quot;../../node_modules/ng-packagr/package.schema.json&quot;,\n  &quot;name&quot;: &quot;@common/mylib-two&quot;,\n  &quot;version&quot;: &quot;0.0.0&quot;,\n  &quot;ngPackage&quot;: {\n    &quot;lib&quot;: {\n      &quot;entryFile&quot;: &quot;index.ts&quot;\n    },\n    &quot;dest&quot;: &quot;@common/mylib-two&quot;\n  }\n}</code></pre></div>\n<p>This way <em>ng-packagr</em> can start packaging our libraries for us. In fact if we run\n<code class=\"language-text\">ng-packagr -p libs/mylib/package.json &amp;&amp; ng-packagr -p libs/mylib-two/package.json</code> after the command run you will notice both the libraries compiled under <em>@common</em> folder.</p>\n<h2>Tools</h2>\n<p>Now we need to take care of building our libraries. In a recent post in the <a href=\"https://blog.nrwl.io/smarter-faster-builds-with-nrwl-nx-c2fd0d1a3277\">NRWL/blog</a> <em>Victor Savkin</em> introduced a new feature on <em>Nx</em> for smarter and faster buils using the toolkit.</p>\n<p>This enhance the <em>Nx</em> toolkit giving you the ability to build only the applications that actually have changed instead of rebuilding the whole repository.</p>\n<p>If you inspect your <code class=\"language-text\">package.json</code> at this point you will notice that there are a series of scripts</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&quot;apps:affected&quot;: &quot;node ./node_modules/@nrwl/schematics/src/command-line/affected.js apps&quot;,\n&quot;build:affected&quot;: &quot;node ./node_modules/@nrwl/schematics/src/command-line/affected.js build&quot;,\n&quot;e2e:affected&quot;: &quot;node ./node_modules/@nrwl/schematics/src/command-line/affected.js e2e&quot;,\n&quot;affected:apps&quot;: &quot;node ./node_modules/@nrwl/schematics/src/command-line/affected.js apps&quot;,\n&quot;affected:build&quot;: &quot;node ./node_modules/@nrwl/schematics/src/command-line/affected.js build&quot;,\n&quot;affected:e2e&quot;: &quot;node ./node_modules/@nrwl/schematics/src/command-line/affected.js e2e&quot;,</code></pre></div>\n<p>We will leverage that but we need to customize it for libraries since those scripts are only available for applications in nx.</p>\n<p>Add these scripts inside the <code class=\"language-text\">scripts</code> folder.</p>\n<script src=\"https://gist.github.com/izifortune/2411d948f9a94f051f05de490384feab.js\"></script>\n<p>The file <code class=\"language-text\">utils.js</code> contains just a set of utilities that we will use into our different scripts.</p>\n<p><code class=\"language-text\">libs-affected.js</code> instead just print out the libraries that are affected from our changes.</p>\n<p>Before testing it out we need to add <code class=\"language-text\">fs-extra</code> in our devDependencies.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">npm i --save-dev fs-extra</code></pre></div>\n<p>And also let’s create a script inside our <code class=\"language-text\">package.json</code> to call <code class=\"language-text\">libs-affected.js</code> script.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&quot;libs:affected&quot;: &quot;node ./scripts/libs-affected.js libs&quot;,</code></pre></div>\n<p>Let’s start by committing our changes that we have so far.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">git commit -am &#39;Initial commmit&#39;</code></pre></div>\n<p>Now generate a new component for <code class=\"language-text\">mylib-two</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">ng generate component myButton --app=mylib-two</code></pre></div>\n<p>Once again let’s commit our changes:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">git commit -am &#39;Add myButton&#39;</code></pre></div>\n<p>If we run now <code class=\"language-text\">npm run libs:affected -- HEAD HEAD~1</code>\nthe output should be: <code class=\"language-text\">mylib-two</code>. The script its returning the library affected since the last commit. Notice that i’m passing the option <code class=\"language-text\">HEAD HEAD~1</code> which compare the current commit with our previous. <code class=\"language-text\">libs:affected</code> supports the same arguments as <code class=\"language-text\">apps:affected</code> from <em>Nx</em> you can invoke the commands either passing the list of the changed files or two commit SHAs.</p>\n<p>To test it even further, let’s import <code class=\"language-text\">mylib</code> into <code class=\"language-text\">mylib-two</code>, commit our changes and then modify only <code class=\"language-text\">mylib</code>, the script should print out to console <code class=\"language-text\">mylib mylib-two</code>.</p>\n<h3>Build</h3>\n<p>Once the number of library will start to growth we definitely don’t want to add each library into our build script to be invoked. Using <code class=\"language-text\">libs-affected</code> we can automate this whole process and build only the changed/affected libraries.</p>\n<p>We will need another scripts to be added:</p>\n<script src=\"https://gist.github.com/izifortune/784f9343dc6cfd5d467ffb460264e2c2.js\"></script>\n<p>And add this to our npm scripts:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&quot;build:libs:affected&quot;: &quot;node ./scripts/libs-build.js build&quot;,</code></pre></div>\n<p>Running <code class=\"language-text\">npm run build:libs:affected -- HEAD HEAD~1</code> will trigger <code class=\"language-text\">ng-packagr</code> build only on those libraries.</p>\n<h3>Test</h3>\n<p>Another important step that we want to guarantee in our repository its testing. In one of my previous <a href=\"https://izifortune.com/unit-testing-angular-applications-with-jest/\">Unit testing angular applications with jest</a> i’ve discussed how to start unit testing with <code class=\"language-text\">jest</code>. Let’s assume that we have already setup jest as our test framework what we need a command that will invoke only the tests of our changed libraries.</p>\n<script src=\"https://gist.github.com/izifortune/948cb42292319c9ffa9ca66e838b4c76.js\"></script>\n<p>And as always another npm script:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&quot;test:libs:affected&quot;: &quot;node ./scripts/libs-test.js libs&quot;,</code></pre></div>\n<p>This is especially good if you are covering unit tests. On the other hand if you have integrations tests than it will be better to run all your tests suit all the time.</p>\n<h3>Bonus: versioning &#x26; release automation</h3>\n<p>The last step that we want to automate in our repository will be related to versioning and releases.</p>\n<p>Leveraging <a href=\"https://github.com/lerna/lerna\">lerna</a> and standard commit we don’t need to manage ourselves all that.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">npm i --save-dev lerna\n./node_modules/.bin/lerna init</code></pre></div>\n<p>This will install <em>lerna</em> in our repository and initialise it. In order for lerna to work we have to modify the file <code class=\"language-text\">lerna.json</code> that was just created:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">{\n  &quot;lerna&quot;: &quot;2.7.0&quot;,\n  &quot;packages&quot;: [\n    &quot;libs/*&quot;\n  ],\n  &quot;version&quot;: &quot;0.0.0&quot;\n}</code></pre></div>\n<p>Add another extra script:</p>\n<script src=\"https://gist.github.com/izifortune/1c6f638c48c594a866f3bc9f4ac2d2be.js\"></script>\n<p>And the last npm script:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&quot;prerelease&quot;: &quot;lerna publish --skip-npm&quot;,\n&quot;release&quot;: &quot;node ./scripts/libs-publish.js&quot;,</code></pre></div>\n<p>The <code class=\"language-text\">prerelease</code> script will take care of increasing the version of our libraries, commit our changes and tag also the commit. Notice that we are passing the flag <code class=\"language-text\">--skip-npm</code> because the actual publishing of our libraries will be done by our script.</p>\n<p>Using a tool like <a href=\"commitizen.github.io/cz-cli/\">commitizen</a> you can also add the flag <code class=\"language-text\">--conventional-commits</code> which will calculate automatically your next version based upon your commit message.</p>\n<p>If you are dying to start using it for your libraries here’s a link to a repository with all the steps already in place.</p>\n<p><a href=\"https://github.com/izifortune/nrwl-packagr\">https://github.com/izifortune/nrwl-packagr</a></p>\n<p>Enjoy!</p>","frontmatter":{"title":"Multiple packages repository with Angular","date":"January 18, 2018","description":null,"socialImage":{"childImageSharp":{"fixed":{"src":"/dist/static/1854f16a71123340b9ebc020ecf346e7/048fd/nrwl-nx-ng-packagr-1.png"}}},"image":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAIAAAC9o5sfAAAACXBIWXMAAAsSAAALEgHS3X78AAABH0lEQVQoz2PQLT+OhrQrTijVX1Csv2hafMCw9LBiw2XV2vM6FScwVTJgChmWHI4Onz/dIPcki8N6HtdayzLvuJV6ZccIaNYvO6pSez7Xe8JzBo2XDJq3bTVP6qidYVA7xqDjkbhGveYsmhGYms/Fh815yqBzyUXj2lXPSwccD2tq7GcwccjcolF9Br/mY2q1Z33i1t4R1j9zWOHcac1bjyMuLzdZJ2BnkbdXu+okPs1AOY3q005ZW28zmN2wVb10zf3cfofT8gqrhD2BjtIBqTmGL8B0yk8YlB5ZoJn6nEH7roXaKU1VoIcrbKox3Yw1tI8BY0W9+kxi2OwdPH5zJCO8klaq15zDDGrsUQVxm2L9Jb3yo0B/qtRdwBpPQAQAzeP4qrtVBFsAAAAASUVORK5CYII=","aspectRatio":2.287671232876712,"src":"/dist/static/4ae32e8228d4b6f7529f1b0ef36d2294/a5924/nrwl-nx-ng-packagr-2.png","srcSet":"/dist/static/4ae32e8228d4b6f7529f1b0ef36d2294/17cc0/nrwl-nx-ng-packagr-2.png 167w,\n/dist/static/4ae32e8228d4b6f7529f1b0ef36d2294/f7869/nrwl-nx-ng-packagr-2.png 333w,\n/dist/static/4ae32e8228d4b6f7529f1b0ef36d2294/a5924/nrwl-nx-ng-packagr-2.png 666w,\n/dist/static/4ae32e8228d4b6f7529f1b0ef36d2294/bc46a/nrwl-nx-ng-packagr-2.png 673w","sizes":"(max-width: 666px) 100vw, 666px"}}}}}},"pageContext":{"slug":"/multiple-packages-repository-with-angular/","previous":{"fields":{"slug":"/managing-modules-with-angular/"},"frontmatter":{"title":"Managing modules with Angular"}},"next":{"fields":{"slug":"/performance-budgets-with-lighthouse-lighthouse-keeper/"},"frontmatter":{"title":"Performance budgets with Lighthouse - Lighthouse keeper"}}}}}