<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: jogelin</title>
    <description>The latest articles on Forem by jogelin (@jogelin).</description>
    <link>https://forem.com/jogelin</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F145797%2F2a55b03a-a367-4308-9b79-e6ecfac41696.jpg</url>
      <title>Forem: jogelin</title>
      <link>https://forem.com/jogelin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jogelin"/>
    <language>en</language>
    <item>
      <title>🍒 Cherry-Picked Nx v19.1 Updates</title>
      <dc:creator>jogelin</dc:creator>
      <pubDate>Mon, 27 May 2024 07:48:04 +0000</pubDate>
      <link>https://forem.com/jogelin/cherry-picked-nx-v191-updates-275f</link>
      <guid>https://forem.com/jogelin/cherry-picked-nx-v191-updates-275f</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/nrwl/nx/releases/tag/19.1.0"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flfir0a8ckoy9ks3oom0m.png" alt="Image description" width="800" height="213"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;[🌊 Nx Core]&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Typescript declarations support for esbuild libraries&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You can see &lt;a href="https://nx.dev/nx-api/esbuild/executors/esbuild#declaration"&gt;two new properties&lt;/a&gt; in the &lt;code&gt;@nx/esbuild:esbuild&lt;/code&gt; executor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;build&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;executor&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@nx/esbuild:esbuild&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;options&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;declaration&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;declarationRootDir&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;libs/my-lib/src&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// root by default&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Generate declaration (*.d.ts) files for every TypeScript or JavaScript file inside your project. Should be used for libraries that are published to an npm repository.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;New separator option for the result of the nx show command&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://nx.dev/nx-api/nx/documents/show"&gt;https://nx.dev/nx-api/nx/documents/show&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;nx&lt;/span&gt; &lt;span class="nx"&gt;show&lt;/span&gt; &lt;span class="nx"&gt;projects&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;affected&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;sep&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Target another executor in schema definitions&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Angular 18 introduced a way to &lt;a href="https://github.com/angular/angular-cli/blob/c33629e3417f87685a6f75b36cb864a2cd8a55e3/packages/angular_devkit/build_angular/builders.json#L4"&gt;map one builder to another one&lt;/a&gt;. It is also now possible to use that approach with Nx in the &lt;code&gt;executors.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;executors&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// New&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;build&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@org/my-plugin:build&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="c1"&gt;// Current&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;serve&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;implementation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;schema&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;description&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Support bun Package Manager!&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;First, install &lt;code&gt;bun&lt;/code&gt; by &lt;a href="https://bun.sh/docs/installation"&gt;following the documentation&lt;/a&gt;. Then you can generate a new Nx workspace by using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;bunx&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;nx&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;workspace&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F92ylbd3g7262ht45iftt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F92ylbd3g7262ht45iftt.png" alt="Image description" width="800" height="683"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;[💫 Upgrades]&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Support Angular 18&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://blog.angular.dev/angular-v18-is-now-available-e79d5ac0affe"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb69a624fm0czdgzapts0.png" alt="Image description" width="800" height="210"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Looking for some help?&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;🤝&lt;/em&gt;&lt;em&gt;Connect with me on&lt;/em&gt; &lt;a href="https://twitter.com/jonathan_gelin"&gt;&lt;strong&gt;&lt;em&gt;Twitter&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; &lt;em&gt;•&lt;/em&gt; &lt;a href="https://www.linkedin.com/in/jonathan-gelin/"&gt;&lt;strong&gt;&lt;em&gt;LinkedIn&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; &lt;em&gt;•&lt;/em&gt; &lt;a href="https://github.com/jogelin"&gt;&lt;strong&gt;&lt;em&gt;Github&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Related&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://jgelin.medium.com/the-nx-series-d83b92185539"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxde8flkefkaw405vk004.png" alt="Image description" width="800" height="210"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nx</category>
      <category>monorepo</category>
      <category>angular</category>
      <category>javascript</category>
    </item>
    <item>
      <title>🍒 Cherry-Picked Nx v19 Updates</title>
      <dc:creator>jogelin</dc:creator>
      <pubDate>Mon, 27 May 2024 07:42:07 +0000</pubDate>
      <link>https://forem.com/jogelin/cherry-picked-nx-v19-updates-23h9</link>
      <guid>https://forem.com/jogelin/cherry-picked-nx-v19-updates-23h9</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Release Note 19 (2024–05–06)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/nrwl/nx/releases/tag/19.0.0"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgntztp74u86psyhl50uv.png" alt="Image description" width="800" height="246"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;[🌊 Nx Core]&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Metadata Property in Project Configuration&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Already covered in &lt;a href="https://medium.com/javascript-in-plain-english/cherry-picked-nx-v18-3-updates-0502ff485629"&gt;my previous blog post on v18.3&lt;/a&gt;, Nx introduced a new &lt;code&gt;metadata&lt;/code&gt; property in the &lt;code&gt;project.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-java-project&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;metadata&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;technologies&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;java17&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ciRunner&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ubuntu-20.04-m6a.large&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;owners&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;backend-team&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Nx v19, you’ll be able to generate these metadata directly from your plugins:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createMetadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CreateMetadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ProjectsMetadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-java-project&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;technologies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;java17&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;ciRunner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ubuntu-20.04-m6a.large&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;owners&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;backend-team&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This opens many possibilities for project customization like listing technologies or the runner you want to use on your CI.&lt;/p&gt;

&lt;p&gt;It also helps define a project type described in my article &lt;a href="https://medium.com/javascript-in-plain-english/reproducible-nx-workspace-with-hugenxs-conventions-a247c0541049"&gt;👥 Reproducible Nx Workspace with HugeNx’s Conventions&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Change imports for the Webpack plugin&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;It is always a better idea not to expose all utilities in the same &lt;code&gt;index.ts&lt;/code&gt; especially when they are not related. It has an impact on the config loading for example.&lt;/p&gt;

&lt;p&gt;Here is a good decision from &lt;a href="https://medium.com/u/2817fb68583"&gt;Nx&lt;/a&gt; related to Webpack configurations:&lt;/p&gt;

&lt;p&gt;Before&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NxAppWebpackPlugin&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nx/webpack&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NxReactWebpackPlugin&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nx/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NxAppWebpackPlugin&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nx/webpack/app-plugin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NxReactWebpackPlugin&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nx/react/webpack-plugin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Global forwardAllArgs for nx:run-commands&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Before, when you had multiple commands in your &lt;code&gt;nx:run-commands&lt;/code&gt; executor, you had to specify for each command if you wanted or not to forward arguments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;configure-branch-environment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;executor&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nx:run-commands&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;options&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;commands&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;command&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;echo &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;BRANCH=$(git branch --show-current)&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; &amp;gt; .local.env&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;forwardAllArgs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; 
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;command&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;echo &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;COMMIT_SHA=$(git rev-parse HEAD)&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; &amp;gt;&amp;gt; .local.env&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;forwardAllArgs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;command&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ls&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;forwardAllArgs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; 
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;command&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cat .local.env&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;forwardAllArgs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; 
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cwd&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{projectRoot}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can specify it globally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;configure-branch-environment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;executor&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nx:run-commands&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;options&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;commands&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;echo &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;BRANCH=$(git branch --show-current)&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; &amp;gt; .local.env&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;echo &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;COMMIT_SHA=$(git rev-parse HEAD)&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; &amp;gt;&amp;gt; .local.env&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ls&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cat .local.env&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cwd&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{projectRoot}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;forwardAllArgs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;[💎 Project Crystal]&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Add generators to convert projects to inferred targets&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://nx.dev/nx-api/cypress/generators/convert-to-inferred"&gt;https://nx.dev/nx-api/cypress/generators/convert-to-inferred&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://nx.dev/nx-api/eslint/generators/convert-to-inferred"&gt;https://nx.dev/nx-api/eslint/generators/convert-to-inferred&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://nx.dev/nx-api/playwright/generators/convert-to-inferred"&gt;https://nx.dev/nx-api/playwright/generators/convert-to-inferred&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;[💫 Upgrades]&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://rollupjs.org/migration/"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzebwi59uc1lspjvvi8pv.png" alt="Image description" width="800" height="246"&gt;&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Support React 18.3&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/facebook/react/blob/main/CHANGELOG.md"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2picw75r05v7po7kf9xj.png" alt="Image description" width="800" height="250"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;[🌐 nx.dev]&lt;/strong&gt;
&lt;/h2&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Main Navigation Menu&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhcijj90ocro1ntef35q0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhcijj90ocro1ntef35q0.png" alt="Image description" width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;New Blog Page&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://nx.dev/blog"&gt;https://nx.dev/blog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8erv4v82kbfms8eo4sai.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8erv4v82kbfms8eo4sai.png" alt="Image description" width="800" height="786"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;New Enterprise Page&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://nx.dev/enterprise"&gt;https://nx.dev/enterprise&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm8e16vy4au8n3vlq0klx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm8e16vy4au8n3vlq0klx.png" alt="Image description" width="800" height="524"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;[☁️ Nx Cloud]&lt;/strong&gt;
&lt;/h2&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;DTE v2&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://nx.dev/ci/reference/release-notes#dte-algorithm-v2-experimental-flag"&gt;https://nx.dev/ci/reference/release-notes#dte-algorithm-v2-experimental-flag&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;NX_CLOUD_DTE_V2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Looking for some help?&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;🤝&lt;/em&gt;&lt;em&gt;Connect with me on&lt;/em&gt; &lt;a href="https://twitter.com/jonathan_gelin"&gt;&lt;strong&gt;&lt;em&gt;Twitter&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; &lt;em&gt;•&lt;/em&gt; &lt;a href="https://www.linkedin.com/in/jonathan-gelin/"&gt;&lt;strong&gt;&lt;em&gt;LinkedIn&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; &lt;em&gt;•&lt;/em&gt; &lt;a href="https://github.com/jogelin"&gt;&lt;strong&gt;&lt;em&gt;Github&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Related&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://jgelin.medium.com/the-nx-series-d83b92185539"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxde8flkefkaw405vk004.png" alt="Image description" width="800" height="210"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nx</category>
      <category>monorepo</category>
      <category>angular</category>
      <category>javascript</category>
    </item>
    <item>
      <title>👥 Reproducible Nx Workspace with HugeNx’s Conventions</title>
      <dc:creator>jogelin</dc:creator>
      <pubDate>Sun, 05 May 2024 06:13:02 +0000</pubDate>
      <link>https://forem.com/jogelin/reproducible-nx-workspace-with-hugenxs-conventions-8hm</link>
      <guid>https://forem.com/jogelin/reproducible-nx-workspace-with-hugenxs-conventions-8hm</guid>
      <description>&lt;p&gt;After migrating multiple organizations to an Nx Monorepo and maintaining it, I discovered that with each major Nx version, I was &lt;strong&gt;generating&lt;/strong&gt; a new repository on the side, &lt;strong&gt;mimicking my existing repo&lt;/strong&gt;, to compare configuration files and ensure they matched the latest version of Nx.&lt;/p&gt;

&lt;p&gt;However, recreating an entire repo to mirror my original was labor-intensive. I began using Bash scripts, then Node.js scripts, and finally, I developed &lt;strong&gt;HugeNx&lt;/strong&gt;, a &lt;strong&gt;custom Nx preset&lt;/strong&gt; that generates a workspace from a configuration file.&lt;/p&gt;

&lt;p&gt;After further reflection, I realized I wasn’t just creating a file to generate a workspace; I was crafting a file that would describe &lt;strong&gt;workspace conventions&lt;/strong&gt; and could be utilized for many other purposes.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/jogelin" rel="noopener noreferrer"&gt;
        jogelin
      &lt;/a&gt; / &lt;a href="https://github.com/jogelin/huge-nx" rel="noopener noreferrer"&gt;
        huge-nx
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Huge&lt;a alt="Nx logo" href="https://nx.dev" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnrwl%2Fnx%2Fmaster%2Fimages%2Fnx-logo.png" width="45"&gt;&lt;/a&gt;
&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://github.com/jogelin/huge-nx/actions/workflows/ci.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/jogelin/huge-nx/actions/workflows/ci.yml/badge.svg" alt="CI"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HugeNx&lt;/strong&gt; is a toolkit designed to dynamically generate and manage &lt;a href="https://nx.dev/" rel="nofollow noopener noreferrer"&gt;Nx workspaces&lt;/a&gt; by adhering to established workspace conventions.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://jgelin.medium.com/reproducible-nx-workspace-with-hugenxs-conventions-a247c0541049" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fjogelin%2Fhuge-nx.%2Fdoc%2Fimages%2Farticle.png" alt="Article"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting Started&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;1. Define your HugeNx's conventions:&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;For example let's create a conventions file &lt;code&gt;angular-monorepo.conventions.ts&lt;/code&gt; that match the default &lt;a href="https://nx.dev/getting-started/tutorials/angular-monorepo-tutorial#creating-a-new-angular-monorepo" rel="nofollow noopener noreferrer"&gt;Nx angular-monorepo preset&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight highlight-source-ts notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;export&lt;/span&gt; &lt;span class="pl-k"&gt;default&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
  &lt;span class="pl-c1"&gt;version&lt;/span&gt;: &lt;span class="pl-s"&gt;'1.0'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
  &lt;span class="pl-c1"&gt;generators&lt;/span&gt;: &lt;span class="pl-kos"&gt;{&lt;/span&gt;
    &lt;span class="pl-s"&gt;'@nx/angular:application'&lt;/span&gt;: &lt;span class="pl-kos"&gt;{&lt;/span&gt;
      &lt;span class="pl-c1"&gt;bundler&lt;/span&gt;: &lt;span class="pl-s"&gt;'esbuild'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-s"&gt;'@nx/angular:library'&lt;/span&gt;: &lt;span class="pl-kos"&gt;{&lt;/span&gt;
      &lt;span class="pl-c1"&gt;linter&lt;/span&gt;: &lt;span class="pl-s"&gt;'eslint'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
      &lt;span class="pl-c1"&gt;unitTestRunner&lt;/span&gt;: &lt;span class="pl-s"&gt;'jest'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
  &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
  &lt;span class="pl-c1"&gt;projectTypes&lt;/span&gt;: &lt;span class="pl-kos"&gt;{&lt;/span&gt;
    &lt;span class="pl-s"&gt;'global:angular:application'&lt;/span&gt;: &lt;span class="pl-kos"&gt;{&lt;/span&gt;
      &lt;span class="pl-c1"&gt;projectPattern&lt;/span&gt;: &lt;span class="pl-s"&gt;'*-app'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
      &lt;span class="pl-c1"&gt;generators&lt;/span&gt;: &lt;span class="pl-kos"&gt;[&lt;/span&gt;&lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-c1"&gt;generator&lt;/span&gt;: &lt;span class="pl-s"&gt;'@nx/angular:application'&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;]&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-s"&gt;'global:angular:lib:feature'&lt;/span&gt;: &lt;span class="pl-kos"&gt;{&lt;/span&gt;
      &lt;span class="pl-c1"&gt;projectPattern&lt;/span&gt;: &lt;span class="pl-s"&gt;'*-feature'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
      &lt;span class="pl-c1"&gt;generators&lt;/span&gt;: &lt;span class="pl-kos"&gt;[&lt;/span&gt;&lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-c1"&gt;generator&lt;/span&gt;: &lt;span class="pl-s"&gt;'@nx/angular:library'&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;]&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
  &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
  &lt;span class="pl-c1"&gt;workspace&lt;/span&gt;: &lt;span class="pl-kos"&gt;{&lt;/span&gt;
    &lt;span class="pl-c1"&gt;apps&lt;/span&gt;: &lt;span class="pl-kos"&gt;{&lt;/span&gt;
      &lt;span class="pl-s"&gt;'my-app'&lt;/span&gt;: &lt;span class="pl-s"&gt;'global:angular:application'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-c1"&gt;libs&lt;/span&gt;: &lt;span class="pl-kos"&gt;{&lt;/span&gt;
      &lt;span class="pl-s"&gt;'my-feature'&lt;/span&gt;: &lt;span class="pl-s"&gt;'global:angular:lib:feature'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
  &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;2. Use &lt;a href="https://www.npmjs.com/package/create-huge-nx" rel="nofollow noopener noreferrer"&gt;create-huge-nx&lt;/a&gt; client to generate&lt;/h3&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/jogelin/huge-nx" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;HugeNx’s Conventions&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The main concept behind this library is the &lt;strong&gt;HugeNx’s Conventions&lt;/strong&gt; file — a configuration file that &lt;strong&gt;groups all conventional decisions&lt;/strong&gt; you’ve made about your Nx workspace. This file will describe how your workspace should look.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkjr0twjywnve3sg7x697.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkjr0twjywnve3sg7x697.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If &lt;strong&gt;HugeNx’s Conventions&lt;/strong&gt; file contains all the information on your targeted workspace, it means you can &lt;strong&gt;generate a new workspace from scratch&lt;/strong&gt; or &lt;strong&gt;even maintain an existing one&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;ProjectTypes&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The first main convention I wanted to integrate is the concept of Nx &lt;strong&gt;ProjectType&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When you delve into the various resources about structuring an Nx workspace, you’ll encounter extensive explanations on categorizing your library by scope or type and creating tags that establish your boundaries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://nx.dev/concepts/more-concepts/monorepo-nx-enterprise#code-organization-naming-conventions" rel="noopener noreferrer"&gt;Code Organization &amp;amp; Naming Conventions&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://nx.dev/concepts/more-concepts/library-types#library-types" rel="noopener noreferrer"&gt;Library Types&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/angular-architects/nx-ddd-plugin/blob/main/libs/ddd/README.md" rel="noopener noreferrer"&gt;Domain Driven Design&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, I always missed a centralized way to specify this list of &lt;strong&gt;ProjectTypes&lt;/strong&gt;. When you generate a project you lose the link with its source generator and its related technologies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fid7m92f4o0v0r0qwvqsa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fid7m92f4o0v0r0qwvqsa.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is why I wanted to keep that information. With the help of &lt;strong&gt;HugeNx’s Conventions&lt;/strong&gt;, you can recognize your projects because they will follow the conventions you specified in them.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I already explain the importance of conventions in my article ⚡&lt;/em&gt; &lt;a href="https://medium.com/@jgelin/the-super-power-of-conventions-with-nx-8d418150b679" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;em&gt;The Super Power of Conventions with Nx&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;&lt;em&gt;.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Reproducible Generation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;When you start a project with Nx, everything is &lt;strong&gt;clean&lt;/strong&gt; and &lt;strong&gt;aligned&lt;/strong&gt;. But after some years we apply migrations, create custom generators, manually modify configurations, etc. All of that, coupled with developer turnover, and you end up with a good &lt;a href="http://ki/Ratatouille#:~:text=The%20word%20ratatouille%20derives%20from,merely%20indicated%20a%20coarse%20stew." rel="noopener noreferrer"&gt;&lt;strong&gt;Ratatouille&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is a common challenge we try to solve in IT, especially at the infrastructure level with the concept of &lt;a href="https://en.wikipedia.org/wiki/Infrastructure_as_code" rel="noopener noreferrer"&gt;&lt;strong&gt;infrastructure as code&lt;/strong&gt;&lt;/a&gt;. The usage of tools like &lt;a href="https://en.wikipedia.org/wiki/Ansible_(software)" rel="noopener noreferrer"&gt;Ansible&lt;/a&gt; allows us to initialize and reconfigure an entire infrastructure from scripts and configuration files.&lt;/p&gt;

&lt;p&gt;With Nx, you can use the &lt;a href="https://nx.dev/nx-api/nx/documents/create-nx-workspace#preset" rel="noopener noreferrer"&gt;list of presets&lt;/a&gt;, but it is &lt;a href="https://github.com/nrwl/nx/blob/master/packages/workspace/src/generators/preset/preset.ts" rel="noopener noreferrer"&gt;&lt;strong&gt;hardcoded&lt;/strong&gt;&lt;/a&gt;. There is some &lt;strong&gt;flexibility&lt;/strong&gt; for each with some options, but &lt;strong&gt;not enough&lt;/strong&gt; to generate a more advanced workspace.&lt;/p&gt;

&lt;p&gt;If you want to create a &lt;strong&gt;more advanced workspace&lt;/strong&gt;, you’ll need t&lt;a href="https://nx.dev/extending-nx/recipes/create-preset" rel="noopener noreferrer"&gt;o create your custom preset&lt;/a&gt;. It is useful for creating a seed but not for quickly generating a workspace &lt;strong&gt;for comparison&lt;/strong&gt;, demo, or workshop; it can be &lt;strong&gt;cumbersome&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is why I decided to create a custom Nx preset that can generate an Nx workspace just by using &lt;strong&gt;HugeNx’s Conventions&lt;/strong&gt;. You don’t need to create or maintain your own preset!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffz2gei29nhzoy3wqqi0i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffz2gei29nhzoy3wqqi0i.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can regenerate your entire repository for &lt;strong&gt;any Nx version&lt;/strong&gt;. This would help for comparing what changed and also for &lt;strong&gt;simplifying&lt;/strong&gt; the way we currently create &lt;strong&gt;Nx presets&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HugeNx&lt;/strong&gt; supports all Nx plugins so you can easily reproduce all Nx presets and even create your custom preset.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Consistent Monorepo&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Generating your repository from scratch is good, but being able to &lt;strong&gt;maintain&lt;/strong&gt; it for a long time is even &lt;strong&gt;better&lt;/strong&gt;, right?&lt;/p&gt;

&lt;p&gt;The main goal of &lt;strong&gt;HugeNx’s Conventions&lt;/strong&gt; is to be the guardian, the &lt;strong&gt;housekeeper&lt;/strong&gt; that will describe how your &lt;strong&gt;workspace should look&lt;/strong&gt; and behave.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkh3z88iqz4eaoz1fyznz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkh3z88iqz4eaoz1fyznz.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Eslint Conventions Rules&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
With the help of tools like &lt;strong&gt;Eslint&lt;/strong&gt;, you can read that file and create rules to &lt;strong&gt;enforce conventions&lt;/strong&gt; and:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Validate that each project follows the &lt;strong&gt;naming conventions&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Validate the &lt;strong&gt;workspace structure&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Validate that each project is correctly &lt;strong&gt;related to one ProjectType&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Validate the &lt;code&gt;nx.json&lt;/code&gt; generator’s options&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Project Discovering&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
With the project inference provided by the &lt;a href="https://nx.dev/concepts/inferred-tasks" rel="noopener noreferrer"&gt;&lt;strong&gt;Nx Project Crystal&lt;/strong&gt;&lt;/a&gt;, you can easily discover your Nx project based on your naming convention.&lt;/p&gt;

&lt;p&gt;You can also create one &lt;strong&gt;Nx plugin&lt;/strong&gt; that matches the &lt;strong&gt;ProjectType&lt;/strong&gt; naming convention and attach the &lt;strong&gt;project configuration&lt;/strong&gt; automatically!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Migration:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Related to the fact that you can &lt;strong&gt;regenerate&lt;/strong&gt; a new workspace from scratch for a specific Nx version, you can now easily generate a workspace with the &lt;strong&gt;latest Nx&lt;/strong&gt; and &lt;strong&gt;compare it with your workspace&lt;/strong&gt;.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://snappify.com/view/69bea243-e514-4ce8-b0f1-993ff2b3c392" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frdneegrwaqluqlbqohmj.supabase.co%2Fstorage%2Fv1%2Fobject%2Fpublic%2Fteam-snap-previews%2F8850277b-735a-4d0e-998f-cea0574a5f05%2F69bea243-e514-4ce8-b0f1-993ff2b3c392.png%3Ft%3D1728070900026" height="auto" class="m-0"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://snappify.com/view/69bea243-e514-4ce8-b0f1-993ff2b3c392" rel="noopener noreferrer" class="c-link"&gt;
          huge-nx - snappify.com
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          A powerful design tool to animate your code snippets in various ways.
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsnappify.com%2Fimages%2Ffavicon-196.png"&gt;
        snappify.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;You can also use tools like &lt;a href="https://phenomnomnominal.github.io/betterer/" rel="noopener noreferrer"&gt;Betterer&lt;/a&gt; if you want to migrate step by step your repository to your &lt;strong&gt;HugeNx’s Conventions.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ProjectType Generator&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
There is &lt;strong&gt;no need&lt;/strong&gt; to create and maintain &lt;strong&gt;complex custom generators&lt;/strong&gt;. You can create a generator that will read your &lt;strong&gt;ProjectTypes&lt;/strong&gt; and generate a project from it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Stay tuned for future implementations of the HugeNx tools for consistent monorepo.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Let’s Generate Your Workspace&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Let’s start with a concrete example by creating a new TypeScript file that will represent your workspace.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;1. Define your conventions&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You can create a file &lt;code&gt;huge-angular-full-stack.conventions.ts&lt;/code&gt; that will contain a workspace with a &lt;strong&gt;full-stack application&lt;/strong&gt; to manage a &lt;strong&gt;Hotel&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;generators&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nx/angular:application&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;//&amp;lt;-- Generator Identifier&lt;/span&gt;
      &lt;span class="na"&gt;linter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eslint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//&amp;lt;-- List of options&lt;/span&gt;
      &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;unitTestRunner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;bundler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;esbuild&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;e2eTestRunner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;playwright&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;inlineStyle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;inlineTemplate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nx/angular:library&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;linter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eslint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;unitTestRunner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nx/angular:component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nx/js:lib&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;bundler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;swc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;projectTypes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;global:angular:app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;//&amp;lt;-- ProjectType Identifier&lt;/span&gt;
      &lt;span class="na"&gt;projectPattern&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*-app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//&amp;lt;-- Pattern matching your naming convention&lt;/span&gt;
      &lt;span class="na"&gt;generators&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nx/angular:application&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt; &lt;span class="c1"&gt;//&amp;lt;-- List of generators used to generate that type of project&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;backend:api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;projectPattern&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*-api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;generators&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nx/nest:application&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;global:angular:lib:data-access&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;projectPattern&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*-data-access&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;generators&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nx/angular:library&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;global:angular:lib:feature&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;projectPattern&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*-feature&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;generators&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nx/angular:library&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;global:angular:lib:ui:storybook&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;//&amp;lt;-- This ProjectType generates a library then a storybook configuration&lt;/span&gt;
      &lt;span class="na"&gt;projectPattern&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*-ui&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;generators&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nx/angular:library&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nx/storybook:configuration&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;uiFramework&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@storybook/angular&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;global:ts:lib:utils&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;projectPattern&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*-utils&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;generators&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nx/js:lib&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;bundler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;swc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;workspace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;//&amp;lt;-- The workspace is structured by folders and projects&lt;/span&gt;
    &lt;span class="na"&gt;apps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;//&amp;lt;-- Generates a folder apps&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hotel-app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;global:angular:app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//&amp;lt;-- Generates a project hotel-app by using the project type global:angular:app&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hotel-api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;//&amp;lt;-- Generates a project hotel-api by using the project type backend:api and extra options&lt;/span&gt;
        &lt;span class="na"&gt;projectType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;backend:api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nx/angular:remote&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;frontendProject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hotel-app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;libs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;//&amp;lt;-- Generates a folder libs&lt;/span&gt;
      &lt;span class="na"&gt;guest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;//&amp;lt;-- Generates a folder guest&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-access&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;global:angular:lib:data-access&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//&amp;lt;-- Generates a project guest-data-access by using the project type global:angular:lib:data-access&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;booking-feature&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;global:angular:lib:feature&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//&amp;lt;-- Generates a project guest-booking-feature by using the project type global:angular:lib:feature&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;feedback-feature&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;global:angular:lib:feature&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//&amp;lt;-- Generates a project guest-feedback-feature by using the project type global:angular:lib:feature&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;room&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;//&amp;lt;-- Generates a folder room&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-access&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;global:angular:lib:data-access&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;list-feature&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;global:angular:lib:feature&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;request-feature&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;global:angular:lib:feature&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;//&amp;lt;-- Generates a folder shared&lt;/span&gt;
        &lt;span class="na"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;//&amp;lt;-- Generates a project shared-ui by using the project type global:angular:lib:ui:storybook and extra options&lt;/span&gt;
          &lt;span class="na"&gt;projectType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;global:angular:lib:ui:storybook&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nx/storybook:configuration&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;shared-ui&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;global:ts:lib:utils&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;The Default Generator Options&lt;/strong&gt;&lt;br&gt;
This is nothing new and is already available in &lt;a href="https://medium.com/u/2817fb68583" rel="noopener noreferrer"&gt;Nx&lt;/a&gt; by configuring your &lt;a href="https://nx.dev/reference/nx-json#generators" rel="noopener noreferrer"&gt;&lt;code&gt;nx.json&lt;/code&gt;&lt;/a&gt; file. You can define default options for each generator that you are using in your workspace.&lt;/p&gt;

&lt;p&gt;All Nx options can be found in the &lt;a href="https://nx.dev/nx-api" rel="noopener noreferrer"&gt;Nx API Documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The List of ProjectTypes&lt;/strong&gt;&lt;br&gt;
Here you’ll define your &lt;strong&gt;list of ProjectType&lt;/strong&gt; based on the technologies, the domain, the type of library, the team, etc.&lt;/p&gt;

&lt;p&gt;For each &lt;strong&gt;ProjectType&lt;/strong&gt;, you’ll specify which generators should be used and all conventions around them. It will use the &lt;strong&gt;Default Generator Options&lt;/strong&gt;, and you can add extra options if needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your Workspace Structure&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Finally, you’ll define your list of projects inside a &lt;strong&gt;workspace layout&lt;/strong&gt;. Each project will be linked and described by a specific &lt;strong&gt;ProjectType&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That section is required for the generation but &lt;strong&gt;not required for the maintenance&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;2. Use create-huge-nx CLI&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;If you want to generate your workspace, you can now use the &lt;strong&gt;HugeNx CLI&lt;/strong&gt; by calling:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;npx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;create-huge-nx@latest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;my-workspace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;--hugeNxConventions=./huge-angular-full-stack.conventions.ts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;--nxCloud&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;skip&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;It will generate a workspace that will look like:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;my-workspace/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;├─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;apps/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;├─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;hotel-api/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;├─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;hotel-api-e&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="err"&gt;e/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;├─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;hotel-app/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;└─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;hotal-app-e&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="err"&gt;e/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;libs/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;├─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;guest/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;├─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;data-access&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;├─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;booking-feature&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;└─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;feedback-feature&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;├─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;room/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;├─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;data-access&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;├─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;list-feature&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;└─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;request-feature&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;└─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;shared/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="err"&gt;├─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ui&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="err"&gt;└─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;utils&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;├─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;nx.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;├─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;package.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;├─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;jest.config.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;└─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;huge-nx.conventions.ts&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;By default, the latest version of Nx will be used but you can generate a workspace with a specific Nx version with &lt;code&gt;--nxVersion&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npx create-huge-nx@latest my-workspace &lt;span class="nt"&gt;--nxVersion&lt;/span&gt; 17 &lt;span class="nt"&gt;--hugeNxConventions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./huge-angular-full-stack.conventions.ts &lt;span class="nt"&gt;--nxCloud&lt;/span&gt; skip


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;More presets&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;It’s now straightforward to create various types of repositories simply by introducing a new &lt;code&gt;huge-nx.conventions.ts&lt;/code&gt; file. This approach not only encompasses all Nx presets but also allows you to describe each type of project in detail, as outlined in the &lt;a href="https://nx.dev/concepts/more-concepts/library-types#library-types" rel="noopener noreferrer"&gt;library types section&lt;/a&gt; of the Nx documentation.&lt;/p&gt;

&lt;p&gt;For instance, you can define the types from the &lt;a href="https://www.npmjs.com/package/@angular-architects/ddd" rel="noopener noreferrer"&gt;&lt;code&gt;@angular-architects/ddd&lt;/code&gt;&lt;/a&gt; package and then use this definition to generate a workspace. This flexibility allows for a highly customized setup that caters to the specific needs of your project, leveraging Nx's powerful and extensible tooling ecosystem.&lt;/p&gt;

&lt;p&gt;I also used ChatGPT to generate my convention files. I just provided an example of the file and specify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It represents an Nx workspace&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Should use Angular generators&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Represent Hotel Business&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Should be a full-stack app&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Final Thoughts&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;HugeNx’s Conventions&lt;/strong&gt; aim to provide a useful tool in the Nx landscape, particularly for those managing large and evolving monorepos.&lt;/p&gt;

&lt;p&gt;By automating and standardizing workspace setups, it helps reduce the complexity often associated with project generation and maintenance. For me, this approach helped me save time and effort in my migration process.&lt;/p&gt;

&lt;p&gt;I am looking forward to improving HugeNx based on your feedback. I hope it will be a valuable addition to your development toolkit. Your insights and experiences are crucial to refining this tool, so please share your thoughts.&lt;/p&gt;

&lt;p&gt;Stay tuned! 🚀&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/jogelin" rel="noopener noreferrer"&gt;
        jogelin
      &lt;/a&gt; / &lt;a href="https://github.com/jogelin/huge-nx" rel="noopener noreferrer"&gt;
        huge-nx
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Huge&lt;a alt="Nx logo" href="https://nx.dev" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnrwl%2Fnx%2Fmaster%2Fimages%2Fnx-logo.png" width="45"&gt;&lt;/a&gt;
&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://github.com/jogelin/huge-nx/actions/workflows/ci.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/jogelin/huge-nx/actions/workflows/ci.yml/badge.svg" alt="CI"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HugeNx&lt;/strong&gt; is a toolkit designed to dynamically generate and manage &lt;a href="https://nx.dev/" rel="nofollow noopener noreferrer"&gt;Nx workspaces&lt;/a&gt; by adhering to established workspace conventions.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://jgelin.medium.com/reproducible-nx-workspace-with-hugenxs-conventions-a247c0541049" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fjogelin%2Fhuge-nx.%2Fdoc%2Fimages%2Farticle.png" alt="Article"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting Started&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;1. Define your HugeNx's conventions:&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;For example let's create a conventions file &lt;code&gt;angular-monorepo.conventions.ts&lt;/code&gt; that match the default &lt;a href="https://nx.dev/getting-started/tutorials/angular-monorepo-tutorial#creating-a-new-angular-monorepo" rel="nofollow noopener noreferrer"&gt;Nx angular-monorepo preset&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight highlight-source-ts notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;export&lt;/span&gt; &lt;span class="pl-k"&gt;default&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
  &lt;span class="pl-c1"&gt;version&lt;/span&gt;: &lt;span class="pl-s"&gt;'1.0'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
  &lt;span class="pl-c1"&gt;generators&lt;/span&gt;: &lt;span class="pl-kos"&gt;{&lt;/span&gt;
    &lt;span class="pl-s"&gt;'@nx/angular:application'&lt;/span&gt;: &lt;span class="pl-kos"&gt;{&lt;/span&gt;
      &lt;span class="pl-c1"&gt;bundler&lt;/span&gt;: &lt;span class="pl-s"&gt;'esbuild'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-s"&gt;'@nx/angular:library'&lt;/span&gt;: &lt;span class="pl-kos"&gt;{&lt;/span&gt;
      &lt;span class="pl-c1"&gt;linter&lt;/span&gt;: &lt;span class="pl-s"&gt;'eslint'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
      &lt;span class="pl-c1"&gt;unitTestRunner&lt;/span&gt;: &lt;span class="pl-s"&gt;'jest'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
  &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
  &lt;span class="pl-c1"&gt;projectTypes&lt;/span&gt;: &lt;span class="pl-kos"&gt;{&lt;/span&gt;
    &lt;span class="pl-s"&gt;'global:angular:application'&lt;/span&gt;: &lt;span class="pl-kos"&gt;{&lt;/span&gt;
      &lt;span class="pl-c1"&gt;projectPattern&lt;/span&gt;: &lt;span class="pl-s"&gt;'*-app'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
      &lt;span class="pl-c1"&gt;generators&lt;/span&gt;: &lt;span class="pl-kos"&gt;[&lt;/span&gt;&lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-c1"&gt;generator&lt;/span&gt;: &lt;span class="pl-s"&gt;'@nx/angular:application'&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;]&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-s"&gt;'global:angular:lib:feature'&lt;/span&gt;: &lt;span class="pl-kos"&gt;{&lt;/span&gt;
      &lt;span class="pl-c1"&gt;projectPattern&lt;/span&gt;: &lt;span class="pl-s"&gt;'*-feature'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
      &lt;span class="pl-c1"&gt;generators&lt;/span&gt;: &lt;span class="pl-kos"&gt;[&lt;/span&gt;&lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-c1"&gt;generator&lt;/span&gt;: &lt;span class="pl-s"&gt;'@nx/angular:library'&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;]&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
  &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
  &lt;span class="pl-c1"&gt;workspace&lt;/span&gt;: &lt;span class="pl-kos"&gt;{&lt;/span&gt;
    &lt;span class="pl-c1"&gt;apps&lt;/span&gt;: &lt;span class="pl-kos"&gt;{&lt;/span&gt;
      &lt;span class="pl-s"&gt;'my-app'&lt;/span&gt;: &lt;span class="pl-s"&gt;'global:angular:application'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-c1"&gt;libs&lt;/span&gt;: &lt;span class="pl-kos"&gt;{&lt;/span&gt;
      &lt;span class="pl-s"&gt;'my-feature'&lt;/span&gt;: &lt;span class="pl-s"&gt;'global:angular:lib:feature'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
  &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;2. Use &lt;a href="https://www.npmjs.com/package/create-huge-nx" rel="nofollow noopener noreferrer"&gt;create-huge-nx&lt;/a&gt; client to generate&lt;/h3&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/jogelin/huge-nx" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;





&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Looking for some help?&lt;/strong&gt; 🤝&lt;br&gt;
**Connect with me on &lt;a href="https://twitter.com/jonathan_gelin" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;em&gt;Twitter&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; • &lt;a href="https://www.linkedin.com/in/jonathan-gelin/" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;em&gt;LinkedIn&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; • &lt;a href="https://github.com/jogelin" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;em&gt;Github&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>nx</category>
      <category>angular</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>🍒 Cherry-Picked Nx v18.3 Updates</title>
      <dc:creator>jogelin</dc:creator>
      <pubDate>Sun, 21 Apr 2024 06:36:10 +0000</pubDate>
      <link>https://forem.com/jogelin/cherry-picked-nx-v183-updates-58pp</link>
      <guid>https://forem.com/jogelin/cherry-picked-nx-v183-updates-58pp</guid>
      <description>&lt;h2&gt;
  
  
  Release Note 18.3 (2024–04–16)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/nrwl/nx/releases/tag/18.3.0"&gt;https://github.com/nrwl/nx/releases/tag/18.3.0&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  [Core] Metadata Property in Project Configuration
&lt;/h2&gt;

&lt;p&gt;This new &lt;code&gt;metadata&lt;/code&gt; property was introduced in &lt;a href="https://github.com/nrwl/nx/pull/22299"&gt;Nx 18.2&lt;/a&gt;. Initially, it was specified only at the project level. For example, for a project using Cypress, the &lt;code&gt;technologies&lt;/code&gt; and the &lt;code&gt;targetGroups&lt;/code&gt; were defined.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;targetGroups&lt;/code&gt; is &lt;a href="https://nx.dev/ci/features/split-e2e-tasks"&gt;used for sharding tests&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In &lt;a href="https://medium.com/u/2817fb68583"&gt;Nx&lt;/a&gt; &lt;strong&gt;v18.3&lt;/strong&gt;, you can specify the&lt;code&gt;metadata&lt;/code&gt; property at either a &lt;a href="https://nx.dev/nx-api/devkit/documents/ProjectConfiguration#metadata"&gt;&lt;strong&gt;project level&lt;/strong&gt;&lt;/a&gt; or a &lt;a href="https://nx.dev/nx-api/devkit/documents/TargetConfiguration#metadata"&gt;&lt;strong&gt;target level&lt;/strong&gt;&lt;/a&gt;. It is also more generic; any property name can be specified within it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-app-e2e"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"metadata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"targetGroups"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"E2E (CI)"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"e2e-ci--src/e2e/app.cy.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"e2e-ci"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"targets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"e2e"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"metadata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"technologies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"cypress"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Runs Cypress Tests"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"e2e-ci--src/e2e/app.cy.ts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"metadata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"technologies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"cypress"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Runs Cypress Tests in src/e2e/app.cy.ts in CI"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"e2e-ci"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"metadata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"technologies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"cypress"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Runs Cypress Tests in CI"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the moment it is used for &lt;a href="https://github.com/nrwl/nx/pull/22655/files"&gt;Cypress&lt;/a&gt;, &lt;a href="https://github.com/nrwl/nx/pull/22768"&gt;Playwright&lt;/a&gt;, and &lt;a href="https://github.com/nrwl/nx/pull/22662/files"&gt;Jest&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want to add extra information to your projects, such as Java technologies or others, I guess this is the correct place!&lt;/p&gt;

&lt;h2&gt;
  
  
  [Core] List Crystal Plugin in &lt;a href="https://medium.com/u/2817fb68583"&gt;&lt;strong&gt;Nx&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;Report&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;For debugging purposes, you can now see the list of &lt;strong&gt;registered plugins&lt;/strong&gt; in the &lt;code&gt;nx report&lt;/code&gt; result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flmteok2qub7p9n81wto3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flmteok2qub7p9n81wto3.png" alt="Image description" width="549" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  [Jest] Ability to Split Jest Tests
&lt;/h2&gt;

&lt;p&gt;Jest can also be used for &lt;strong&gt;e2e tests&lt;/strong&gt;! Just as we do with Cypress or Playwright &lt;a href="https://nx.dev/ci/features/split-e2e-tasks"&gt;for splitting and distributing the tests&lt;/a&gt;, we can now do the same for Jest.&lt;/p&gt;

&lt;p&gt;Please check the documentation about &lt;a href="https://nx.dev/nx-api/jest/documents/overview#splitting-e2e-tests"&gt;&lt;strong&gt;Splitting e2e Tests For Jest&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  [nx.dev] Various nx.dev Improvements
&lt;/h2&gt;

&lt;p&gt;It’s also important to highlight that the Nx team is continually improving its website.&lt;/p&gt;

&lt;h3&gt;
  
  
  Remember selected tabs
&lt;/h3&gt;

&lt;p&gt;One notable feature is the ability to remember selected tabs. When you select a specific tab on a page, all other tabs on the page with the same name will also be selected. This selection will persist during your next visit to &lt;a href="http://nx.dev/"&gt;nx.dev&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For example, if you are working with &lt;code&gt;yarn&lt;/code&gt;, when you select the &lt;code&gt;yarn&lt;/code&gt; tab on the &lt;a href="https://nx.dev/getting-started/installation"&gt;Installation Page&lt;/a&gt;, all pages will adapt and display &lt;code&gt;yarn&lt;/code&gt; commands by selecting &lt;code&gt;yarn&lt;/code&gt; tabs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh4glmc7o8sm4xqp1wit7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh4glmc7o8sm4xqp1wit7.png" alt="Image description" width="800" height="258"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  New &lt;a href="https://nx.dev/contact"&gt;Contact Page&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs1ct6fxdmaiqcy66aizj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs1ct6fxdmaiqcy66aizj.png" alt="Image description" width="800" height="591"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Looking for some help?&lt;/strong&gt; 🤝&lt;br&gt;
**Connect with me on &lt;a href="https://twitter.com/jonathan_gelin"&gt;&lt;strong&gt;&lt;em&gt;Twitter&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; • &lt;a href="https://www.linkedin.com/in/jonathan-gelin/"&gt;&lt;strong&gt;&lt;em&gt;LinkedIn&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; • &lt;a href="https://github.com/jogelin"&gt;&lt;strong&gt;&lt;em&gt;Github&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>nx</category>
      <category>monorepo</category>
      <category>typescript</category>
      <category>angular</category>
    </item>
    <item>
      <title>🍒 Cherry-Picked Nx v18.2 Updates</title>
      <dc:creator>jogelin</dc:creator>
      <pubDate>Fri, 05 Apr 2024 07:48:35 +0000</pubDate>
      <link>https://forem.com/jogelin/cherry-picked-nx-v181-updates-5dmm</link>
      <guid>https://forem.com/jogelin/cherry-picked-nx-v181-updates-5dmm</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Release Note 18.2 (2024–03–28)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/nrwl/nx/releases/tag/18.2.0"&gt;https://github.com/nrwl/nx/releases/tag/18.2.0&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  [Angular] Support Angular 17.3
&lt;/h2&gt;

&lt;p&gt;As usual, Nx is up to date with the latest version of Angular!&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://blog.ninja-squad.com/2024/03/13/what-is-new-angular-17.3/" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--HbjC13mc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.ninja-squad.com/assets/images/angular_gradient.png" height="800" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://blog.ninja-squad.com/2024/03/13/what-is-new-angular-17.3/" rel="noopener noreferrer" class="c-link"&gt;
          What’s new in Angular 17.3? | Ninja Squad
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          Angular 17.3 is out!
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s---88H57KW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.ninja-squad.com/assets/images/favicon.ico" width="32" height="32"&gt;
        blog.ninja-squad.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://blog.angular.io/meet-angulars-new-output-api-253a41ffa13c" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--rdu5_0oF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://miro.medium.com/v2/da:true/resize:fit:800/0%2AnWl-YH3WpG-2McBK" height="400" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://blog.angular.io/meet-angulars-new-output-api-253a41ffa13c" rel="noopener noreferrer" class="c-link"&gt;
          Meet Angular’s new output() API. Angular v17.3 introduces the improved… | by Paul Gschwendtner | Mar, 2024 | Angular Blog
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          Angular v17.3 introduces the improved API for declaring outputs as a developer preview.
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--tb4_FaA---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://miro.medium.com/v2/resize:fill:256:256/1%2AuJa0SU-F2NXVKhHTbP1HBw.png" width="256" height="256"&gt;
        blog.angular.io
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  [Core] Scope Nx Plugin Project Crystal 💛💛💛
&lt;/h2&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/nrwl/nx/pull/22379"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        feat(core): add ability to scope plugins
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#22379&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/FrozenPandaz"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--OK4txGhG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/8104246%3Fv%3D4" alt="FrozenPandaz avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/FrozenPandaz"&gt;FrozenPandaz&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/nrwl/nx/pull/22379"&gt;&lt;time&gt;Mar 18, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      



&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Current Behavior&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;There is no way to users to filter where plugins are applied. Only by the plugin author.&lt;/p&gt;
&lt;p&gt;This means that errors thrown make the plugin unusable and more modifications to the project graph are made than desired.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Expected Behavior&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;Plugins can be scoped via &lt;code&gt;include&lt;/code&gt; and &lt;code&gt;exclude&lt;/code&gt; which are both lists of file patterns.&lt;/p&gt;
&lt;div class="highlight highlight-source-json js-code-highlight"&gt;
&lt;pre&gt;{
  &lt;span class="pl-ii"&gt;plugins: [&lt;/span&gt;
    {
      &lt;span class="pl-ii"&gt;plugin: '@nx/jest/plugin',&lt;/span&gt;
      &lt;span class="pl-ii"&gt;include: ['packages/**/*'],&lt;/span&gt;
      &lt;span class="pl-ii"&gt;exclude: ['e2e/**/*']&lt;/span&gt;
    }
  &lt;span class="pl-ii"&gt;]&lt;/span&gt;
}&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;This will scope running the plugin to processing only those config files.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Related Issue(s)&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;Fixes #&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nrwl/nx/pull/22379"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;In my previous article, “&lt;a href="https://medium.com/javascript-in-plain-english/target-exclusions-in-nx-project-crystal-fbabce816b21"&gt;⛔ Target Exclusions in Nx Project Crystal&lt;/a&gt;,” I introduced alternatives for excluding certain projects from specific plugins.&lt;/p&gt;

&lt;p&gt;For instance, you might not want a &lt;code&gt;test&lt;/code&gt; target in an &lt;code&gt;e2e&lt;/code&gt; project simply because there’s a &lt;code&gt;jest.config.ts&lt;/code&gt; file present.&lt;/p&gt;

&lt;p&gt;Now, &lt;strong&gt;an official method is available&lt;/strong&gt; for excluding or including plugins for a specific project. Within your &lt;code&gt;nx.json&lt;/code&gt; file, you can now specify the &lt;code&gt;exclude&lt;/code&gt; or &lt;code&gt;include&lt;/code&gt; options:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"plugins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"plugin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@nx/jest/plugin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"targetName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"exclude"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"my-lib-e2e/**/*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  [Gradle] New Gradle Integration
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://nx.dev/nx-api/gradle" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--cE_Z6V-u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://nx.dev/images/open-graph/nx-api-gradle.jpg" height="" class="m-0" width=""&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://nx.dev/nx-api/gradle" rel="noopener noreferrer" class="c-link"&gt;
          @nx/gradle | Nx
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          The Nx Plugin for Gradle allows Gradle tasks to be run through Nx
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--PUhRf1om--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://nx.dev/favicon/favicon.svg" width="32" height="32"&gt;
        nx.dev
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;You can now leverage the new Gradle integration with the &lt;a href="https://nx.dev/nx-api/gradle/generators/init"&gt;&lt;code&gt;@nx/gradle:init&lt;/code&gt;&lt;/a&gt; generator. To initialize, simply run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nx g @nx/gradle:init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This initialization will also add the &lt;code&gt;@nx/gradle/plugin&lt;/code&gt; to your &lt;code&gt;nx.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"plugins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"plugin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@nx/gradle/plugin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"testTargetName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"classesTargetName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"buildTargetName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"classes"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This plugin will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Integrate your Gradle projects into the Nx Dependency Tree by scanning all Gradle configurations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Discover your projects by scanning the Gradle configuration matching the pattern &lt;code&gt;**/build.{gradle.kts,gradle}&lt;/code&gt;, and then assign the targets &lt;code&gt;build&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt;, and &lt;code&gt;classes&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  [Cypress] New target &lt;code&gt;open-cypress&lt;/code&gt; is added by the @nx/cypress/plugin
&lt;/h2&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/nrwl/nx/pull/22556"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        feat(testing): infer open-cypress task
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#22556&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/leosvelperez"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--x4b4bNxV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/12051310%3Fv%3D4" alt="leosvelperez avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/leosvelperez"&gt;leosvelperez&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/nrwl/nx/pull/22556"&gt;&lt;time&gt;Mar 28, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Infer a new task named &lt;code&gt;open-cypress&lt;/code&gt;, which runs the command &lt;code&gt;cypress open&lt;/code&gt; from the project root.&lt;/p&gt;




&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Current Behavior&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Expected Behavior&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Related Issue(s)&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;Fixes #22389&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nrwl/nx/pull/22556"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;If you’re working with Nx Project Crystal and have a Cypress project that includes a &lt;code&gt;cypress.config.*&lt;/code&gt; file, the &lt;code&gt;@nx/cypress/plugin&lt;/code&gt; &lt;a href="https://nx.dev/nx-api/cypress/documents/overview#how-nxcypress-infers-tasks"&gt;will automatically add related targets to your project&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A new target, &lt;code&gt;open-cypress&lt;/code&gt;, will now be added to your project configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"open-cypress"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cypress open"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"cwd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You have the flexibility to use a different name by specifying the new plugin option &lt;code&gt;openTargetName&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"plugins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"plugin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@nx/cypress/plugin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"targetName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"e2e"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"ciTargetName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"e2e-ci"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"componentTestingTargetName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"component-test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"openTargetName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"open-cypress"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;--&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;NEW&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Looking for some help?&lt;/strong&gt; 🤝&lt;br&gt;
**Connect with me on &lt;a href="https://twitter.com/jonathan_gelin"&gt;&lt;strong&gt;&lt;em&gt;Twitter&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; • &lt;a href="https://www.linkedin.com/in/jonathan-gelin/"&gt;&lt;strong&gt;&lt;em&gt;LinkedIn&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; • &lt;a href="https://github.com/jogelin"&gt;&lt;strong&gt;&lt;em&gt;Github&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>nx</category>
      <category>monorepo</category>
      <category>angular</category>
      <category>gradle</category>
    </item>
    <item>
      <title>🩹 Nx Crystal Plugin Picking the Essentials</title>
      <dc:creator>jogelin</dc:creator>
      <pubDate>Sat, 23 Mar 2024 11:26:27 +0000</pubDate>
      <link>https://forem.com/jogelin/nx-crystal-plugin-picking-the-essentials-43ek</link>
      <guid>https://forem.com/jogelin/nx-crystal-plugin-picking-the-essentials-43ek</guid>
      <description>&lt;p&gt;As specified in my article, &lt;a href="https://medium.com/@jgelin/target-exclusions-in-nx-project-crystal-fbabce816b21"&gt;⛔ Target Exclusions in Nx Project Crystal&lt;/a&gt;, there are use cases that necessitate extending the Nx Project Crystal. However, it is not possible to hook only a specific part of the plugin. You either take it all or you don’t use it at all. Only the &lt;code&gt;createNode&lt;/code&gt; function is exposed, but that function does more than one thing.&lt;/p&gt;

&lt;p&gt;I started a discussion on GitHub concerning that subject: &lt;a href="https://github.com/nrwl/nx/discussions/22099"&gt;Design Nx Plugin Project Crystal&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But there is a solution, don’t forget that nothing is impossible in JavaScript! If you want to access a library’s internal function, just patch it 😅&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;My Use Case&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I pursued this solution because I appreciate the Nx Project Configuration inference and, especially, the no-configuration idea. Yeah yeah, Nx will probably implement that, but I cannot wait 😬.&lt;/p&gt;

&lt;p&gt;However, with the current plugins, it is not possible because they enforce that only projects containing a &lt;code&gt;project.json&lt;/code&gt; will be taken into account. For example, I would like to keep the benefit of dynamic test target assignment from the &lt;code&gt;@nx/jest/plugin&lt;/code&gt; but without the filter on the &lt;code&gt;project.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can check the section &lt;a href="https://jgelin.medium.com/discovering-nx-project-crystals-magic-7f42faf2a135#8a48"&gt;Create Your Cyrstal Plugin&lt;/a&gt; of my article &lt;a href="https://jgelin.medium.com/discovering-nx-project-crystals-magic-7f42faf2a135"&gt;💎 Discovering Nx Project Crystal’s Magic&lt;/a&gt; if you want to know what I am talking about 🙃&lt;/p&gt;

&lt;p&gt;So, if I want to use the &lt;code&gt;@nx/jest/plugin&lt;/code&gt; for the generation of the &lt;code&gt;test&lt;/code&gt; target, I’ll need to expose the internal function &lt;a href="https://github.com/nrwl/nx/blob/286e83dbe9233bd4fb227658a27bc79796694b85/packages/jest/src/plugins/plugin.ts#L116"&gt;&lt;code&gt;buildJestTargets&lt;/code&gt;&lt;/a&gt;. To do so, I'll need to patch the &lt;code&gt;@nx/jest/plugin&lt;/code&gt; library 😈&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Patch Nx Plugins&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Be careful, the following content may offend your sensibility 🙃&lt;/p&gt;

&lt;p&gt;Patching your packages is supported by default for yarn and &lt;code&gt;pnpm&lt;/code&gt;. But if you are using other package managers, you can always use the library &lt;code&gt;patch-package&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In my case, I am using &lt;code&gt;pnpm&lt;/code&gt;, so I first ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm patch @nx/jest

You can now edit the following folder: /private/var/folders/6c/qvy5njbd5z92xgwvcnmpmgcm0000gn/T/9504b5672db3b12b750d6825857fbbb4

Once you&lt;span class="s1"&gt;'re done with your changes, run "pnpm patch-commit '&lt;/span&gt;/private/var/folders/6c/qvy5njbd5z92xgwvcnmpmgcm0000gn/T/9504b5672db3b12b750d6825857fbbb4&lt;span class="s1"&gt;'"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;pnpm&lt;/code&gt; will copy the library into a temporary folder and tell you what step you should follow next.&lt;/p&gt;

&lt;p&gt;So, I can edit the plugin located at &lt;code&gt;/private/.....57f/src/plugins/plugin.js&lt;/code&gt; and add an export in front of the internal function &lt;a href="https://github.com/nrwl/nx/blob/286e83dbe9233bd4fb227658a27bc79796694b85/packages/jest/src/plugins/plugin.ts#L116"&gt;&lt;code&gt;buildJestTargets&lt;/code&gt;&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;buildJestTargets&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I should also inform TypeScript of the exposition by adding the declaration to the file &lt;code&gt;/private/.....57f/src/plugins/plugin.d.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;buildJestTargets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;configFilePath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;projectRoot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JestPluginOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CreateNodesContext&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TargetConfiguration&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then I run the patch command to apply my modification to my repository:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm patch-commit &lt;span class="s1"&gt;'/private/var/folders/6c/qvy5njbd5z92xgwvcnmpmgcm0000gn/T/9504b5672db3b12b750d6825857fbbb4'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then I see that &lt;code&gt;pnpm&lt;/code&gt; updated my &lt;code&gt;package.json&lt;/code&gt; to override the library with:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"pnpm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"patchedDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"@nx/jest@18.0.6"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"patches/@nx__jest@18.0.6.patch"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;and I can see that I have a new patch file &lt;code&gt;patches/@nx__jest@18.0.6.patch&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gh"&gt;diff --git a/src/plugins/plugin.d.ts b/src/plugins/plugin.d.ts
index 1976aa9371ddcc675643d8d13c38c5fdc73e9356..4416e2279b73e4623284fb6a0ec2d275a9bb131c 100644
&lt;/span&gt;&lt;span class="gd"&gt;--- a/src/plugins/plugin.d.ts
&lt;/span&gt;&lt;span class="gi"&gt;+++ b/src/plugins/plugin.d.ts
&lt;/span&gt;&lt;span class="p"&gt;@@ -4,3 +4,9 @@&lt;/span&gt; export interface JestPluginOptions {
 }
 export declare const createDependencies: CreateDependencies;
 export declare const createNodes: CreateNodes&amp;lt;JestPluginOptions&amp;gt;;
&lt;span class="gi"&gt;+export declare async function buildJestTargets(
+    configFilePath: string,
+    projectRoot: string,
+    options: JestPluginOptions,
+    context: CreateNodesContext
+): Promise&amp;lt;Record&amp;lt;string, TargetConfiguration&amp;gt;&amp;gt;;
&lt;/span&gt;\ No newline at end of file
&lt;span class="gh"&gt;diff --git a/src/plugins/plugin.js b/src/plugins/plugin.js
index 5e4162dc41c30b8b1649cd3e3d4661d1b7dccc6c..3de56fef3129d97c85a383e770f0031a68134121 100644
&lt;/span&gt;&lt;span class="gd"&gt;--- a/src/plugins/plugin.js
&lt;/span&gt;&lt;span class="gi"&gt;+++ b/src/plugins/plugin.js
&lt;/span&gt;&lt;span class="p"&gt;@@ -60,7 +60,7 @@&lt;/span&gt; exports.createNodes = [
         };
     },
 ];
&lt;span class="gd"&gt;-async function buildJestTargets(configFilePath, projectRoot, options, context) {
&lt;/span&gt;&lt;span class="gi"&gt;+export async function buildJestTargets(configFilePath, projectRoot, options, context) {
&lt;/span&gt;     const config = await (0, jest_config_1.readConfig)({
         _: [],
         $0: undefined,
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That means each time I run &lt;code&gt;pnpm install&lt;/code&gt;, the patch will be applied along with the modification. Now, let's delve into crafting your custom plugin.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Craft Your Custom Plugin Now&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;You’re now set to develop your custom Jest plugin without the filter. Here’s a prototype plugin, &lt;code&gt;tools/nx-plugins/my-jest-plugin.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CreateNodes&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nx/devkit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;dirname&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node:path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createNodes&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;createJestNodes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JestPluginOptions&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nx/jest/plugin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// IT IS AVAILABLE YEAAAH&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;buildJestTargets&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nx/jest/src/plugins/plugin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createNodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CreateNodes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;JestPluginOptions&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="nx"&gt;createJestNodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;configFilePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;projectRoot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;configFilePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// SAME PLUGIN BUT WITHOUT THE PROJECT.JSON CONDITION&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;projects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;projectRoot&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;projectRoot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;buildJestTargets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;configFilePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;projectRoot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And then, in the &lt;code&gt;nx.json&lt;/code&gt;, it should replace &lt;code&gt;@nx/jest/plugin&lt;/code&gt; with:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"plugins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;HERE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;REPLACE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@nx/jest/plugin"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;YOUR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;CUSTOM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;PLUGIN&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"plugin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./tools/nx-plugins/my-jest-plugin.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"targetName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;⚠️ Cautions&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;This is a temporary tip. Nx Crystal is still a baby, a powerful baby! Keep an eye on Nx updates to ensure this approach is still valid!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do you need it? You are exposed to breaking change!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The patch is strictly linked to the version. If you update Nx, you’ll have to validate the patch.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In my example, I remove the memoization of the plugin; I recommend implementing one each time you are implementing a custom plugin.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;“But this is stupid; you can directly remove the filter on the existing plugin by using the same approach!”.&lt;/em&gt; This is an example; I am doing other stuff too. 😉&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;In Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Got more ideas? Feel free to share, and I’ll eagerly incorporate them. Let’s keep the conversation going and make Nx Project Crystal even more versatile.&lt;/p&gt;

&lt;p&gt;🚀 Stay Tuned!&lt;/p&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Looking for some help?&lt;/em&gt;&lt;/strong&gt;&lt;em&gt;🤝&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Connect with me on&lt;/em&gt; &lt;a href="https://twitter.com/jonathan_gelin"&gt;&lt;strong&gt;Twitter&lt;/strong&gt;&lt;/a&gt; • &lt;a href="https://www.linkedin.com/in/jonathan-gelin/"&gt;&lt;strong&gt;LinkedIn&lt;/strong&gt;&lt;/a&gt; • &lt;a href="https://github.com/jogelin"&gt;&lt;strong&gt;Github&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/jogelin" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IUMYN_82--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.dev.to/cdn-cgi/image/width%3D150%2Cheight%3D150%2Cfit%3Dcover%2Cgravity%3Dauto%2Cformat%3Dauto/https%253A%252F%252Fdev-to-uploads.s3.amazonaws.com%252Fuploads%252Fuser%252Fprofile_image%252F145797%252F2a55b03a-a367-4308-9b79-e6ecfac41696.jpg" alt="jogelin"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/jogelin/target-exclusions-in-nx-project-crystal-4dca" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;⛔ Target Exclusions in Nx Project Crystal&lt;/h2&gt;
      &lt;h3&gt;jogelin ・ Mar 21&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#nx&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#typescript&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#angular&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#react&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



</description>
      <category>nx</category>
      <category>monorepo</category>
      <category>angular</category>
      <category>react</category>
    </item>
    <item>
      <title>📤 Local Library Development with Nx Release and Verdaccio</title>
      <dc:creator>jogelin</dc:creator>
      <pubDate>Thu, 21 Mar 2024 08:12:48 +0000</pubDate>
      <link>https://forem.com/jogelin/local-library-development-with-nx-release-and-verdaccio-2e91</link>
      <guid>https://forem.com/jogelin/local-library-development-with-nx-release-and-verdaccio-2e91</guid>
      <description>&lt;p&gt;Nx offers everything you need to develop and publish your NPM packages efficiently. It provides a structured environment and essential tooling, including &lt;a href="https://verdaccio.org/"&gt;Verdaccio&lt;/a&gt; for local publishing and the innovative &lt;a href="https://nx.dev/features/manage-releases#using-the-programmatic-api-for-nx-release"&gt;Nx Release&lt;/a&gt; system.&lt;/p&gt;

&lt;p&gt;In my previous article, &lt;a href="https://medium.com/@jgelin/cherry-picked-nx-v18-1-updates-067889301e55"&gt;🍒 Cherry-Picked Nx v18.1 Updates&lt;/a&gt;, I highlighted how the custom &lt;code&gt;publish.mjs&lt;/code&gt; will now be replaced by the &lt;strong&gt;Nx Release&lt;/strong&gt; for managing publishable libraries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nx Release&lt;/strong&gt; is mainly achieving three main phases:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsf7ch7krbcfe7g4cuw4q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsf7ch7krbcfe7g4cuw4q.png" alt="Image description" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For those unfamiliar with &lt;strong&gt;Nx Release&lt;/strong&gt;, I recommend:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Reading &lt;a href="https://medium.com/u/71b649cf0618?source=post_page-----019af5c5bec0--------------------------------"&gt;Juri Strumpflohner&lt;/a&gt;’s article: &lt;a href="https://blog.nrwl.io/versioning-and-releasing-packages-in-a-monorepo-45ee194378d1"&gt;Versioning and Releasing Packages in a Monorepo&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check Nx Documentation: &lt;a href="https://nx.dev/features/manage-releases#using-nx-release-subcommands-independently"&gt;Feature&lt;/a&gt;, &lt;a href="https://nx.dev/recipes/nx-release"&gt;Recipe&lt;/a&gt; and &lt;a href="https://nx.dev/nx-api/nx/documents/release"&gt;Api&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;In that short article, I wanted to share insights on utilizing the new system alongside Verdaccio for the local development of publishable libraries.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Practical Use Case&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To begin, create an empty &lt;strong&gt;Nx Workspac&lt;/strong&gt;e with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-nx-workspace@latest myorg &lt;span class="nt"&gt;--preset&lt;/span&gt; empty &lt;span class="nt"&gt;--workspaceType&lt;/span&gt; integrated &lt;span class="nt"&gt;--nxCloud&lt;/span&gt; skip &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;myorg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, add the &lt;code&gt;@nx/js&lt;/code&gt; plugin feature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nx add @nx/js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, create the publishable library you wish to develop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nx g @nx/js:lib my-lib &lt;span class="nt"&gt;--publishable&lt;/span&gt; &lt;span class="nt"&gt;--importPath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;@myorg/my-lib
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;What happened?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Upon generating the publishable library, Nx installs and configures all necessary tooling for your workspace, preparing it for publication.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Verdaccio Setup&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Nx automatically configures &lt;strong&gt;Verdaccio&lt;/strong&gt; on your workspace using &lt;a href="https://nx.dev/nx-api/js/generators/setup-verdaccio"&gt;&lt;code&gt;@nx/js:setup-verdaccio&lt;/code&gt;&lt;/a&gt;, resulting in a root &lt;code&gt;project.json&lt;/code&gt; with the following configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@my-org/source"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"$schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node_modules/nx/schemas/project-schema.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"targets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"local-registry"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"executor"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@nx/js:verdaccio"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4873&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".verdaccio/config.yml"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"storage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tmp/local-registry/storage"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration enables the local &lt;strong&gt;Verdaccio&lt;/strong&gt; registry to run on port 4873, using the specified storage and configuration paths. You can start &lt;strong&gt;Verdaccio&lt;/strong&gt; using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nx run local-registry
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Nx Global Configuration&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Nx also sets up the &lt;strong&gt;Nx Release&lt;/strong&gt; globally in your &lt;code&gt;nx.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"release"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"preVersionCommand"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx nx run-many -t build"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;preVersionCommand&lt;/code&gt; ensures that builds or other tasks are completed before version updating.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Project Configuration&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Finally, your library project configuration will include &lt;strong&gt;Nx Release&lt;/strong&gt;-specific settings and a target &lt;code&gt;nx-release-publish&lt;/code&gt; for running the release:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-lib"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"targets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"nx-release-publish"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"packageRoot"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dist/{projectRoot}"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"release"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"generatorOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"packageRoot"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dist/{projectRoot}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"currentVersionResolver"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"git-tag"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now seamlessly publish your library using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nx release
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Local Development Flow&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If you want to test your library locally, on another local repository, for example, you will have to follow the steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Start Verdaccio&lt;/strong&gt;: &lt;code&gt;nx run local-registry&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Build your Libraries&lt;/strong&gt;: Automated by &lt;strong&gt;Nx Release&lt;/strong&gt; using the &lt;code&gt;preVersionCommand&lt;/code&gt; in &lt;code&gt;nx.json&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Update Versions in Outputs&lt;/strong&gt;: Automated by &lt;strong&gt;Nx Release&lt;/strong&gt; with the generator &lt;a href="https://nx.dev/nx-api/js/generators/release-version#nxjsreleaseversion"&gt;&lt;code&gt;@nx/js:release-version&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Publish Library on Verdaccio&lt;/strong&gt;: Automated by &lt;strong&gt;Nx Release&lt;/strong&gt; using &lt;a href="https://nx.dev/nx-api/js/executors/release-publish"&gt;&lt;code&gt;@nx/js:release-publish&lt;/code&gt;&lt;/a&gt; and the generated target &lt;code&gt;nx-release-publish&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Install your Libraries&lt;/strong&gt;: &lt;code&gt;npm install @my-org/my-lib@latest&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Working locally can become repetitive and tedious, especially when needing to create a unique version each time; otherwise, &lt;strong&gt;Nx Release&lt;/strong&gt; will refuse to publish the same version again. Additionally, I prefer not to complicate my workflow by including an unpublish step.&lt;/p&gt;

&lt;p&gt;In the Nx documentation, two particularly interesting examples are highlighted: &lt;a href="https://nx.dev/features/manage-releases#using-the-programmatic-api-for-nx-release"&gt;Using the programmatic API for Nx release&lt;/a&gt; and &lt;a href="https://nx.dev/recipes/nx-release/update-local-registry-setup"&gt;Update Your Local Registry&lt;/a&gt;. These examples demonstrate how you can craft a custom script to enhance the standard Nx Release process.&lt;/p&gt;

&lt;p&gt;To cover the entire process mentioned above, I implemented a custom script &lt;code&gt;tools/scripts/publish-local.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Related to the target generated in the root project.json&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;localRegistryTarget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@myorg/source:local-registry&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Callback used to stop Verdaccio process&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;stopLocalRegistry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Get Options From Execution&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;yargs&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;version&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// don't use the default meaning of version in yargs&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;version&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Explicit version specifier to use, if overriding conventional commits&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`0.0.0-local.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// the version will be always unique&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;targetPath&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Relative path to the repo where to install the published libraries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parseAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="cm"&gt;/**
   * Step 1: Start Verdaccio
   */&lt;/span&gt;
  &lt;span class="nx"&gt;stopLocalRegistry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;startLocalRegistry&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;localRegistryTarget&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;verbose&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="cm"&gt;/**
   * Step 2: Build your Libraries
   * Step 3: Update Versions in Outputs
   */&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;projectsVersionData&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;releaseVersion&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;specifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;stageChanges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;gitCommit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;gitTag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;firstRelease&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;generatorOptionsOverrides&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;skipLockFileUpdate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="cm"&gt;/**
   * Step 4: Publish Library on Verdaccio
   */&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;publishStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;releasePublish&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;firstRelease&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="cm"&gt;/**
   * Step 5: Install your Libraries
   */&lt;/span&gt;
  &lt;span class="c1"&gt;// Get All published Npm packages that should be installed&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;packagesToInstall&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;projectsVersionData&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;newVersion&lt;/span&gt; &lt;span class="p"&gt;}])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;readCachedProjectGraph&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;packageJson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`package.json`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;packageJson&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;@&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;newVersion&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Prepare the install command&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;targetPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;targetPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;installCommand&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;getInstallCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;targetPath&lt;/span&gt;
  &lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;packagesToInstall&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; --registry=http://localhost:4873`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;installCommand&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Locate to target dir and run the install command&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;targetPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;execSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;installCommand&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="cm"&gt;/**
   * Final: When installation is done, no need to have Verdaccio
   */&lt;/span&gt;
  &lt;span class="nf"&gt;stopLocalRegistry&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;publishStatus&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})().&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// If anything goes wrong, stop Verdaccio&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;stopLocalRegistry&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Used to define which install command should be used on the targetPath&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getInstallCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;targetPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;siblingFiles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;readdirSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;targetPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;siblingFiles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;yarn.lock&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;yarn add&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;siblingFiles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package-lock.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;npm install&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;siblingFiles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pnpm-lock.yaml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pnpm add&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`No package manager found for target repository: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;targetPath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now publish your packages locally just by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx ts-node ./tools/scripts/publish-local.ts &lt;span class="nt"&gt;--targetPath&lt;/span&gt; ../app-using-my-lib
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Final Thoughts&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;It is always difficult when you want to test a publishable library locally. Nx provides all the tooling you need to support you in that process.&lt;/p&gt;

&lt;p&gt;However, it is up to everyone to decide whether you want to use that tooling manually or simply automate it by using a custom script.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In this article, I propose one way, but I highly recommend adapting it to create your own way.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🚀 Stay Tuned!&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Looking for some help?&lt;/em&gt;&lt;/strong&gt;&lt;em&gt;🤝&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Connect with me on&lt;/em&gt; &lt;a href="https://twitter.com/jonathan_gelin"&gt;&lt;strong&gt;Twitter&lt;/strong&gt;&lt;/a&gt; • &lt;a href="https://www.linkedin.com/in/jonathan-gelin/"&gt;&lt;strong&gt;LinkedIn&lt;/strong&gt;&lt;/a&gt; • &lt;a href="https://github.com/jogelin"&gt;&lt;strong&gt;Github&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>nx</category>
      <category>angular</category>
      <category>npm</category>
    </item>
    <item>
      <title>🍒 Cherry-Picked Nx v18.1 Updates</title>
      <dc:creator>jogelin</dc:creator>
      <pubDate>Thu, 21 Mar 2024 08:09:40 +0000</pubDate>
      <link>https://forem.com/jogelin/cherry-picked-nx-v181-updates-2hhg</link>
      <guid>https://forem.com/jogelin/cherry-picked-nx-v181-updates-2hhg</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;[Core] Activate/Deactivate Project Crystal&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Until now you could use the environment variable &lt;a href="https://nx.dev/reference/environment-variables#environment-variables"&gt;NX_ADD_PLUGINS&lt;/a&gt; to activate or deactivate the inferred targets. A new property &lt;code&gt;useInferencePlugins: false&lt;/code&gt; was added to the &lt;code&gt;nx.json&lt;/code&gt; to do the same:&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://nx.dev/nx-api/devkit/documents/NxJsonConfiguration#useinferenceplugins" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--metjt-CY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://nx.dev/images/open-graph/nx-api-devkit-documents-NxJsonConfiguration.jpg" height="" class="m-0" width=""&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://nx.dev/nx-api/devkit/documents/NxJsonConfiguration#useinferenceplugins" rel="noopener noreferrer" class="c-link"&gt;
          NxJsonConfiguration | Nx
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          Nx is a build system with built-in tooling and advanced CI capabilities. It helps you maintain and scale monorepos, both locally and on CI.
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--PUhRf1om--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://nx.dev/favicon/favicon.svg" width="32" height="32"&gt;
        nx.dev
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;





&lt;h2&gt;
  
  
  &lt;strong&gt;[Angular] Support Angular 17.2&lt;/strong&gt;
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://blog.angular.io/angular-v17-2-is-now-available-596cbe96242d" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--1B9OCgWK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://miro.medium.com/v2/resize:fit:960/1%2AFqNPqslt0wc985iUWowLVQ.png" height="450" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://blog.angular.io/angular-v17-2-is-now-available-596cbe96242d" rel="noopener noreferrer" class="c-link"&gt;
          Angular v17.2 is now available. We rarely write blog posts about minor… | by Minko Gechev | Feb, 2024 | Angular Blog
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          We rarely write blog posts about minor releases, but today we have a few surprises for you — experimental support for Material 3, signal…
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--tb4_FaA---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://miro.medium.com/v2/resize:fill:256:256/1%2AuJa0SU-F2NXVKhHTbP1HBw.png" width="256" height="256"&gt;
        blog.angular.io
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;[Angular] New “extract-i18n” Executor&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7muq7vtwv7auvryv7tmd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7muq7vtwv7auvryv7tmd.png" alt="Image description" width="800" height="347"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://nx.dev/nx-api/angular/executors/extract-i18n" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--9dmJYFtA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://nx.dev/images/open-graph/nx-api-angular-executors-extract-i18n.jpg" height="" class="m-0" width=""&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://nx.dev/nx-api/angular/executors/extract-i18n" rel="noopener noreferrer" class="c-link"&gt;
          @nx/angular:extract-i18n | Nx
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          Extracts i18n messages from source code.
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--PUhRf1om--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://nx.dev/favicon/favicon.svg" width="32" height="32"&gt;
        nx.dev
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;





&lt;h2&gt;
  
  
  &lt;strong&gt;[Remix] Add Remix Presets in “&lt;/strong&gt;&lt;code&gt;create-nx-workspace"&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--40Tv_kJY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://miro.medium.com/v2/resize:fit:1400/1%2AuVaUpRUzlR547tQ7_sYtKw.png%2520align%3D%2522left%2522" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--40Tv_kJY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://miro.medium.com/v2/resize:fit:1400/1%2AuVaUpRUzlR547tQ7_sYtKw.png%2520align%3D%2522left%2522" alt="" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nx.dev/nx-api/nx/documents/create-nx-workspace#preset"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8uYMe_sa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711006782241/be263705-46aa-4a02-a2de-3205ba938f5d.png%2520align%3D%2522center%2522" alt="" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;[Remix] Plugin Remix uses CLI directly&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftp4wiwjey3qqze1nzcxg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftp4wiwjey3qqze1nzcxg.png" alt="Image description" width="800" height="244"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://nx.dev/nx-api/nx/documents/create-nx-workspace#preset" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--lHgYZq1C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://nx.dev/images/open-graph/nx-api-nx-documents-create-nx-workspace.jpg" height="" class="m-0" width=""&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://nx.dev/nx-api/nx/documents/create-nx-workspace#preset" rel="noopener noreferrer" class="c-link"&gt;
          create-nx-workspace - CLI command | Nx
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          Create a new Nx workspace
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--PUhRf1om--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://nx.dev/favicon/favicon.svg" width="32" height="32"&gt;
        nx.dev
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;





&lt;h2&gt;
  
  
  &lt;strong&gt;[Gradle] New Gradle Plugin&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;It is not documented yet but there is a new plugin for supporting &lt;a href="https://gradle.org/"&gt;Gradle&lt;/a&gt;:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/nrwl/nx/pull/21055"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        feat(core): add gradle plugin
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#21055&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/xiongemi"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--KdbtPaf6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/16211801%3Fv%3D4" alt="xiongemi avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/xiongemi"&gt;xiongemi&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/nrwl/nx/pull/21055"&gt;&lt;time&gt;Jan 09, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      



&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Current Behavior&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Expected Behavior&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Related Issue(s)&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;Fixes #&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nrwl/nx/pull/21055"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;





&lt;h2&gt;
  
  
  &lt;strong&gt;[Rollup] Crystalize Rollup&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;It will look for look for &lt;code&gt;rollup.config.{js,mjs,cjs}&lt;/code&gt; files and add a &lt;code&gt;build&lt;/code&gt; target automatically:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/nrwl/nx/pull/22045"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        feat(bundling): crystalize rollup
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#22045&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/Coly010"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--hrrK6AVP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/12140467%3Fv%3D4" alt="Coly010 avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/Coly010"&gt;Coly010&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/nrwl/nx/pull/22045"&gt;&lt;time&gt;Feb 28, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      



&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Current Behavior&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;Rollup does not have a Crystal Plugin&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Expected Behavior&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;Rollup has a Crystal Plugin:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It will look for &lt;code&gt;rollup.config.{js,mjs,cjs}&lt;/code&gt; files.&lt;/li&gt;
&lt;li&gt;It will add a build target&lt;/li&gt;
&lt;li&gt;It will use `rollup -c {rollupConfigFileName}&lt;/li&gt;
&lt;li&gt;It will read the config file using rollup's loadConfigFile util&lt;/li&gt;
&lt;li&gt;It will parse the output of the config to determine the outputs that will be created and use them for Nx caching&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Tested on: &lt;a href="https://github.com/freeCodeCamp/freeCodeCamp/tree/main/tools/ui-components"&gt;https://github.com/freeCodeCamp/freeCodeCamp/tree/main/tools/ui-components&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Related Issue(s)&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;Fixes #&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nrwl/nx/pull/22045"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;





&lt;h2&gt;
  
  
  &lt;strong&gt;[Release] Use Nx release instead of custom publish script&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe0cg66aqld9vta6y6b9w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe0cg66aqld9vta6y6b9w.png" alt="Image description" width="800" height="645"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://blog.nrwl.io/versioning-and-releasing-packages-in-a-monorepo-45ee194378d1" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--V_4ok7Qh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://miro.medium.com/v2/resize:fit:1200/1%2Awqtc_sHIbF3y7CalbD7rNQ.jpeg" height="420" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://blog.nrwl.io/versioning-and-releasing-packages-in-a-monorepo-45ee194378d1" rel="noopener noreferrer" class="c-link"&gt;
          Versioning and Releasing Packages in a Monorepo | by Juri Strumpflohner | Feb, 2024 | Nx Devtools
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          When it comes to publishing NPM packages, there are a bunch of libraries and utilities out there that help with the process. Many of them…
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--n_8lUvTC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://miro.medium.com/v2/resize:fill:256:256/1%2AywyYJghcf-EQClcX3XHclA.jpeg" width="256" height="256"&gt;
        blog.nrwl.io
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;





&lt;h2&gt;
  
  
  &lt;strong&gt;[CI] Group CI Logs with NX_SKIP_LOG_GROUPING&lt;/strong&gt;
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://nx.dev/reference/environment-variables#environment-variables" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--LBx-7jHw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://nx.dev/images/open-graph/reference-environment-variables.jpg" height="420" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://nx.dev/reference/environment-variables#environment-variables" rel="noopener noreferrer" class="c-link"&gt;
          Environment Variables | Nx
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          Nx is a build system with built-in tooling and advanced CI capabilities. It helps you maintain and scale monorepos, both locally and on CI.
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--PUhRf1om--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://nx.dev/favicon/favicon.svg" width="32" height="32"&gt;
        nx.dev
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;





&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Looking for some help?&lt;/strong&gt; 🤝&lt;br&gt;
**Connect with me on &lt;a href="https://twitter.com/jonathan_gelin"&gt;&lt;strong&gt;&lt;em&gt;Twitter&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; • &lt;a href="https://www.linkedin.com/in/jonathan-gelin/"&gt;&lt;strong&gt;&lt;em&gt;LinkedIn&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; • &lt;a href="https://github.com/jogelin"&gt;&lt;strong&gt;&lt;em&gt;Github&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>nx</category>
      <category>monorepo</category>
      <category>angular</category>
      <category>devops</category>
    </item>
    <item>
      <title>⛔ Target Exclusions in Nx Project Crystal</title>
      <dc:creator>jogelin</dc:creator>
      <pubDate>Thu, 21 Mar 2024 08:02:05 +0000</pubDate>
      <link>https://forem.com/jogelin/target-exclusions-in-nx-project-crystal-4dca</link>
      <guid>https://forem.com/jogelin/target-exclusions-in-nx-project-crystal-4dca</guid>
      <description>&lt;h3&gt;
  
  
  &lt;strong&gt;UPDATE 2024–04-03:&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;An official way now exists to exclude or include plugins for a specific project:&lt;/strong&gt;&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/nrwl/nx/pull/22379"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        feat(core): add ability to scope plugins
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#22379&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/FrozenPandaz"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--OK4txGhG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/8104246%3Fv%3D4" alt="FrozenPandaz avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/FrozenPandaz"&gt;FrozenPandaz&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/nrwl/nx/pull/22379"&gt;&lt;time&gt;Mar 18, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      



&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Current Behavior&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;There is no way to users to filter where plugins are applied. Only by the plugin author.&lt;/p&gt;
&lt;p&gt;This means that errors thrown make the plugin unusable and more modifications to the project graph are made than desired.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Expected Behavior&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;Plugins can be scoped via &lt;code&gt;include&lt;/code&gt; and &lt;code&gt;exclude&lt;/code&gt; which are both lists of file patterns.&lt;/p&gt;
&lt;div class="highlight highlight-source-json js-code-highlight"&gt;
&lt;pre&gt;{
  &lt;span class="pl-ii"&gt;plugins: [&lt;/span&gt;
    {
      &lt;span class="pl-ii"&gt;plugin: '@nx/jest/plugin',&lt;/span&gt;
      &lt;span class="pl-ii"&gt;include: ['packages/**/*'],&lt;/span&gt;
      &lt;span class="pl-ii"&gt;exclude: ['e2e/**/*']&lt;/span&gt;
    }
  &lt;span class="pl-ii"&gt;]&lt;/span&gt;
}&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;This will scope running the plugin to processing only those config files.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Related Issue(s)&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;Fixes #&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nrwl/nx/pull/22379"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;If we take the example below, you can now use the approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"plugins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"plugin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@nx/jest/plugin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"targetName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"exclude"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"my-lib-e2e/**/*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;Since the release of Nx 18, many repositories have started the adoption of &lt;a href="https://nx.dev/concepts/inferred-tasks"&gt;&lt;strong&gt;Nx Project Crystal&lt;/strong&gt;&lt;/a&gt;. As it’s still the beginning, the feature to exclude some projects from the dynamic target assignment is not supported yet.&lt;/p&gt;

&lt;p&gt;In this article, I want to share workarounds and ideas until the Nx team implements something internally.&lt;/p&gt;

&lt;p&gt;If you’re looking to understand how Nx assigns targets to projects dynamically, I first recommend reading my article:&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/jogelin" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IUMYN_82--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.dev.to/cdn-cgi/image/width%3D150%2Cheight%3D150%2Cfit%3Dcover%2Cgravity%3Dauto%2Cformat%3Dauto/https%253A%252F%252Fdev-to-uploads.s3.amazonaws.com%252Fuploads%252Fuser%252Fprofile_image%252F145797%252F2a55b03a-a367-4308-9b79-e6ecfac41696.jpg" alt="jogelin"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/jogelin/discovering-nx-project-crystals-magic-6i7" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;💎 Discovering Nx Project Crystal’s Magic&lt;/h2&gt;
      &lt;h3&gt;jogelin ・ Feb 26&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#nx&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#react&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#angular&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#typescript&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Workarounds&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Let’s specify the context by mentioning that you have a project named &lt;code&gt;my-lib-e2e&lt;/code&gt; and you don't want that project to have a test target even if it contains a &lt;code&gt;jest.config.ts&lt;/code&gt;. However, you still want to get the benefit of the &lt;code&gt;@nx/jest/plugin&lt;/code&gt; for your other 1000 Nx projects 😋.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Manually Override the “test” Target with&lt;/strong&gt; &lt;a href="https://nx.dev/nx-api/nx/executors/noop"&gt;&lt;code&gt;nx:noop&lt;/code&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;In your &lt;code&gt;my-lib-e2e/project.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-lib-e2e"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"targets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Given that &lt;code&gt;project.json&lt;/code&gt; takes precedence over all plugins, the inferred &lt;code&gt;test&lt;/code&gt; target from the &lt;code&gt;@nx/jest/plugin&lt;/code&gt; will be overridden.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Dynamically Override Any Target with&lt;/strong&gt; &lt;a href="https://nx.dev/nx-api/nx/executors/noop"&gt;&lt;code&gt;nx:noop&lt;/code&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;You can also develop a plugin to automatically assign &lt;code&gt;nx:noop&lt;/code&gt; on any target. For instance, I crafted a plugin located at &lt;code&gt;tools/nx-plugins/targets-noopify.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CreateNodes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ProjectConfiguration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;readJsonFile&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nx/devkit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;join&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node:path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;TargetsNoopifyOptions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createNodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CreateNodes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TargetsNoopifyOptions&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;**/project.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;configFilePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;workspaceRoot&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;projectRoot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;configFilePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// get project name from porject.json&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;projectJson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;readJsonFile&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ProjectConfiguration&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;workspaceRoot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;configFilePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;projectName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;projectJson&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// check if the target of the project should be noopified&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;targetsToStub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;targetsToStub&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// override the targets&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;targets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;targetsToStub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;targetName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;targetName&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;projects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;projectRoot&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;projectRoot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This plugin should then &lt;strong&gt;be listed last&lt;/strong&gt; in &lt;code&gt;nx.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"plugins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"plugin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@nx/jest/plugin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"targetName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;MAKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;SURE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;THIS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;COMES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;AFTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;THE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;PLUGIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;YOU&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;WISH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;OVERRIDE&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"plugin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./tools/nx-plugins/targets-noopify.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"my-lib-e2e"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Create Your Custom&lt;/strong&gt; &lt;code&gt;@nx/jest/plugin&lt;/code&gt; and Skip the Projects
&lt;/h3&gt;

&lt;p&gt;Alternatively, you could implement your custom Jest plugin that filters projects. Here’s an example plugin &lt;code&gt;tools/nx-plugins/skip-jest-plugin.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;CreateNodes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;joinPathFragments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ProjectConfiguration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;readJsonFile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nx/devkit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;join&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node:path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;JestPluginOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;createNodes&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;createJestNodes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nx/jest/plugin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;readdirSync&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createNodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CreateNodes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
  &lt;span class="nx"&gt;JestPluginOptions&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;skipProjects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="nx"&gt;createJestNodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;configFilePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;projectRoot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;configFilePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;siblingFiles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;readdirSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;workspaceRoot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;projectRoot&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;siblingFiles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;project.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;joinPathFragments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;projectRoot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;project.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;projectJson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;readJsonFile&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ProjectConfiguration&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;projectName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;projectJson&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;skipProjects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;createJestNodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;configFilePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And then, in the &lt;code&gt;nx.json&lt;/code&gt;, it should replace &lt;code&gt;@nx/jest/plugin&lt;/code&gt; with:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;plugins&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// HERE, REPLACE "@nx/jest/plugin" WITH YOUR CUSTOM PLUGIN&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;plugin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./tools/nx-plugins/skip-jest-plugin.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;options&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;targetName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;skipProjects&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-lib-e2e&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Ideas&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;As &lt;a href="https://medium.com/u/b4fe03dfad11?source=post_page-----fbabce816b21--------------------------------"&gt;Max Kless&lt;/a&gt; commented, they are open to ideas, so I jumped into it 🙂&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1768391696235073759-907" src="https://platform.twitter.com/embed/Tweet.html?id=1768391696235073759"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1768391696235073759-907');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1768391696235073759&amp;amp;theme=dark"
  }



&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Skip projects per plugin&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This is related to the last workaround described above but integrated into Project Crystal. For example, you would have an &lt;code&gt;nx.json&lt;/code&gt; like:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;plugins&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;plugin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@nx/jest/plugin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;options&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;targetName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;skipProjects&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-lib-e2e&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;// Could be a pattern instead&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;✅ Specific per plugin&lt;br&gt;&lt;br&gt;
⛔ Duplication in each plugin&lt;br&gt;&lt;br&gt;
⛔ If the plugin adds multiple targets, it is not possible to filter only one&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Add “projects” property on targetDefaults&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This strategy takes a leaf from the &lt;a href="https://nx.dev/reference/nx-json#projects"&gt;Nx Release workflow&lt;/a&gt;, applies it to &lt;code&gt;targetDefaults&lt;/code&gt; for more granular control:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$schema&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./node_modules/nx/schemas/nx-schema.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;targetDefaults&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cache&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;inputs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;^production&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;projects&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;!my-lib-e2e&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;✅ Specific per target&lt;br&gt;&lt;br&gt;
✅ Centralized&lt;br&gt;&lt;br&gt;
✅ Re-use existing from Release&lt;br&gt;&lt;br&gt;
⛔ Cannot be specified by executor because the &lt;a href="https://github.com/nrwl/nx/blob/d4e47cce2057f88e78ddb516d8d35cc74eebd60e/packages/jest/src/plugins/plugin.ts#L140"&gt;uses Nx Command&lt;/a&gt;&lt;br&gt;&lt;br&gt;
⛔ It does not reflect what you can specify in your &lt;a href="https://github.com/nrwl/nx/blob/master/packages/nx/schemas/project-schema.json"&gt;Project Configuration&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;In Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Got more ideas? Feel free to share, and I’ll eagerly incorporate them. Let’s keep the conversation going and make Nx Project Crystal even more versatile.&lt;br&gt;
🚀 Stay Tuned!&lt;/p&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Looking for some help?&lt;/em&gt;&lt;/strong&gt;&lt;em&gt;🤝&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Connect with me on&lt;/em&gt; &lt;a href="https://twitter.com/jonathan_gelin"&gt;&lt;strong&gt;Twitter&lt;/strong&gt;&lt;/a&gt; • &lt;a href="https://www.linkedin.com/in/jonathan-gelin/"&gt;&lt;strong&gt;LinkedIn&lt;/strong&gt;&lt;/a&gt; • &lt;a href="https://github.com/jogelin"&gt;&lt;strong&gt;Github&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/jogelin" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IUMYN_82--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.dev.to/cdn-cgi/image/width%3D150%2Cheight%3D150%2Cfit%3Dcover%2Cgravity%3Dauto%2Cformat%3Dauto/https%253A%252F%252Fdev-to-uploads.s3.amazonaws.com%252Fuploads%252Fuser%252Fprofile_image%252F145797%252F2a55b03a-a367-4308-9b79-e6ecfac41696.jpg" alt="jogelin"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/jogelin/nx-crystal-plugin-picking-the-essentials-43ek" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;🩹 Nx Crystal Plugin Picking the Essentials&lt;/h2&gt;
      &lt;h3&gt;jogelin ・ Mar 23&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#nx&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#monorepo&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#angular&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#react&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



</description>
      <category>nx</category>
      <category>typescript</category>
      <category>angular</category>
      <category>react</category>
    </item>
    <item>
      <title>⏰ It’s time to talk about Import Map, Micro Frontend, and Nx Monorepo</title>
      <dc:creator>jogelin</dc:creator>
      <pubDate>Mon, 11 Mar 2024 08:03:40 +0000</pubDate>
      <link>https://forem.com/jogelin/its-time-to-talk-about-import-map-micro-frontend-and-nx-monorepo-283o</link>
      <guid>https://forem.com/jogelin/its-time-to-talk-about-import-map-micro-frontend-and-nx-monorepo-283o</guid>
      <description>&lt;p&gt;In this article, I am sharing about an architecture that has profoundly changed my perception of software development for &lt;strong&gt;large enterprises&lt;/strong&gt; with &lt;strong&gt;complex infrastructure&lt;/strong&gt; and &lt;strong&gt;team organization&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I’ve been eager to write this article for a long time, and &lt;strong&gt;now’s the time!&lt;/strong&gt; I’ve always valued &lt;strong&gt;sticking to standards&lt;/strong&gt;, and I believe the ecosystem is now ready to properly handle this architecture with the latest tools.&lt;/p&gt;

&lt;p&gt;The advent of &lt;a href="https://esbuild.github.io/"&gt;&lt;strong&gt;esbuild&lt;/strong&gt;&lt;/a&gt;, the native support for &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules"&gt;&lt;strong&gt;ES Modules&lt;/strong&gt;&lt;/a&gt; in browsers, the widespread adoption of &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap"&gt;&lt;strong&gt;import map&lt;/strong&gt;&lt;/a&gt;, the emergence of tools like &lt;a href="https://www.angulararchitects.io/blog/announcing-native-federation-1-0/"&gt;&lt;strong&gt;Native Federation&lt;/strong&gt;&lt;/a&gt;, and the &lt;a href="https://nx.dev/"&gt;&lt;strong&gt;Nx&lt;/strong&gt;&lt;/a&gt; ecosystem all combine to forge a flexible and well-maintained &lt;strong&gt;Micro Frontend Architecture&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I’ll cover:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://medium.com/p/0b8e2c07568a#e6e9"&gt;Real Story!&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://medium.com/p/0b8e2c07568a#017b"&gt;A short reminder about browsers&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://medium.com/p/0b8e2c07568a#9c3f"&gt;Micro frontend architecture in a nutshell&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://medium.com/p/0b8e2c07568a#57ef"&gt;What is an Import Map?&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://medium.com/p/0b8e2c07568a#2f22"&gt;Exploring the Full Potential of Import Maps and Overrides&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://medium.com/p/0b8e2c07568a#e1ed"&gt;Nx Enables Scalable Micro Frontend Architecture&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://medium.com/p/0b8e2c07568a#a8b4"&gt;What about Native Federation?&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/p/0b8e2c07568a#656e"&gt;Final Thoughts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Real Story!&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Just to give you more context, I led the migration of several &lt;a href="https://angularjs.org/"&gt;AngularJS&lt;/a&gt; applications to the newer &lt;a href="https://angular.dev/"&gt;Angular&lt;/a&gt; Framework. My client finally decided to make that move following the AngularJS deprecation announcement (stay up to date please 🙏)️.&lt;/p&gt;

&lt;p&gt;Using the usual migration process was not possible. After investigating multiple scenarios, the micro frontend architecture was chosen. As we see, it facilitates &lt;strong&gt;incremental migration&lt;/strong&gt;, provides &lt;strong&gt;isolation&lt;/strong&gt;, and allows the integration of apps from &lt;strong&gt;multiple teams&lt;/strong&gt; into one &lt;strong&gt;unified platform&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;At that time, the micro frontend architecture was not yet popular and only the &lt;a href="https://single-spa.js.org/docs/getting-started-overview/"&gt;&lt;strong&gt;single-spa&lt;/strong&gt;&lt;/a&gt; library was &lt;strong&gt;mature&lt;/strong&gt; enough. It supports many frameworks, including AngularJS and Angular, making it a perfect choice for us!&lt;/p&gt;

&lt;p&gt;Single-spa orchestrates the micro frontend by toggling between AngularJS or Angular implementations based on a feature flag:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9hs6v9gq3hsi4f82i9ma.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9hs6v9gq3hsi4f82i9ma.png" alt="Image description" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using &lt;a href="https://single-spa.js.org/docs/getting-started-overview/"&gt;single-spa&lt;/a&gt; has significantly enhanced my understanding of implementing micro frontend architecture, particularly highlighting the substantial benefits of utilizing &lt;strong&gt;import maps&lt;/strong&gt; and &lt;strong&gt;micro frontend overrides&lt;/strong&gt;. These tools have greatly improved my experience in &lt;strong&gt;local development&lt;/strong&gt;, &lt;strong&gt;testing&lt;/strong&gt;, and &lt;strong&gt;deployment&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I highly recommend having a look at the &lt;a href="https://single-spa.js.org/docs/getting-started-overview/"&gt;&lt;strong&gt;single-spa&lt;/strong&gt;&lt;/a&gt; documentation to understand the concepts of &lt;strong&gt;micro frontend&lt;/strong&gt; and &lt;strong&gt;import map&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;A short reminder about browsers&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To grasp the following subjects, I believe it’s crucial first to recall the &lt;strong&gt;basics&lt;/strong&gt; of the web, focusing on the primary flow of a &lt;strong&gt;browser running a web application&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftj75rgbiu5xyy57v2bjf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftj75rgbiu5xyy57v2bjf.png" alt="Image description" width="800" height="220"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The first action is always to get an &lt;code&gt;index.html&lt;/code&gt; file, which has everything needed to start the application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Then, the browser loads all the files that the &lt;code&gt;index.html&lt;/code&gt; says it should. This often includes the &lt;strong&gt;main files&lt;/strong&gt; for the application, like JavaScript and stylesheets.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After that, the application or the user interaction leads to more requests being made, for example, &lt;strong&gt;calling APIs&lt;/strong&gt; or &lt;strong&gt;loading parts&lt;/strong&gt; of the site as needed.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The browser’s job is simply to load these files or assets and put them together into the web application.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Micro frontend architecture in a nutshell&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Let’s start with a short definition: the micro frontend architecture involves &lt;strong&gt;breaking down&lt;/strong&gt; a frontend application into &lt;strong&gt;smaller&lt;/strong&gt;, more &lt;strong&gt;manageable&lt;/strong&gt; pieces — each responsible for a &lt;strong&gt;distinct feature&lt;/strong&gt; or &lt;strong&gt;domain&lt;/strong&gt; of your application. It’s often compared to the &lt;a href="https://avinetworks.com/glossary/microservice/"&gt;microservices concept&lt;/a&gt; but at the frontend layer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Famm0e2omid0d50qbc68y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Famm0e2omid0d50qbc68y.png" alt="Image description" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Determining the exact point at which an application adheres to micro frontend architecture can be challenging, like defining the ideal size for a microservice.&lt;/p&gt;

&lt;p&gt;The key aspect is having a platform capable of &lt;strong&gt;plugging&lt;/strong&gt; in and &lt;strong&gt;combining&lt;/strong&gt; multiple pieces of functionality to produce a &lt;strong&gt;unified application&lt;/strong&gt;. Whether these pieces are &lt;strong&gt;lazy-loaded&lt;/strong&gt; components or &lt;strong&gt;micro frontend&lt;/strong&gt;, the principle remains essentially the &lt;strong&gt;same&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;In which situation it suits you well?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;There are many use cases where the micro frontend architecture can be useful:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7bz7kjs5ck3btrklipg7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7bz7kjs5ck3btrklipg7.png" alt="Image description" width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multiple Frameworks&lt;/strong&gt;: The most common use case involves integrating various technologies into a single product, particularly useful for unifying disparate systems.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Team Decentralization&lt;/strong&gt;: When teams operate independently, within a monorepo or different repositories, micro frontends make it easier to merge their work into one cohesive product.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Separation of Concerns&lt;/strong&gt;: Ideal for structuring your application into isolated domains and features for better organization.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Complex Infrastructure&lt;/strong&gt;: The ability to plug a micro frontend into an existing environment can significantly enhance the development experience! We’ll delve into this reason further later on.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Don’t use micro frontend architecture if you don’t need it&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Major Concepts&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In a micro-frontend architecture, we distinguish various types of entities, each adhering to a distinct concept:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5tp62ihe27fyopdqs8ry.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5tp62ihe27fyopdqs8ry.png" alt="Image description" width="800" height="615"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Micro Frontend&lt;/strong&gt; (or micro app) is loaded by the &lt;strong&gt;Host&lt;/strong&gt; upon navigation or routing. Each micro frontend is responsible for a distinct feature or domain within the application. Like any app, it can contain child routes and multiple components.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Parcel&lt;/strong&gt; (also referred to as a component or expose) is loaded independently on-demand. It can be a shared component or a shared service and can be plugged in anywhere.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Tools/Frameworks&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;There are several implementations of the micro frontend architecture, and I’ll delve into three notable ones here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgezqukaj1tcixnluryq7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgezqukaj1tcixnluryq7.png" alt="Image description" width="800" height="187"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Single-spa&lt;/strong&gt;: This framework keeps things &lt;strong&gt;simple&lt;/strong&gt; and works with many technologies. However, its &lt;strong&gt;simplicity&lt;/strong&gt; might mean you have to do more work if you’re using just one technology.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Webpack Module Federation&lt;/strong&gt;: Almost everyone uses &lt;strong&gt;Webpack&lt;/strong&gt;, and its module federation feature makes micro frontends easy for these users. But, if you’re using a different tool, you might need to find another solution.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Native Federation&lt;/strong&gt;: This method combines the ease of Webpack’s approach with &lt;strong&gt;newer&lt;/strong&gt; tools like &lt;strong&gt;esbuild&lt;/strong&gt; or &lt;strong&gt;Vite&lt;/strong&gt;, fitting well with modern development practices while supporting micro frontend architecture.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What is an Import Map?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Let’s begin with the most intriguing aspect. In my opinion, the import map is an &lt;strong&gt;underappreciated browser technology&lt;/strong&gt;. It is compatible with all browsers and plays a role in directly supporting JavaScript modules in the browser.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7mm7loxr09rkxhv4qrbh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7mm7loxr09rkxhv4qrbh.png" alt="Image description" width="771" height="268"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For full compatibility and extra features, we usually use the library &lt;a href="https://github.com/guybedford/es-module-shims"&gt;&lt;code&gt;es-module-shims&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;How does it work?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The principle is quite straightforward. Since the introduction of the ES module into our JavaScript ecosystem, we’ve all started using syntax like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;moment&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;moment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;partition&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lodash&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;However, when using ES modules natively in a browser, you need to specify the full path to the JS file, something like:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;moment&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;partition&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This approach isn’t very readable or maintainable, is it? Therefore, the import map was created to map a library name to a URL:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;importmap&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;imports&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;moment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lodash&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It functions similarly to TypeScript’s path mapping but directly in your browser. Now, you can use the same syntax whether loading modules locally or in the browser.&lt;/p&gt;

&lt;p&gt;This import map can be specified &lt;strong&gt;inline&lt;/strong&gt; or as an &lt;strong&gt;external file&lt;/strong&gt;, like:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;&amp;lt;script&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;type=&lt;/span&gt;&lt;span class="s2"&gt;"importmap"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;src=&lt;/span&gt;&lt;span class="s2"&gt;"assets/shared.importmap.json"&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;script&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;type=&lt;/span&gt;&lt;span class="s2"&gt;"importmap"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;src=&lt;/span&gt;&lt;span class="s2"&gt;"assets/remotes.importmap.json"&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;For more information, I recommend checking out the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap"&gt;MDN Web Docs&lt;/a&gt; and the &lt;a href="https://github.com/WICG/import-maps?tab=readme-ov-file"&gt;proposal’s GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;How is it related to the micro frontend architecture?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;As I mentioned, the micro frontend architecture is a just a way for dynamically loading bundles from the browser and integrating them into the actual apps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvzksgti0ghweo1nc4pa3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvzksgti0ghweo1nc4pa3.png" alt="Image description" width="800" height="363"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This orchestration is the role of the &lt;strong&gt;Host&lt;/strong&gt;. However, when the host needs to load an &lt;strong&gt;ES module&lt;/strong&gt;, it can simply utilize the &lt;strong&gt;JS import system&lt;/strong&gt; and, with the aid of the &lt;strong&gt;import map&lt;/strong&gt;, map the module to its location&lt;/p&gt;

&lt;p&gt;Similarly, for &lt;strong&gt;Parcels&lt;/strong&gt;, when you need to load a component on demand, the import map will map your &lt;strong&gt;JS import&lt;/strong&gt; to the current location.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Import Maps are overridable!&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You can declare multiple import maps in the same HTML. This means that if two import maps declare the same key, the last one will override the previous one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fddnzmx3puebl7r6lhexk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fddnzmx3puebl7r6lhexk.png" alt="Image description" width="800" height="1190"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By injecting a new import map into your HTML, you can hook/remap any bundle. Thus, you can replace a micro frontend, a component, or even a shared library!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I recommend the library &lt;a href="https://github.com/single-spa/import-map-overrides"&gt;&lt;code&gt;import-map-override&lt;/code&gt;&lt;/a&gt; which allows you to manage the import map directly in your browser.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Security&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Overriding an import map in a web application does not inherently reduce its security, as all frontend assets are public and can be modified client-side. However, for applications that load assets from multiple servers, configuring a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP"&gt;Content-Security-Policy&lt;/a&gt; (CSP) is crucial.&lt;/p&gt;

&lt;p&gt;CSP helps whitelist trusted domains, significantly reducing the risk of &lt;a href="https://en.wikipedia.org/wiki/Cross-site_scripting"&gt;Cross-Site Scripting&lt;/a&gt; (XSS) and other security threats. This security measure ensures that even if client-side modifications are possible, the application’s integrity and user safety are maintained.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Exploring the Full Potential of Import Maps and Overrides&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now that we understand the principles of the import map and the fact that we can override the bundles loading directly in the browser, let’s see how we can get the advantage of that concept within our development process:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftiqv6ztz572fy8g6w4p5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftiqv6ztz572fy8g6w4p5.png" alt="Image description" width="800" height="162"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Local Development&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Setting up a complex local environment in a large organization often involves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Spending &lt;strong&gt;more than a day to set up&lt;/strong&gt; your local machine.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Installing a &lt;strong&gt;wide range of software&lt;/strong&gt;, like backend systems, local databases or connections to external environments, local queuing systems, etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Adjusting settings for &lt;strong&gt;multi-tenants&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Take coffee breaks while you &lt;strong&gt;wait&lt;/strong&gt; for your local environment to bootstrap in the morning, hoping it stays stable throughout the day.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This complexity can be quite frustrating, especially when you only need to make a minor UI adjustment. &lt;strong&gt;This is the exact challenge I aimed to tackle through the adoption of micro frontend architecture in combination with the import map overrides.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of running an entire complex ecosystem, you can just plug your local environment into an external environment where all of the complexity is already in place.&lt;/p&gt;

&lt;p&gt;To do so, you just need to serve your micro frontend locally and use the import map override principle on the distant environment:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyox4rz9bfk2mpwg1l5s3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyox4rz9bfk2mpwg1l5s3.png" alt="Image description" width="800" height="306"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the reload, the micro frontend loaded by the browser will be not the one on the distant server but the one on your local machine.&lt;/p&gt;

&lt;p&gt;One crucial aspect is that you are directly integrating your code into a real environment that contains the latest main branch. This means we can move past the infamous “&lt;strong&gt;It Works On My Machine!&lt;/strong&gt;” scenario.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This approach showcases true Continuous Integration&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Pull Request&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;When you’ve completed your implementation (and tested it 😋), you typically create a pull request to merge your code into the shared codebase.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Facilitate Reviews&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You can once again leverage the advantage of import map overriding to make the review process easier, allowing reviewers to validate your changes without needing to deploy or clone the code locally:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faj7enhtonb6rt8j7qiuw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faj7enhtonb6rt8j7qiuw.png" alt="Image description" width="800" height="506"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this stage, the CI will build your app and generate new bundles for the modified micro frontend. Additionally, you can generate an &lt;a href="https://medium.com/p/0b8e2c07568a#c8c8"&gt;affected &lt;code&gt;importmap.json&lt;/code&gt;&lt;/a&gt; with the updated bundles.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simplify UI e2e tests&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You can also use the affected import map for your &lt;strong&gt;UI tests&lt;/strong&gt; (mocks). In this scenario, the affected &lt;code&gt;importmap.json&lt;/code&gt; generated can be injected into tools like &lt;strong&gt;Playwright&lt;/strong&gt; or &lt;strong&gt;Cypress&lt;/strong&gt; to directly test the affected micro frontends.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Acceptance&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This step signifies the moment when you need to confirm that your code is ready for production deployment. It can be automated on CI or manually (please automate 🙏).&lt;/p&gt;

&lt;p&gt;Typically, this is run several times per day with the most recent codebase in an environment that mirrors production. In this scenario, you’ll generate an &lt;code&gt;importmap.json&lt;/code&gt; that includes the latest versions of all bundles:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft8x5vyu7a7qrfe7lti2s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft8x5vyu7a7qrfe7lti2s.png" alt="Image description" width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the latest &lt;code&gt;importmap.json&lt;/code&gt; generated proves successful, it can then become a release candidate for production.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Production&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;When your release is validated and ready, you can consider deploying it to production. Here, too, having an &lt;code&gt;importmap.json&lt;/code&gt; offers significant advantages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F972594nq8u3d1oxuz8xo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F972594nq8u3d1oxuz8xo.png" alt="Image description" width="800" height="217"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deploy in a Sec&lt;/strong&gt;&lt;br&gt;
You can deploy/upload your bundles to production at any time. Until the &lt;code&gt;importmap.json&lt;/code&gt; references them, they will not be loaded. Thus, deployment involves merely modifying and uploading the latest import map. This deployment process takes a mere second, requires no freeze, and is completely transparent to the user.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You should have a look to them &lt;a href="https://github.com/single-spa/import-map-deployer"&gt;import-map-deployer&lt;/a&gt;&lt;em&gt;library which enable to update an&lt;/em&gt;&lt;code&gt;importmap.json&lt;/code&gt; directly on the server&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Keep Previous Bundles in Cache&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
It’s also important to note that the &lt;code&gt;importmap.json&lt;/code&gt; can still reference bundles with previous versions. In fact, if some micro frontends have not been modified, there’s no need to generate a new version for them.&lt;/p&gt;

&lt;p&gt;This means that users won’t have to reload these existing versions because they are probably already cached in their browser. On the other hand, the &lt;code&gt;importmap.json&lt;/code&gt; should never be cached!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Canary Deployment &amp;amp; A/B Testing&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
One last, and not negligible, benefit of the &lt;code&gt;importmap.json&lt;/code&gt; is that it can be generated dynamically. This means you can decide whether a micro frontend should load an old version or a new one.&lt;/p&gt;

&lt;p&gt;As a result, you can easily conduct &lt;a href="https://medium.com/@chandu.bathula16/machine-learning-concept-70-a-b-a-a-b-testing-1c082cd91795"&gt;A/B testing&lt;/a&gt; or &lt;a href="https://semaphoreci.com/blog/what-is-canary-deployment"&gt;canary deployments&lt;/a&gt; based on feature flags or authenticated user criteria!&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Nx Enables Scalable Micro Frontend Architecture&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I won’t delve into all the benefits of Nx, a topic I’ve extensively covered in previous writings. I’ll encourage you to have a look at the &lt;a href="https://nx.dev/"&gt;Nx website&lt;/a&gt; for more detailed information.&lt;/p&gt;

&lt;p&gt;My conviction in the value Nx brings to not just JavaScript/TypeScript repositories but to any codebase is unwavering. Its strengths in enhancing sharing, visibility, performance, and adherence to conventions are universally applicable.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Monorepo and Micro Frontend aren’t the opposite?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Not at all! A monorepo adds value through enhanced code maintenance, build, and integration processes. Conversely, micro frontend architecture delivers benefits at runtime.&lt;/p&gt;

&lt;p&gt;Both strategies advocate for separation of concerns and reusability, showcasing significant advantages in incorporating micro frontends within a monorepo.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://nx.dev/concepts/more-concepts/why-monorepos" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--1frpFGOM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://nx.dev/images/open-graph/concepts-more-concepts-why-monorepos.jpg" height="420" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://nx.dev/concepts/more-concepts/why-monorepos" rel="noopener noreferrer" class="c-link"&gt;
          Monorepos | Nx
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          Nx is a build system with built-in tooling and advanced CI capabilities. It helps you maintain and scale monorepos, both locally and on CI.
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--PUhRf1om--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://nx.dev/favicon/favicon.svg" width="32" height="32"&gt;
        nx.dev
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Nx still delivers value even if you don’t use a monorepo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Affected micro frontends&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;A pivotal concept in Nx is the ability to execute tasks solely on the affected code. This feature significantly simplifies working on a single micro frontend at a time in a remote environment, streamlining local development.&lt;/p&gt;

&lt;p&gt;By limiting actions like build, lint, and testing to impacted micro frontends, the efficiency of your CI/CD processes can be markedly improved. Utilizing an affected &lt;code&gt;importmap.json&lt;/code&gt; that lists the affected micro frontends can enhance various processes, including testing PRs on existing environments, running e2e tests, and facilitating incremental deployments.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://nx.dev/ci/features/affected" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--qABdVLDN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://nx.dev/images/open-graph/ci-features-affected.jpg" height="420" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://nx.dev/ci/features/affected" rel="noopener noreferrer" class="c-link"&gt;
          Run Only Tasks Affected by a PR | Nx
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          Nx is a build system with built-in tooling and advanced CI capabilities. It helps you maintain and scale monorepos, both locally and on CI.
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--PUhRf1om--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://nx.dev/favicon/favicon.svg" width="32" height="32"&gt;
        nx.dev
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;Single Version Policy&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;While independence and isolation are cornerstone principles of micro frontend architecture, sharing some services and components across all instances is inevitable.&lt;/p&gt;

&lt;p&gt;The monorepo approach, coupled with a single version policy, ensures by design that micro frontends remain compatible with one another, fostering a cohesive ecosystem.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://nx.dev/concepts/more-concepts/dependency-management" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--5eYmW0Dz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://nx.dev/images/open-graph/concepts-more-concepts-dependency-management.jpg" height="420" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://nx.dev/concepts/more-concepts/dependency-management" rel="noopener noreferrer" class="c-link"&gt;
          Dependency Management | Nx
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          Nx is a build system with built-in tooling and advanced CI capabilities. It helps you maintain and scale monorepos, both locally and on CI.
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--PUhRf1om--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://nx.dev/favicon/favicon.svg" width="32" height="32"&gt;
        nx.dev
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;What about Native Federation?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Like I said at the beginning, I think now the ecosystem is mature enough to apply the same principles by using &lt;strong&gt;Angular&lt;/strong&gt;, or other frameworks using &lt;strong&gt;esbuild&lt;/strong&gt;, and &lt;strong&gt;Native Federation&lt;/strong&gt; within an &lt;strong&gt;Nx&lt;/strong&gt; monorepo.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I encourage you to have a look at the &lt;a href="https://www.angulararchitects.io/en/blog/announcing-native-federation-1-0/"&gt;blog post announcing Native Federation&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Unfortunately, I was unable to implement the import map overrides in conjunction with Native Federation. However, this issue is currently under discussion on GitHub:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/angular-architects/module-federation-plugin/issues/489"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Use more importmap default behaviours
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#489&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/jogelin"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--H75JfLZT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/954509%3Fv%3D4" alt="jogelin avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/jogelin"&gt;jogelin&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/angular-architects/module-federation-plugin/issues/489"&gt;&lt;time&gt;Mar 04, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Hi there,&lt;/p&gt;
&lt;p&gt;As usual, it's a great library 👏. I appreciate the fact that the lesser-known &lt;code&gt;importmaps&lt;/code&gt; standard is utilized ;)&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Goal&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;I've previously employed &lt;code&gt;importmaps&lt;/code&gt; in one of my micro-frontend projects alongside &lt;a href="https://single-spa.js.org/" rel="nofollow"&gt;single-spa&lt;/a&gt; and the &lt;a href="https://github.com/single-spa/import-map-overrides"&gt;importmap overrides library&lt;/a&gt;. This approach significantly enhances the developer experience in complex environments by allowing direct integration of a &lt;strong&gt;local server&lt;/strong&gt; into an &lt;strong&gt;integration server&lt;/strong&gt; (more info in the &lt;a href="https://www.youtube.com/watch?v=vjjcuIxqIzY&amp;amp;list=PLLUD8RtHvsAOhtHnyGx57EYXoaNsxGrTU&amp;amp;index=5" rel="nofollow"&gt;YouTube video from Joel Denning&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;It also proves beneficial for testing, enabling the generation of an affected &lt;code&gt;importmap&lt;/code&gt; on PRs and its use to override bundles in an existing environment without the need for cloning or deploying anything.&lt;/p&gt;
&lt;p&gt;It also facilitates &lt;strong&gt;incremental&lt;/strong&gt; and &lt;strong&gt;canary&lt;/strong&gt; deployment.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Issue&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;My intention was to apply the same strategy with native federation due to its utilization. However, I found it unfeasible due to a &lt;a href="https://github.com/angular-architects/module-federation-plugin/blob/main/libs/native-federation-runtime/src/lib/model/global-cache.ts"&gt;globalCache&lt;/a&gt; that does not account for potential modifications to the &lt;code&gt;importmaps&lt;/code&gt; overrides. This capability is a &lt;strong&gt;default feature&lt;/strong&gt; and it is supported by the &lt;a href="https://github.com/guybedford/es-module-shims?tab=readme-ov-file#overriding-import-map-entries"&gt;es-module-shims library&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Propositions&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;First, let's examine the current behavior:&lt;/p&gt;
&lt;div class="highlight highlight-source-mermaid js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;flowchart&lt;/span&gt; &lt;span class="pl-c1"&gt;TD&lt;/span&gt;
    &lt;span class="pl-k"&gt;subgraph&lt;/span&gt; &lt;span class="pl-en"&gt;Remote&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;[&lt;/span&gt;&lt;/span&gt;On Load Remote Module&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class="pl-ent"&gt;1&lt;/span&gt;&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;[&lt;/span&gt;&lt;/span&gt;loadRemoteModule on routing or in component&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class="pl-ent"&gt;2&lt;/span&gt;&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;[&lt;/span&gt;&lt;/span&gt;getRemote Infos From Cache&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class="pl-ent"&gt;3&lt;/span&gt;&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;[&lt;/span&gt;&lt;/span&gt;importShim from remote url&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

        &lt;span class="pl-ent"&gt;1&lt;/span&gt; &lt;span class="pl-k"&gt;--&amp;gt;&lt;/span&gt; &lt;span class="pl-ent"&gt;2&lt;/span&gt;
        &lt;span class="pl-ent"&gt;2&lt;/span&gt; &lt;span class="pl-k"&gt;--&amp;gt;&lt;/span&gt; &lt;span class="pl-ent"&gt;3&lt;/span&gt;
    &lt;span class="pl-k"&gt;end&lt;/span&gt;

    &lt;span class="pl-k"&gt;subgraph&lt;/span&gt; &lt;span class="pl-en"&gt;Host&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;[&lt;/span&gt;&lt;/span&gt;On Host Initialization&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class="pl-k"&gt;direction&lt;/span&gt; &lt;span class="pl-c1"&gt;TB&lt;/span&gt;
        &lt;span class="pl-ent"&gt;a&lt;/span&gt;&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;[&lt;/span&gt;&lt;/span&gt;initFederation In Host&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class="pl-ent"&gt;b&lt;/span&gt;&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;[&lt;/span&gt;&lt;/span&gt;Fetch federation.manifest.json&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

        &lt;span class="pl-ent"&gt;h&lt;/span&gt;&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;[&lt;/span&gt;&lt;/span&gt;Load remoteEntry.json of the host&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class="pl-ent"&gt;i&lt;/span&gt;&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;[&lt;/span&gt;&lt;/span&gt;Generate importmap with key/url&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

        &lt;span class="pl-ent"&gt;y&lt;/span&gt;&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;[&lt;/span&gt;&lt;/span&gt;Combine Host importmap and remotes importmaps&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class="pl-ent"&gt;z&lt;/span&gt;&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;[&lt;/span&gt;&lt;/span&gt;Write importmaps in DOM&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

        &lt;span class="pl-ent"&gt;a&lt;/span&gt; &lt;span class="pl-k"&gt;--&amp;gt;&lt;/span&gt; &lt;span class="pl-ent"&gt;b&lt;/span&gt;
        &lt;span class="pl-ent"&gt;a&lt;/span&gt; &lt;span class="pl-k"&gt;--&amp;gt;&lt;/span&gt; &lt;span class="pl-ent"&gt;A&lt;/span&gt;
        &lt;span class="pl-ent"&gt;b&lt;/span&gt; &lt;span class="pl-k"&gt;--&amp;gt;&lt;/span&gt; &lt;span class="pl-ent"&gt;B&lt;/span&gt;

        &lt;span class="pl-k"&gt;subgraph&lt;/span&gt; &lt;span class="pl-en"&gt;A&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;[&lt;/span&gt;&lt;/span&gt;hostImportMap&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span class="pl-k"&gt;direction&lt;/span&gt; &lt;span class="pl-c1"&gt;TB&lt;/span&gt;
            &lt;span class="pl-ent"&gt;h&lt;/span&gt;&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;[&lt;/span&gt;&lt;/span&gt;Load remoteEntry.json&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span class="pl-ent"&gt;i&lt;/span&gt;&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;[&lt;/span&gt;&lt;/span&gt;Generate importmap with key/url&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

            &lt;span class="pl-ent"&gt;h&lt;/span&gt; &lt;span class="pl-k"&gt;--&amp;gt;&lt;/span&gt; &lt;span class="pl-ent"&gt;i&lt;/span&gt;
        &lt;span class="pl-k"&gt;end&lt;/span&gt;

        &lt;span class="pl-k"&gt;subgraph&lt;/span&gt; &lt;span class="pl-en"&gt;B&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;[&lt;/span&gt;&lt;/span&gt;remotesImportMap&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span class="pl-k"&gt;direction&lt;/span&gt; &lt;span class="pl-c1"&gt;TB&lt;/span&gt;
            &lt;span class="pl-ent"&gt;c&lt;/span&gt;&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;[&lt;/span&gt;&lt;/span&gt;Load remoteEntry.json&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span class="pl-ent"&gt;d&lt;/span&gt;&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;[&lt;/span&gt;&lt;/span&gt;Generate importmap with key/url&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span class="pl-ent"&gt;e&lt;/span&gt;&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;[&lt;/span&gt;&lt;/span&gt;Add remote entry infos to globalCache&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

            &lt;span class="pl-ent"&gt;c&lt;/span&gt; &lt;span class="pl-k"&gt;--&amp;gt;&lt;/span&gt; &lt;span class="pl-ent"&gt;d&lt;/span&gt;
            &lt;span class="pl-ent"&gt;c&lt;/span&gt; &lt;span class="pl-k"&gt;--&amp;gt;&lt;/span&gt; &lt;span class="pl-ent"&gt;e&lt;/span&gt;
        &lt;span class="pl-k"&gt;end&lt;/span&gt;

        &lt;span class="pl-ent"&gt;A&lt;/span&gt; &lt;span class="pl-k"&gt;--&amp;gt;&lt;/span&gt; &lt;span class="pl-ent"&gt;y&lt;/span&gt;
        &lt;span class="pl-ent"&gt;B&lt;/span&gt; &lt;span class="pl-k"&gt;--&amp;gt;&lt;/span&gt; &lt;span class="pl-ent"&gt;y&lt;/span&gt;
        &lt;span class="pl-ent"&gt;y&lt;/span&gt; &lt;span class="pl-k"&gt;--&amp;gt;&lt;/span&gt; &lt;span class="pl-ent"&gt;z&lt;/span&gt;
    &lt;span class="pl-k"&gt;end&lt;/span&gt;

    &lt;span class="pl-ent"&gt;Cache&lt;/span&gt;&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;((&lt;/span&gt;&lt;/span&gt;globalCache&lt;span class="pl-pds"&gt;&lt;span class="pl-sg"&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

    &lt;span class="pl-ent"&gt;e&lt;/span&gt; &lt;span class="pl-k"&gt;.-&amp;gt;&lt;/span&gt; &lt;span class="pl-ent"&gt;Cache&lt;/span&gt;
    &lt;span class="pl-ent"&gt;2&lt;/span&gt; &lt;span class="pl-k"&gt;.-&amp;gt;&lt;/span&gt; &lt;span class="pl-ent"&gt;Cache&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;1. Allow importmap overrides in the &lt;code&gt;es-module-shims&lt;/code&gt; library&lt;/h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;div class="highlight highlight-text-html-basic js-code-highlight"&gt;
&lt;pre&gt; &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;script&lt;/span&gt; &lt;span class="pl-c1"&gt;type&lt;/span&gt;="&lt;span class="pl-s"&gt;esms-options&lt;/span&gt;"&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="pl-kos"&gt;{&lt;/span&gt;
   &lt;span class="pl-s"&gt;"shimMode"&lt;/span&gt;: &lt;span class="pl-c1"&gt;true&lt;/span&gt;
   &lt;span class="pl-s"&gt;"mapOverrides"&lt;/span&gt;: &lt;span class="pl-c1"&gt;true&lt;/span&gt;
 &lt;span class="pl-kos"&gt;}&lt;/span&gt;
 &lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;script&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;2. Import the importmap directly as a file in the &lt;code&gt;index.html&lt;/code&gt; instead of runtime code in &lt;code&gt;initFederation&lt;/code&gt;
&lt;/h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;The browser can combine directly multiple importmaps and load them for us. I would suggest that instead of executing runtime code, integrating all importmap already generated at compile time directly in the &lt;code&gt;index.html&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight highlight-text-html-basic js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c1"&gt;&amp;lt;!DOCTYPE html&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;html&lt;/span&gt; &lt;span class="pl-c1"&gt;lang&lt;/span&gt;="&lt;span class="pl-s"&gt;en&lt;/span&gt;"&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;head&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;meta&lt;/span&gt; &lt;span class="pl-c1"&gt;charset&lt;/span&gt;="&lt;span class="pl-s"&gt;utf-8&lt;/span&gt;" /&amp;gt;
    &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;title&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;host&lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;title&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;base&lt;/span&gt; &lt;span class="pl-c1"&gt;href&lt;/span&gt;="&lt;span class="pl-s"&gt;/&lt;/span&gt;" /&amp;gt;
    &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;meta&lt;/span&gt; &lt;span class="pl-c1"&gt;name&lt;/span&gt;="&lt;span class="pl-s"&gt;viewport&lt;/span&gt;" &lt;span class="pl-c1"&gt;content&lt;/span&gt;="&lt;span class="pl-s"&gt;width=device-width, initial-scale=1&lt;/span&gt;" /&amp;gt;
    &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;link&lt;/span&gt; &lt;span class="pl-c1"&gt;rel&lt;/span&gt;="&lt;span class="pl-s"&gt;icon&lt;/span&gt;" &lt;span class="pl-c1"&gt;type&lt;/span&gt;="&lt;span class="pl-s"&gt;image/x-icon&lt;/span&gt;" &lt;span class="pl-c1"&gt;href&lt;/span&gt;="&lt;span class="pl-s"&gt;favicon.ico&lt;/span&gt;" /&amp;gt;

    &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;script&lt;/span&gt; &lt;span class="pl-c1"&gt;type&lt;/span&gt;="&lt;span class="pl-s"&gt;importmap-shim&lt;/span&gt;" &lt;span class="pl-c1"&gt;src&lt;/span&gt;="&lt;span class="pl-s"&gt;assets/host-shared.importmap.json&lt;/span&gt;"&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;script&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;script&lt;/span&gt; &lt;span class="pl-c1"&gt;type&lt;/span&gt;="&lt;span class="pl-s"&gt;importmap-shim&lt;/span&gt;" &lt;span class="pl-c1"&gt;src&lt;/span&gt;="&lt;span class="pl-s"&gt;assets/remotes.importmap.json&lt;/span&gt;"&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;script&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;head&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;body&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;nx-nf-root&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;nx-nf-root&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;body&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;html&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;3. Ensure that when we &lt;code&gt;loadRemoteModule&lt;/code&gt;, we obtain the actual version from the &lt;code&gt;importmap&lt;/code&gt;
&lt;/h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;By listening to the DOM mutation like es-module-shim and refreshing the cache&lt;/h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;div class="highlight highlight-source-ts js-code-highlight"&gt;
&lt;pre&gt;  &lt;span class="pl-k"&gt;new&lt;/span&gt; &lt;span class="pl-smi"&gt;MutationObserver&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;mutations&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-c1"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
    &lt;span class="pl-k"&gt;for&lt;/span&gt; &lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; addedNodes&lt;span class="pl-kos"&gt;,&lt;/span&gt; type &lt;span class="pl-kos"&gt;}&lt;/span&gt; &lt;span class="pl-k"&gt;of&lt;/span&gt; &lt;span class="pl-s1"&gt;mutations&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
      &lt;span class="pl-k"&gt;if&lt;/span&gt; &lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;type&lt;/span&gt; &lt;span class="pl-c1"&gt;!==&lt;/span&gt; &lt;span class="pl-s"&gt;'childList'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-k"&gt;continue&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
      &lt;span class="pl-k"&gt;for&lt;/span&gt; &lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;node&lt;/span&gt; &lt;span class="pl-k"&gt;of&lt;/span&gt; &lt;span class="pl-s1"&gt;addedNodes&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
        &lt;span class="pl-k"&gt;if&lt;/span&gt; &lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;node&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;tagName&lt;/span&gt; &lt;span class="pl-c1"&gt;===&lt;/span&gt; &lt;span class="pl-s"&gt;'SCRIPT'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
          &lt;span class="pl-k"&gt;if&lt;/span&gt; &lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;node&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;type&lt;/span&gt; &lt;span class="pl-c1"&gt;===&lt;/span&gt; &lt;span class="pl-s"&gt;'importmap-shim'&lt;/span&gt; &lt;span class="pl-c1"&gt;||&lt;/span&gt; &lt;span class="pl-s1"&gt;node&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;type&lt;/span&gt; &lt;span class="pl-c1"&gt;===&lt;/span&gt; &lt;span class="pl-s"&gt;'importmap'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
            &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;remoteNamesToRemote&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;globalcache&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;remoteNamesToRemote&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
            &lt;span class="pl-c"&gt;// TODO: should update the remoteNamesToRemote by changing the base url&lt;/span&gt;
          &lt;span class="pl-kos"&gt;}&lt;/span&gt;
        &lt;span class="pl-kos"&gt;}&lt;/span&gt;
      &lt;span class="pl-kos"&gt;}&lt;/span&gt;
    &lt;span class="pl-kos"&gt;}&lt;/span&gt;
  &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;observe&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-smi"&gt;document&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-c1"&gt;childList&lt;/span&gt;: &lt;span class="pl-c1"&gt;true&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-c1"&gt;subtree&lt;/span&gt;: &lt;span class="pl-c1"&gt;true&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;The challenge here is that the cache is grouped per remote and only maintains a single base URL, so overriding one &lt;code&gt;exposes&lt;/code&gt; would change the URL for others as well.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;By directly reading the &lt;code&gt;importmap&lt;/code&gt;
&lt;/h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;The impact on performance is uncertain. Having an API library to manipulate &lt;code&gt;importmaps&lt;/code&gt; would be advantageous.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Work Around&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;I have succeeded in overriding the &lt;code&gt;loadRemoteModule&lt;/code&gt; function:&lt;/p&gt;
&lt;div class="highlight highlight-source-ts js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;export&lt;/span&gt; &lt;span class="pl-k"&gt;function&lt;/span&gt; &lt;span class="pl-en"&gt;getImportMapOverride&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;importMapKey&lt;/span&gt;: &lt;span class="pl-smi"&gt;string&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;: &lt;span class="pl-smi"&gt;string&lt;/span&gt; &lt;span class="pl-c1"&gt;|&lt;/span&gt; &lt;span class="pl-c1"&gt;undefined&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
  &lt;span class="pl-c"&gt;// &lt;span class="pl-k"&gt;&lt;a class="mentioned-user" href="https://dev.to/ts"&gt;@ts&lt;/a&gt;&lt;/span&gt;-ignore&lt;/span&gt;
  &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;imports&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-smi"&gt;window&lt;/span&gt;&lt;span class="pl-kos"&gt;?.&lt;/span&gt;&lt;span class="pl-c1"&gt;importMapOverrides&lt;/span&gt;&lt;span class="pl-kos"&gt;?.&lt;/span&gt;&lt;span class="pl-en"&gt;getOverrideMap&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;?.&lt;/span&gt;&lt;span class="pl-c1"&gt;imports&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
  &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-s1"&gt;imports&lt;/span&gt; &lt;span class="pl-c1"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="pl-s1"&gt;imports&lt;/span&gt;&lt;span class="pl-kos"&gt;[&lt;/span&gt;&lt;span class="pl-s1"&gt;importMapKey&lt;/span&gt;&lt;span class="pl-kos"&gt;]&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-kos"&gt;}&lt;/span&gt;

&lt;span class="pl-k"&gt;export&lt;/span&gt; &lt;span class="pl-k"&gt;async&lt;/span&gt; &lt;span class="pl-k"&gt;function&lt;/span&gt; &lt;span class="pl-en"&gt;loadRemoteOverrideUtils&lt;/span&gt;&lt;span class="pl-c1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-smi"&gt;T&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-smi"&gt;any&lt;/span&gt;&lt;span class="pl-c1"&gt;&amp;gt;&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;
  &lt;span class="pl-s1"&gt;remoteName&lt;/span&gt;: &lt;span class="pl-smi"&gt;string&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
  &lt;span class="pl-s1"&gt;exposedModule&lt;/span&gt;: &lt;span class="pl-smi"&gt;string&lt;/span&gt;
&lt;span class="pl-kos"&gt;)&lt;/span&gt;: &lt;span class="pl-smi"&gt;Promise&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-smi"&gt;T&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
  &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;remoteKey&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;`&lt;span class="pl-s1"&gt;&lt;span class="pl-kos"&gt;${&lt;/span&gt;&lt;span class="pl-s1"&gt;remoteName&lt;/span&gt;&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;/span&gt;/&lt;span class="pl-s1"&gt;&lt;span class="pl-kos"&gt;${&lt;/span&gt;&lt;span class="pl-s1"&gt;exposedModule&lt;/span&gt;&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;/span&gt;`&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

  &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;importMapOverrideUrl&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;getImportMapOverride&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;remoteKey&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

  &lt;span class="pl-c"&gt;// If override found for remoteKey, load it separately&lt;/span&gt;
  &lt;span class="pl-c"&gt;// Else, use the default function&lt;/span&gt;
  &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-s1"&gt;importMapOverrideUrl&lt;/span&gt;
    ? &lt;span class="pl-en"&gt;importShim&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-smi"&gt;T&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;importMapOverrideUrl&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
    : &lt;span class="pl-en"&gt;loadRemoteModule&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;remoteName&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;exposedModule&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;But I don't like the fact that the &lt;code&gt;globalCache&lt;/code&gt; of native federation is still invalid.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;full code here &lt;a href="https://github.com/jogelin/nx-nf/tree/poc-load-remote-overrides"&gt;https://github.com/jogelin/nx-nf/tree/poc-load-remote-overrides&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What about directly overriding the &lt;code&gt;federation.manifest.json&lt;/code&gt;?&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;In my opinion, it is the best approach because overriding only one &lt;code&gt;exposes&lt;/code&gt; does not make sense. Usually, we want to override an entire remote URL.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;By using a custom approach&lt;/h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;I implemented an easy way, but custom, but it keeps the &lt;code&gt;globalCache&lt;/code&gt; in sync:&lt;/p&gt;
&lt;p&gt;If you have that override in your &lt;code&gt;localStorage&lt;/code&gt;:
&lt;a rel="noopener noreferrer" href="https://github.com/angular-architects/module-federation-plugin/assets/954509/ae7e8003-0dd2-4ada-b086-ea19347f0ef9"&gt;&lt;img width="470" alt="image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ngSmNMAD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/angular-architects/module-federation-plugin/assets/954509/ae7e8003-0dd2-4ada-b086-ea19347f0ef9"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Directly in the &lt;code&gt;main.ts&lt;/code&gt; you can use:&lt;/p&gt;
&lt;div class="highlight highlight-source-ts js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-en"&gt;initFederation&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'/assets/federation.manifest.json'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
  &lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;then&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-c1"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pl-en"&gt;initFederationOverrides&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-c"&gt;// &amp;lt;-- HERE&lt;/span&gt;
  &lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;catch&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;err&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-c1"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pl-smi"&gt;console&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;error&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;err&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
  &lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;then&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;_&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-c1"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pl-k"&gt;import&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'./bootstrap'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
  &lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;catch&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;err&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-c1"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pl-smi"&gt;console&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;error&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;err&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;utilities functions:&lt;/p&gt;
&lt;div class="highlight highlight-source-ts js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-s1"&gt;processRemoteInfo&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt; &lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s"&gt;'@angular-architects/native-federation'&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-smi"&gt;ImportMap&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt; &lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s"&gt;'./import-map.type'&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-smi"&gt;NATIVE_FEDERATION_LOCAL_STORAGE_PREFIX&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;'native-federation-override:'&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-k"&gt;export&lt;/span&gt; &lt;span class="pl-k"&gt;function&lt;/span&gt; &lt;span class="pl-en"&gt;initFederationOverrides&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;: &lt;span class="pl-smi"&gt;Promise&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-smi"&gt;ImportMap&lt;/span&gt;&lt;span class="pl-kos"&gt;[&lt;/span&gt;&lt;span class="pl-kos"&gt;]&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
  &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;overrides&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;loadNativeFederationOverridesFromStorage&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
  &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;processRemoteInfoPromises&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-smi"&gt;Object&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;entries&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;overrides&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;map&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;
    &lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;[&lt;/span&gt;&lt;span class="pl-s1"&gt;remoteName&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;url&lt;/span&gt;&lt;span class="pl-kos"&gt;]&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-c1"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pl-en"&gt;processRemoteInfo&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;url&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;remoteName&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
  &lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

  &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-smi"&gt;Promise&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;all&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;processRemoteInfoPromises&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-kos"&gt;}&lt;/span&gt;

&lt;span class="pl-k"&gt;function&lt;/span&gt; &lt;span class="pl-en"&gt;loadNativeFederationOverridesFromStorage&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;: &lt;span class="pl-smi"&gt;Record&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-smi"&gt;string&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-smi"&gt;string&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
  &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-smi"&gt;Object&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;entries&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;localStorage&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;reduce&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;overrides&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-kos"&gt;[&lt;/span&gt;&lt;span class="pl-s1"&gt;key&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;url&lt;/span&gt;&lt;span class="pl-kos"&gt;]&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-c1"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
    &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
      ...&lt;span class="pl-s1"&gt;overrides&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
      ...&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;key&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;startsWith&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-smi"&gt;NATIVE_FEDERATION_LOCAL_STORAGE_PREFIX&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-c1"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
        &lt;span class="pl-kos"&gt;[&lt;/span&gt;&lt;span class="pl-s1"&gt;key&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;replace&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-smi"&gt;NATIVE_FEDERATION_LOCAL_STORAGE_PREFIX&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s"&gt;''&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;]&lt;/span&gt;: &lt;span class="pl-s1"&gt;url&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
      &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
  &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;But why not using an &lt;code&gt;importmap&lt;/code&gt; to load the &lt;code&gt;remoteEntry.json&lt;/code&gt; files?&lt;/h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;federation.manifest.json&lt;/code&gt; would then appear as:&lt;/p&gt;
&lt;div class="highlight highlight-source-json js-code-highlight"&gt;
&lt;pre&gt;{
    &lt;span class="pl-ii"&gt;imports: {&lt;/span&gt;
        &lt;span class="pl-ent"&gt;"host"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;http://localhost:4200/remoteEntry.json&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
    &lt;span class="pl-ent"&gt;"mfAccount"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;http://localhost:4203/remoteEntry.json&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
    &lt;span class="pl-ent"&gt;"mfHome"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;http://localhost:4201/remoteEntry.json&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
    &lt;span class="pl-ent"&gt;"mfLogin"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;http://localhost:4202/remoteEntry.json&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
    }
&lt;span class="pl-ii"&gt;}&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;and directly integrate it into the index.html:&lt;/p&gt;
&lt;div class="highlight highlight-text-html-basic js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c1"&gt;&amp;lt;!DOCTYPE html&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;html&lt;/span&gt; &lt;span class="pl-c1"&gt;lang&lt;/span&gt;="&lt;span class="pl-s"&gt;en&lt;/span&gt;"&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;head&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;meta&lt;/span&gt; &lt;span class="pl-c1"&gt;charset&lt;/span&gt;="&lt;span class="pl-s"&gt;utf-8&lt;/span&gt;" /&amp;gt;
    &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;title&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;host&lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;title&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;base&lt;/span&gt; &lt;span class="pl-c1"&gt;href&lt;/span&gt;="&lt;span class="pl-s"&gt;/&lt;/span&gt;" /&amp;gt;
    &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;meta&lt;/span&gt; &lt;span class="pl-c1"&gt;name&lt;/span&gt;="&lt;span class="pl-s"&gt;viewport&lt;/span&gt;" &lt;span class="pl-c1"&gt;content&lt;/span&gt;="&lt;span class="pl-s"&gt;width=device-width, initial-scale=1&lt;/span&gt;" /&amp;gt;
    &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;link&lt;/span&gt; &lt;span class="pl-c1"&gt;rel&lt;/span&gt;="&lt;span class="pl-s"&gt;icon&lt;/span&gt;" &lt;span class="pl-c1"&gt;type&lt;/span&gt;="&lt;span class="pl-s"&gt;image/x-icon&lt;/span&gt;" &lt;span class="pl-c1"&gt;href&lt;/span&gt;="&lt;span class="pl-s"&gt;favicon.ico&lt;/span&gt;" /&amp;gt;

    &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;script&lt;/span&gt; &lt;span class="pl-c1"&gt;type&lt;/span&gt;="&lt;span class="pl-s"&gt;importmap-shim&lt;/span&gt;" &lt;span class="pl-c1"&gt;src&lt;/span&gt;="&lt;span class="pl-s"&gt;assets/federation.manifest.json&lt;/span&gt;"&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;script&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;head&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;body&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;nx-nf-root&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;nx-nf-root&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;body&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;html&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;and in the &lt;code&gt;initFederation&lt;/code&gt;, we just need to use:&lt;/p&gt;
&lt;div class="highlight highlight-source-ts js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;import&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'mfAccount'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;then&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;remoteEntry&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-c1"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pl-c"&gt;// same as before, inject exposes to inline importmap)&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;In this way:
✅ It is standard
✅ We use &lt;code&gt;importmap&lt;/code&gt; everywhere
✅ We can use default override behaviour
✅ It allows to override a full remote AND exposes separately&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What do you Think?&lt;/strong&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Do you want to make a PR?&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;Yes of course after discussion :)&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/angular-architects/module-federation-plugin/issues/489"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;However, the underlying principles remain unchanged. Rather than directly utilizing the &lt;code&gt;importmap.json&lt;/code&gt;, I have the option to override the &lt;code&gt;federation.manifest.json&lt;/code&gt;. This requires the creation of custom code within the application to enable the overrides of the bundles.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Do you want to try it?&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;First, clone my GitHub repository:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone git@github.com:jogelin/nx-nf.git &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;nx-nf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;2. Begin by installing the packages:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;3. Next, you can start one micro frontend, for example, &lt;code&gt;mf-admin&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx nx run mf-admin:serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;4. Then, access the URL &lt;a href="https://nx-nf-a2d7c.web.app/admin"&gt;https://nx-nf-a2d7c.web.app/admin&lt;/a&gt; where I have already deployed the application. You should see the application:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr4wp9btmpbv8mvnqu6z9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr4wp9btmpbv8mvnqu6z9.png" alt="Image description" width="800" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;5. Now, open your favorite browser debugging tool and connect your local server to the remote application by adding this entry in the local storage:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;native-federation-override:mfAdmin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:4203/remoteEntry.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// override mfAdmin with you local server&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;6. Then, make modifications to the &lt;code&gt;mf-admin&lt;/code&gt; micro frontend. For example, change the message from "Welcome to the Admin Page" to “Welcome to the LOCAL Admin Page”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5f9rt2ovmy8bbh9gpt1r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5f9rt2ovmy8bbh9gpt1r.png" alt="Image description" width="686" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;7. After you make changes, reload the page, and you should see your modifications reflected on the remote server immediately!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F83vl3mpgm4rx1o5hty0e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F83vl3mpgm4rx1o5hty0e.png" alt="Image description" width="800" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;8. To revert the changes, simply remove the entry from the local storage and refresh the page to see the original state again.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;native-federation-override:mfAdmin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You can override any micro frontend using this approach. However, as I mentioned, the method involving native federation is not entirely native yet because it doesn’t utilize the default behavior of import maps.&lt;/p&gt;

&lt;p&gt;You can find all the code utilizing Native Federation, Angular, and Nx in my GitHub repository.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/jogelin"&gt;
        jogelin
      &lt;/a&gt; / &lt;a href="https://github.com/jogelin/nx-nf"&gt;
        nx-nf
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      POC repository showing Nx Native Federation and Importmap Override Configurations
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;NxNf&lt;/h1&gt;

&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;&lt;a href="https://jgelin.medium.com/its-time-to-talk-about-import-map-micro-frontend-and-nx-monorepo-0b8e2c07568a" rel="nofollow"&gt;⏰ It’s time to talk about Import Map, Micro Frontend, and Nx Monorepo&lt;/a&gt;&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;How leveraging native import map overrides can significantly benefit your micro frontend architecture&lt;/p&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/jogelin/nx-nf"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;Final Thoughts&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This exploration reveals the power of the native JavaScript ecosystem in browsers, highlighting how native support for ES modules enhances our development experience beyond faster build times.&lt;/p&gt;

&lt;p&gt;The simplicity and effectiveness of the import map principle show us a way to solve complex issues with elegant solutions. It hints at a future where reliance on custom framework implementations diminishes in favor of native browser features, making development smoother and more intuitive.&lt;/p&gt;

&lt;p&gt;Moreover, the use of Nx as part of this ecosystem offers a powerful toolkit that enables developers to approach complex projects with enhanced agility and precision.&lt;/p&gt;

&lt;p&gt;The hope for more native features like these grows, promising a simpler, yet more powerful development landscape. With Nx and advancements in browser capabilities, we’re moving towards a future where building sophisticated web applications becomes more accessible and efficient.&lt;/p&gt;

&lt;p&gt;🚀 Stay Tuned!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Credits&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://medium.com/u/a142a504a37c?source=post_page-----0b8e2c07568a--------------------------------"&gt;&lt;strong&gt;Joel Denning&lt;/strong&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Joel Denning is the visionary behind &lt;a href="https://single-spa.js.org/"&gt;single-spa&lt;/a&gt;, boasting profound insights into the true mechanics of the web and is, in my view, a pioneer in micro frontend architecture. I highly recommend checking the &lt;a href="https://single-spa.js.org/"&gt;single-spa&lt;/a&gt; website and his &lt;a href="https://www.youtube.com/@jbdenning/videos"&gt;YouTube channel&lt;/a&gt;. While the videos might appear dated at first glance, rest assured, Joel is ahead of his time, and the content remains incredibly relevant today.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flcho817cmtebvwwjmagc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flcho817cmtebvwwjmagc.png" alt="Image description" width="800" height="204"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Engineer, Architect, Speaker, Trainer, Consultant, and Author, Manfred knows what he is talking about. For everyone, not just Angular, interested in micro frontends and web architecture in general, I encourage you to have a look at his book &lt;a href="https://www.angulararchitects.io/en/ebooks/micro-frontends-and-moduliths-with-angular/"&gt;Enterprise Angular: Micro Frontends and Moduliths with Angular&lt;/a&gt; and the blog of the &lt;a href="https://www.angulararchitects.io/en/blog/"&gt;Angular Architect&lt;/a&gt; team.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F31il46v1v1jdxeqyp8vy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F31il46v1v1jdxeqyp8vy.png" alt="Image description" width="400" height="518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Start a Collaboration?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Connect with me on &lt;a href="https://twitter.com/jonathan_gelin"&gt;&lt;strong&gt;Twitter&lt;/strong&gt;&lt;/a&gt; • &lt;a href="https://www.linkedin.com/in/jonathan-gelin/"&gt;&lt;strong&gt;LinkedIn&lt;/strong&gt;&lt;/a&gt; • &lt;a href="https://github.com/jogelin"&gt;&lt;strong&gt;Github&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>microfrontends</category>
      <category>angular</category>
      <category>nx</category>
      <category>react</category>
    </item>
    <item>
      <title>💎 Discovering Nx Project Crystal’s Magic</title>
      <dc:creator>jogelin</dc:creator>
      <pubDate>Mon, 26 Feb 2024 17:01:51 +0000</pubDate>
      <link>https://forem.com/jogelin/discovering-nx-project-crystals-magic-6i7</link>
      <guid>https://forem.com/jogelin/discovering-nx-project-crystals-magic-6i7</guid>
      <description>

&lt;h2&gt;
  
  
  &lt;strong&gt;Overview&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;After delving into this feature in my previous articles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://jgelin.medium.com/nx-targets-elevated-part-one-f421062818e6"&gt;🚡 Nx Targets Elevated (Part One)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jgelin.medium.com/nx-targets-elevated-part-two-9edc56cf1a00"&gt;🚡 Nx Targets Elevated (Part Two)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jgelin.medium.com/%EF%B8%8F-nx-plugin-v2-dynamic-project-configurations-6055ba700105"&gt;✌️ Nx Plugin v2: Dynamic Project Configurations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’m excited to discuss again one of my favorite Nx features: &lt;strong&gt;“The Inferred Project Configurations.”&lt;/strong&gt; The &lt;a href="https://medium.com/u/2817fb68583?source=post_page-----7f42faf2a135--------------------------------"&gt;Nx&lt;/a&gt; team now introduces a unified approach known as &lt;a href="https://nx.dev/concepts/inferred-tasks"&gt;&lt;strong&gt;Nx Project Crystal&lt;/strong&gt;&lt;/a&gt; 💎.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In this article, I’ll cover:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;· &lt;a href="https://medium.com/@jgelin/discovering-nx-project-crystals-magic-7f42faf2a135#c775"&gt;The Origin&lt;/a&gt;&lt;br&gt;
· &lt;a href="https://medium.com/@jgelin/discovering-nx-project-crystals-magic-7f42faf2a135#ea77"&gt;Project Crystal in a Nutshell&lt;/a&gt;&lt;br&gt;
· &lt;a href="https://medium.com/@jgelin/discovering-nx-project-crystals-magic-7f42faf2a135#7f8a"&gt;How it works&lt;/a&gt;&lt;br&gt;
· &lt;a href="https://medium.com/@jgelin/discovering-nx-project-crystals-magic-7f42faf2a135#8a48"&gt;Create Your Cyrstal Plugin&lt;/a&gt;&lt;br&gt;
· &lt;a href="https://medium.com/@jgelin/discovering-nx-project-crystals-magic-7f42faf2a135#083b"&gt;A Multitude of Benefits&lt;/a&gt;&lt;br&gt;
· &lt;a href="https://medium.com/@jgelin/discovering-nx-project-crystals-magic-7f42faf2a135#aa78"&gt;Cautions&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;The Origin&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To grasp the concept of &lt;a href="https://nx.dev/concepts/inferred-tasks"&gt;&lt;strong&gt;Nx Project Crystal&lt;/strong&gt;&lt;/a&gt; 💎, let’s revisit the &lt;a href="https://medium.com/u/2817fb68583?source=post_page-----7f42faf2a135--------------------------------"&gt;Nx&lt;/a&gt; team’s journey in project configuration.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;1. angular.json&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;“In the beginning, there was nothing”.&lt;/em&gt;&lt;/strong&gt; The &lt;a href="https://medium.com/u/2817fb68583?source=post_page-----7f42faf2a135--------------------------------"&gt;Nx&lt;/a&gt; team began defining a monorepo structure for apps and libs using &lt;a href="https://angular.io/guide/workspace-config"&gt;&lt;code&gt;angular.json&lt;/code&gt;&lt;/a&gt;, tied to &lt;a href="https://angular.io/cli"&gt;Angular CLI&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyu3i0tzu6qizs9hyxpva.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyu3i0tzu6qizs9hyxpva.png" alt="angular.json" width="800" height="567"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, this initial approach was specific to Angular, lacking generality and extensibility.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;2. workspace.json&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;A v2 schema introduced the&lt;a href="https://nx.dev/deprecated/workspace-json#workspacejson"&gt;&lt;code&gt;workspace.json&lt;/code&gt;&lt;/a&gt; files*&lt;em&gt;.&lt;/em&gt;* Some concepts were generalized such as the &lt;a href="https://nx.dev/concepts/more-concepts/nx-and-angular#executors-vs-builders-generators-vs-schematics"&gt;executors (instead of a builder) or the generators (instead of schematics).&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi4snxsbg4hwwseyzwm5w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi4snxsbg4hwwseyzwm5w.png" alt="workspace.json" width="800" height="594"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The new format proved useful due to its extensibility and generality. However, maintaining a large codebase within a single file presented challenges. Consequently, the demand for greater flexibility and project-specific specifications increased.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;3. project.json&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Thus, the concept of distributed configuration emerged with the &lt;a href="https://nx.dev/core-tutorial/02-create-cli#projectjson-syntax"&gt;&lt;code&gt;project.json&lt;/code&gt;&lt;/a&gt; (or package.json) file. It maintained the same format but was divided and specified at the root of each project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnc6pzrf05ywgtvqduih0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnc6pzrf05ywgtvqduih0.png" alt="project.json" width="800" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Defining a project has become straightforward — simply add that file, and you’re done. However, the proliferation of files implies challenging maintenance due to significant duplication. This situation necessitated the development of migration scripts to manage these configurations effectively.&lt;/p&gt;

&lt;p&gt;Additionally, there emerged a requirement to support technologies not adhering to Nx’s standards, enabling the integration of Nx benefits into existing repositories and accommodating various technologies, including &lt;code&gt;.Net&lt;/code&gt;, among others.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;4. Inferred configuration&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Then, &lt;strong&gt;project inference&lt;/strong&gt; appeared, introducing the possibility of assigning project configurations simply through &lt;strong&gt;glob pattern matching&lt;/strong&gt;. &lt;a href="https://nx.dev/extending-nx/tutorials/create-plugin"&gt;An Nx plugin&lt;/a&gt; exposes specific functions that are automatically loaded by the Nx core, and voilà, you have dynamic configuration :)&lt;/p&gt;

&lt;p&gt;It began with &lt;a href="https://nx.dev/deprecated/v1-nx-plugin-api"&gt;Plugin v1&lt;/a&gt;, which only assigned a list of targets for existing projects (see &lt;a href="https://jgelin.medium.com/nx-targets-elevated-part-one-f421062818e6"&gt;🚡 Nx Targets Elevated&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqqktsq8xreru0qyhqca5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqqktsq8xreru0qyhqca5.png" alt="Inferred configuration 1" width="800" height="212"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then came &lt;a href="https://nx.dev/extending-nx/recipes/project-graph-plugins"&gt;Plugin v2&lt;/a&gt;, offering the ability to dynamically add project nodes with full configuration, even if they do not exist in your codebase (see &lt;a href="https://jgelin.medium.com/%EF%B8%8F-nx-plugin-v2-dynamic-project-configurations-6055ba700105"&gt;✌️ Nx Plugin v2: Dynamic Project Configurations&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fedriuce44tp49s1i0ypj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fedriuce44tp49s1i0ypj.png" alt="Inferred configuration 2" width="800" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And finally, a consolidated approach to that concept was integrated into Nx:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fztohwen80jbzo9087wu7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fztohwen80jbzo9087wu7.png" alt="Image description" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Project Crystal in a Nutshell&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Nx Project Crystal&lt;/strong&gt; offers the ability to utilize Nx plugins that automatically add tasks to your projects based on the configuration files of various tools.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I recommend watching the great video&lt;/em&gt; &lt;a href="https://www.youtube.com/watch?v=wADNsVItnsM"&gt;&lt;em&gt;Nx — Project Crystal&lt;/em&gt;&lt;/a&gt; &lt;em&gt;and reading the related article&lt;/em&gt; &lt;a href="https://blog.nrwl.io/what-if-nx-plugins-were-more-like-vscode-extensions-dcdad140ae09"&gt;&lt;em&gt;What if Nx Plugins Were More Like VSCode Extensions&lt;/em&gt;&lt;/a&gt; &lt;em&gt;by&lt;/em&gt; &lt;a href="https://medium.com/u/71b649cf0618?source=post_page-----7f42faf2a135--------------------------------"&gt;Juri Strumpflohner&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;a href="https://medium.com/u/2817fb68583?source=post_page-----7f42faf2a135--------------------------------"&gt;Nx&lt;/a&gt; team likes to compare it to a simple plugin that you’ll add to your favorite IDE. You don’t need to do anything else; the plugin activates functionalities automatically because it recognizes specific configurations or patterns in your workspace.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For example&lt;/strong&gt;, if you want to use &lt;a href="https://vitejs.dev/"&gt;Vite&lt;/a&gt; to build your application, you simply need to add the &lt;a href="https://nx.dev/nx-api/vite/documents/overview#how-nxvite-infers-tasks"&gt;@nx/vite plugin&lt;/a&gt; to your Nx workspace by using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nx add @nx/vite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Automatically, all projects that contain a &lt;code&gt;vite.config.*&lt;/code&gt; file will have new tasks assigned. You will be able to use &lt;code&gt;build&lt;/code&gt;, &lt;code&gt;preview&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt;, &lt;code&gt;serve&lt;/code&gt; and &lt;code&gt;serve-static&lt;/code&gt; directly:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr6vp6wle72gbwt5qarn5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr6vp6wle72gbwt5qarn5.png" alt="inject vite target" width="800" height="185"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is true for Vite, but it is also applies to many other plugins, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://nx.dev/nx-api/webpack#how-nxwebpack-infers-tasks"&gt;@nx/webpack&lt;/a&gt; → &lt;code&gt;build&lt;/code&gt;, &lt;code&gt;preview&lt;/code&gt;, &lt;code&gt;serve&lt;/code&gt; and &lt;code&gt;serve-static&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://nx.dev/nx-api/cypress/documents/overview#how-nxcypress-infers-tasks"&gt;@nx/cypress&lt;/a&gt; → &lt;code&gt;e2e&lt;/code&gt;, &lt;code&gt;e2e-ci&lt;/code&gt; and &lt;code&gt;component-test&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://nx.dev/nx-api/playwright/documents/overview#how-nxplaywright-infers-tasks"&gt;@nx/playwright&lt;/a&gt; → &lt;code&gt;e2e&lt;/code&gt;, &lt;code&gt;e2e-ci&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://nx.dev/nx-api/detox/documents/overview#how-nxdetox-infers-tasks"&gt;@nx&lt;/a&gt;/&lt;a href="https://nx.dev/nx-api/detox/documents/overview#how-nxdetox-infers-tasks"&gt;detox&lt;/a&gt; → &lt;code&gt;build&lt;/code&gt;, &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://nx.dev/nx-api/eslint/documents/overview#how-nxeslint-infers-tasks"&gt;@nx/eslint&lt;/a&gt; → &lt;code&gt;lint&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://nx.dev/nx-api/expo/documents/overview#how-nxexpo-infers-tasks"&gt;@nx/expo&lt;/a&gt; → &lt;code&gt;start&lt;/code&gt;, &lt;code&gt;serve&lt;/code&gt;, &lt;code&gt;run-ios&lt;/code&gt;, &lt;code&gt;run-android&lt;/code&gt;, &lt;code&gt;export&lt;/code&gt;, &lt;code&gt;prebuild&lt;/code&gt;, &lt;code&gt;install&lt;/code&gt;, &lt;code&gt;build&lt;/code&gt; and &lt;code&gt;submit&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://nx.dev/nx-api/jest/documents/overview#how-nxjest-infers-tasks"&gt;@nx/jest&lt;/a&gt; → &lt;code&gt;test&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://nx.dev/nx-api/next/documents/overview#how-nxnext-infers-tasks"&gt;@nx/next&lt;/a&gt; → &lt;code&gt;build&lt;/code&gt;, &lt;code&gt;dev&lt;/code&gt;, &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;serve-static&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://nx.dev/nx-api/nuxt/documents/overview#how-nxnuxt-infers-tasks"&gt;@nx/nuxt&lt;/a&gt; → &lt;code&gt;build&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt; and &lt;code&gt;serve&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://nx.dev/nx-api/react-native/documents/overview#how-nxreactnative-infers-tasks"&gt;@nx/react-native&lt;/a&gt; → &lt;code&gt;start&lt;/code&gt;, &lt;code&gt;pod-install&lt;/code&gt;, &lt;code&gt;bundle&lt;/code&gt;, &lt;code&gt;run-ios&lt;/code&gt;, &lt;code&gt;run-android&lt;/code&gt;, &lt;code&gt;build-io&lt;/code&gt; and &lt;code&gt;build-android&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://nx.dev/nx-api/remix/documents/overview#how-nxremix-infers-tasks"&gt;@nx/remix&lt;/a&gt; → &lt;code&gt;build&lt;/code&gt;, &lt;code&gt;serve&lt;/code&gt;, &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;typecheck&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://nx.dev/nx-api/storybook/documents/overview#how-nxstorybook-infers-tasks"&gt;@nx/storybook&lt;/a&gt; → &lt;code&gt;build-storybook&lt;/code&gt;, &lt;code&gt;storybook&lt;/code&gt;, &lt;code&gt;test-storybook&lt;/code&gt; and &lt;code&gt;static-storybook&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why don’t I see the main plugins like&lt;/strong&gt; &lt;a href="https://nx.dev/nx-api/angular/documents/overview"&gt;&lt;strong&gt;@nx/angular&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;or&lt;/strong&gt; &lt;a href="https://nx.dev/nx-api/react/documents/overview"&gt;&lt;strong&gt;@nx/react&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your Angular/React project configurations have already been simplified through the removal of common targets like &lt;code&gt;lint&lt;/code&gt; or &lt;code&gt;test&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, it’s challenging to generalize targets like build or serve because they involve many specifications unique to your app.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;IMO, it’s only a matter of time before the&lt;/em&gt; &lt;a href="https://medium.com/u/2817fb68583?source=post_page-----7f42faf2a135--------------------------------"&gt;Nx&lt;/a&gt; team proposes a solution for this :).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How it works&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Let’s take a look behind the scenes to understand how we can benefit from this feature.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgo6qldso543j0bi7djeb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgo6qldso543j0bi7djeb.png" alt="How it works" width="800" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, Nx computes the project graph configuration by loading configurations from multiple places:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;First, it iterates over the plugin list declared in your &lt;code&gt;nx.json&lt;/code&gt; and calls the &lt;code&gt;createNodes&lt;/code&gt; function for each.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Then, it reads &lt;code&gt;targetDefaults&lt;/code&gt; in the &lt;code&gt;nx.json&lt;/code&gt; file and it applies the default configuration to the corresponding targets.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, it uses the configuration from the &lt;code&gt;project.json&lt;/code&gt; (or package.json), if specified at the root of the project.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;How do I know which task is available at the end?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Nx provided a solution for that too! You can &lt;a href="https://nx.dev/features/explore-graph"&gt;explore your Nx workspace&lt;/a&gt; and see the consolidated configuration simply by running the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nx show project myreactapp &lt;span class="nt"&gt;--web&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you will be able to visualize all of the configurations for your project&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdor861hsxj4lg9qw72q3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdor861hsxj4lg9qw72q3.png" alt="UI configs" width="800" height="592"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This is also visible in the&lt;/em&gt; &lt;a href="https://nx.dev/recipes/nx-console"&gt;&lt;em&gt;Nx console plugin&lt;/em&gt;&lt;/a&gt; &lt;em&gt;in your IDE!&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Create Your Cyrstal Plugin&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Let’s explore how quickly you can implement your plugin, injecting your configurations and behaviors into your workspace.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Nx Plugin&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The first step is to &lt;a href="https://nx.dev/plugins/tutorials/create-plugin#create-a-local-plugin"&gt;create an Nx plugin&lt;/a&gt; and configure it in your &lt;code&gt;nx.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It can be a simple &lt;code&gt;*.ts&lt;/code&gt; file located anywhere in your workspace that you &lt;a href="https://nx.dev/plugins/recipes/project-inference-plugins#adding-plugins-to-workspace"&gt;register in your &lt;code&gt;nx.json&lt;/code&gt;&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"plugins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./tools/plugins/my-plugin.ts"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or you can use the plugin generator by executing the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nx g @nx/plugin:plugin my-plugin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And again, you’ll need to &lt;a href="https://nx.dev/plugins/recipes/project-inference-plugins#adding-plugins-to-workspace"&gt;register your plugin in your &lt;code&gt;nx.json&lt;/code&gt;&lt;/a&gt; configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"plugins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@my-org/my-plugin"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also provide options to your plugin by using the following syntax in your &lt;code&gt;nx.josn&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"plugins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"plugin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@my-org/my-plugin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"targetName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"build"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Export the createNodes from your plugin&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Then, you can begin implementing your plugin. I highly recommend examining some existing Nx plugin implementations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;For simplicity, look at &lt;a href="https://github.com/nrwl/nx/blob/master/packages/eslint/src/plugins/plugin.ts"&gt;@nx/eslint&lt;/a&gt; or &lt;a href="https://github.com/nrwl/nx/blob/master/packages/jest/src/plugins/plugin.ts"&gt;@nx/jest&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For more advanced task distribution, consider &lt;a href="https://github.com/nrwl/nx/blob/master/packages/cypress/src/plugins/plugin.ts"&gt;@nx/cypress&lt;/a&gt; or &lt;a href="https://github.com/nrwl/nx/blob/master/packages/playwright/src/plugins/plugin.ts"&gt;@nx/playwright&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For custom implementations, check out &lt;a href="https://github.com/nx-dotnet/nx-dotnet/blob/84f35f133e35b1aa60b66d183bf8a3b50db6517a/packages/core/src/graph/create-nodes.ts#L97"&gt;@nx-dotnet/core&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I chose the &lt;a href="https://github.com/nrwl/nx/blob/master/packages/vite/src/plugins/plugin.ts"&gt;@nx/vite&lt;/a&gt; plugin to illustrate the mechanism:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd2p55mb0gz0cykfr4ebu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd2p55mb0gz0cykfr4ebu.png" alt="vite create target" width="800" height="907"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Many functions are omitted because they are specific to the plugin and not necessary to grasp the main structure of the plugin.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I divided the code into three main parts:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A. The plugin options contract&lt;/strong&gt;: Typically used to define the names of the targets you wish to generate, but it can be used for anything.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;B. The targets memoization&lt;/strong&gt;: Since generating the configuration graph is resource-intensive, the &lt;a href="https://en.wikipedia.org/wiki/Memoization"&gt;&lt;strong&gt;memoization&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;pattern&lt;/strong&gt; is essential to prevent unnecessary computation when nothing changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C. The main&lt;/strong&gt; &lt;a href="https://nx.dev/extending-nx/recipes/project-graph-plugins"&gt;&lt;code&gt;createNodes&lt;/code&gt;&lt;/a&gt; &lt;strong&gt;function&lt;/strong&gt;: This function is invoked by Nx and returns new project configurations.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;createNodes&lt;/code&gt; function is a pair consisting of a &lt;strong&gt;glob pattern&lt;/strong&gt; to determine when the plugin should be activated &lt;strong&gt;and a function&lt;/strong&gt; that receives the activation context as a parameter and can return a project configuration.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;configFilePath&lt;/code&gt; contains the path matching the glob pattern, representing the project’s root path.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Even if the glob pattern matches, it’s possible to &lt;strong&gt;filter out and skip execution&lt;/strong&gt; if it doesn’t meet a specific criterion. Here, the criterion is to assign tasks only to existing projects.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Since the &lt;strong&gt;options are optional&lt;/strong&gt;, they simply provide a way to set default values for target names.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This forms the core of the function, &lt;strong&gt;generating all tasks or retrieving them from the cache&lt;/strong&gt; if they exist.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It then creates and &lt;strong&gt;returns the project configuration&lt;/strong&gt; to be incorporated into the global project configuration graph.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;A Multitude of Benefits&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;You’ll gain from project inference and creating your plugin in several compelling use cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Remove duplication of configurations&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Adhering to the “&lt;a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself"&gt;&lt;strong&gt;Don’t Repeat Yourself&lt;/strong&gt;&lt;/a&gt;” principle becomes straightforward. If your workspace is cluttered with redundant &lt;code&gt;project.json&lt;/code&gt; configurations, creating plugins to inject common elements significantly eases long-term maintenance.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Centralize your workspace conventions&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;As I discussed in my previous article &lt;a href="https://jgelin.medium.com/the-super-power-of-conventions-with-nx-8d418150b679"&gt;⚡ The Super Power of Conventions with Nx&lt;/a&gt;, for teams managing large codebases, enhancing the development experience through established conventions is invaluable. These can be rules or best practices, encapsulated within an Nx plugin to uniformly apply across your workspace.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Speed up the Nx adoption on the existing repository!&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;That’s one of my favorite use cases, just add Nx and plugins to your existing repo, and you’ll access many functionalities automatically.&lt;/p&gt;

&lt;p&gt;But before having the possibility to &lt;strong&gt;execute tasks&lt;/strong&gt;, you need to ensure that Nx can &lt;strong&gt;see your projects&lt;/strong&gt;. The first reflex is to create a &lt;code&gt;project.json&lt;/code&gt; file everywhere you want to declare a project.&lt;/p&gt;

&lt;p&gt;However, it will be difficult if you have to define hundreds of &lt;code&gt;project.json&lt;/code&gt; with the same configuration. It can also be projects that are not even related to JavaScript projects. In that case, the creation of custom plugins will facilitate that definition in a short time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For example&lt;/strong&gt;, if you have a huge list of themes containing only &lt;code&gt;*.scss&lt;/code&gt; files like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── apps/
└── libs/
    └── themes/
        ├── core/
        ├── blue/
        │   ├── components/
        │   ├── colors.scss
        │   ├── variables.scss
        │   └── index.scss
        ├── dark/
        │   └── ...
        ├── light/
        │   └── ...
        ├── yellow/
        │   └── ...
        └── pink/
            └── ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to see the dependencies between the applications and the themes, you can simply create a plugin that will expose the themes as projects in Nx:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createNodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CreateNodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;libs/themes/**/index.scss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;configFilePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;toProjectName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;configFilePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;projects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`theme-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;configFilePath&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="na"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
              &lt;span class="c1"&gt;// ...&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Automatically, without having to create any &lt;code&gt;project.json&lt;/code&gt; file, you will see them in your dependency graph and gain the benefit of Nx features such as affected, caching, boundaries, etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Task Distributions on CI&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Another interesting use case is the dynamic creation of tasks to parallelize executions that could be time-consuming.&lt;/p&gt;

&lt;p&gt;By dividing long-running tasks into multiple tasks, you can benefit from the Nx &lt;a href="https://nx.dev/ci/features/distribute-task-execution"&gt;Distribution Task Execution&lt;/a&gt; on CI and parallelize all tasks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For example&lt;/strong&gt;, Nx has implemented this approach for Cypress or Playwright by &lt;a href="https://nx.dev/ci/features/split-e2e-tasks"&gt;automatically splitting E2E tasks by file&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;If you are interested in technical details, you can also read my article&lt;/em&gt; &lt;a href="https://medium.com/@jgelin/nx-distribute-e2e-task-execution-for-playwright-and-cypress-e3aa8811842a"&gt;&lt;em&gt;⚡ Distributed e2e Task Execution with Nx for Playwright and Cypress&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Less complex generators and migrations&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;When I started using the project inference, the main concern was &lt;strong&gt;“It will break the&lt;/strong&gt; &lt;a href="https://nx.dev/extending-nx/recipes/migration-generators"&gt;&lt;strong&gt;migration process of Nx&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;!”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Indeed!&lt;/strong&gt; But before Nx Project Crystal, project inference was only used for specific use cases with custom executors not covered by Nx migrations.&lt;/p&gt;

&lt;p&gt;🤯 &lt;strong&gt;Previously&lt;/strong&gt;, supporting advanced project configurations required creating complex generators for complex &lt;code&gt;project.json&lt;/code&gt; files.&lt;/p&gt;

&lt;p&gt;Maintaining these was challenging. With every change, we needed to update the generator and create a migration script to apply modifications across all projects.&lt;/p&gt;

&lt;p&gt;This was time-consuming and frustrating, especially when migrations were buggy.&lt;/p&gt;

&lt;p&gt;😎 &lt;strong&gt;Now&lt;/strong&gt;, with the project inference approach, you can centralize your specific configurations. If something changes, you simply update your plugins, and the changes are automatically applied to all projects.&lt;/p&gt;

&lt;p&gt;No need for complex generators or migrations anymore!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Cautions&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://nx.dev/concepts/inferred-tasks#plugin-order-matters"&gt;&lt;strong&gt;Plugins Order Matters&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;!&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;As highlighted in the flow chart, configurations are not deeply merged, meaning if two plugins configure the same target name, only the last one will take precedence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For instance&lt;/strong&gt;, if your nx.json includes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "plugins": ["@nx/cypress/plugin", "@nx/playwright/plugin"]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And a project contains both &lt;code&gt;Cypress&lt;/code&gt; and &lt;code&gt;Playwright&lt;/code&gt; tests, Nx will first invoke &lt;code&gt;@nx/cypress&lt;/code&gt; and then &lt;code&gt;@nx/playwright&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmu4c5sk1oahzyd6m1s7d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmu4c5sk1oahzyd6m1s7d.png" alt="overlap" width="800" height="298"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To address this&lt;/strong&gt;, you can rename one of the targets using the plugin options in &lt;code&gt;nx.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"plugins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"plugin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@nx/cypress/plugin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"targetName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"e2e-legacy"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"@nx/playwright/plugin"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows you to run both targets:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc21115h2rve94cdgq7zc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc21115h2rve94cdgq7zc.png" alt="solution" width="800" height="181"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://nx.dev/concepts/inferred-tasks#overriding-inferred-task-configuration"&gt;&lt;strong&gt;Configs Order Matters&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;!&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;It’s also important to note that &lt;code&gt;targetDefaults&lt;/code&gt; configurations in your &lt;code&gt;nx.json&lt;/code&gt; take precedence over plugins.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For example&lt;/strong&gt;, if a plugin returns a configuration like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"my-app"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"executor"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@angular-devkit/build-angular:application"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"dependsOn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"^build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"generate-api"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"generate-api"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"executor"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But in your &lt;code&gt;nx.json&lt;/code&gt;, you’ve specified &lt;code&gt;targetDefaults&lt;/code&gt; like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"targetDefaults"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"dependsOn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"^build"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then your &lt;code&gt;generate-api&lt;/code&gt; target won’t be executed because the &lt;code&gt;targetDefaults&lt;/code&gt; will override the &lt;code&gt;dependsOn&lt;/code&gt; configuration.&lt;/p&gt;

&lt;p&gt;I would recommend being specific in your &lt;code&gt;targetDefaults&lt;/code&gt; to prevent conflicts with the plugins.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"targetDefaults"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@angular-devkit/build-angular:application"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"dependsOn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"^build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"generate-api"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Final Thoughts&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The journey the &lt;a href="https://medium.com/u/2817fb68583?source=post_page-----7f42faf2a135--------------------------------"&gt;Nx&lt;/a&gt; team embarked on to bring Project Crystal to life has been truly inspiring. From the early days of Angular-specific setups to the seamless approach offered by Project Crystal, every step has shown their dedication to making our lives as developers easier.&lt;/p&gt;

&lt;p&gt;Looking ahead, the idea of Zero Configuration repositories sounds like an exciting leap forward. It promises a future where setting up and managing projects will be a breeze, giving us more time to focus on what we love: building awesome software.&lt;/p&gt;

&lt;p&gt;So let’s embrace tools like Nx Project Crystal with open arms. They’re here to help us work smarter, not harder, and together, we can unlock endless possibilities for innovation and creativity in our development journeys.&lt;/p&gt;

&lt;p&gt;Your feedback and suggestions are always welcome! 🚀 Stay Tuned!&lt;br&gt;&lt;br&gt;
&lt;a href="https://twitter.com/jonathan_gelin"&gt;&lt;strong&gt;Twitter&lt;/strong&gt;&lt;/a&gt; — &lt;a href="https://www.linkedin.com/in/jonathan-gelin/"&gt;&lt;strong&gt;LinkedIn&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;—&lt;/strong&gt; &lt;a href="https://github.com/jogelin"&gt;&lt;strong&gt;Github&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nx</category>
      <category>react</category>
      <category>angular</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
