<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Gilles Ferrand's Blog]]></title><description><![CDATA[Lead Developer Front-end - Enthusiast Developer - NX &amp; Angular Lover]]></description><link>https://gillesferrand.com</link><generator>RSS for Node</generator><lastBuildDate>Thu, 16 Apr 2026 13:35:19 GMT</lastBuildDate><atom:link href="https://gillesferrand.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[State management architecture in Nx]]></title><description><![CDATA[Building scalable Angular applications requires more than just writing good code, it demands architectural decisions that prevent your project from becoming a tangled mess of dependencies. As you saw in few of my last posts, Nx provides a powerful fr...]]></description><link>https://gillesferrand.com/state-management-architecture-in-nx</link><guid isPermaLink="true">https://gillesferrand.com/state-management-architecture-in-nx</guid><category><![CDATA[Nx]]></category><category><![CDATA[Angular]]></category><category><![CDATA[NgRx]]></category><dc:creator><![CDATA[Gilles Ferrand]]></dc:creator><pubDate>Sat, 16 Aug 2025 14:17:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1755357008865/b9523734-d548-4c26-bb2f-9b27bde85579.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Building scalable Angular applications requires more than just writing good code, it demands architectural decisions that prevent your project from becoming a tangled mess of dependencies. As you saw in few of my last posts, Nx provides a powerful framework for organizing these decisions, especially when it comes to state management patterns.</p>
<h2 id="heading-the-challenge-of-angular-state-management-at-scale">The challenge of Angular state management at scale</h2>
<p>Traditional Angular applications often struggle with state management as they grow. Components become tightly coupled, services proliferate without clear boundaries, and testing becomes increasingly difficult. The typical result is a codebase where changing one feature breaks another, and adding new functionality requires understanding the entire application. Nx addresses these issues through workspace architecture that enforces clear separation of concerns and prevents architectural drift through automated linting rules.</p>
<h2 id="heading-library-based-architecture">Library-Based architecture</h2>
<p>The foundation of effective state management in Nx lies in its library structure. Rather than organizing code by file type (components, services, models), Nx encourages organization by domain and responsibility:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755353123465/36024f3c-4517-40fb-b949-f0ea39484c08.png" alt class="image--center mx-auto" /></p>
<pre><code class="lang-bash">libs/todo-management/todo/
├── data-access/    <span class="hljs-comment"># HTTP services and external data</span>
├── store/          <span class="hljs-comment"># NgRx Signal Store implementation / State implementation</span>
├── feature/        <span class="hljs-comment"># Smart components with business logic aka a feature</span>
├── ui/             <span class="hljs-comment"># Presentational components</span>
└── util/           <span class="hljs-comment"># Shared models and types</span>
</code></pre>
<p>This structure creates natural boundaries that mirror how state actually flows through your application.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755293101936/5461cf0b-338d-48d4-b9a6-6a149161a45d.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-dependency-direction-and-boundaries">Dependency Direction and Boundaries</h2>
<p>The real power of Nx state management architecture comes from its dependency rules. These aren't suggestions you can enforce them through ESLint configuration that prevents architectural violations : <a target="_blank" href="https://gillesferrand.com/nx-from-chaos-to-consistency-enforcing-boundaries">https://gillesferrand.com/nx-from-chaos-to-consistency-enforcing-boundaries</a></p>
<p>This creates isolated business domains that can be developed and tested independently. Store libraries, dedicated for a feature, handle state management and can depend on data-access for external data sources and other stores for composition, but remain isolated from features, and UI concerns. This hierarchy creates unidirectional data flow and prevents the circular dependencies that plague traditional Angular applications.</p>
<h2 id="heading-state-management-implementation">State Management Implementation</h2>
<p>With <a target="_blank" href="https://ngrx.io/guide/signals/signal-store">NgRx Signal Store</a>, state management becomes more declarative and reactive. The store library contains all state logic:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> TodoStore = signalStore(
  withState(initialState),
  withComputed(<span class="hljs-function">(<span class="hljs-params">{ todos }</span>) =&gt;</span> ({
    completedTodos: computed(<span class="hljs-function">() =&gt;</span> todos().filter(<span class="hljs-function"><span class="hljs-params">t</span> =&gt;</span> t.completed)),
    activeTodos: computed(<span class="hljs-function">() =&gt;</span> todos().filter(<span class="hljs-function"><span class="hljs-params">t</span> =&gt;</span> !t.completed))
  })),
  withMethods(<span class="hljs-function">(<span class="hljs-params">store, todoService = inject(<span class="hljs-params">TodoService</span>)</span>) =&gt;</span> ({
    loadTodos: <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-comment">// State management logic</span>
    },
    addTodo: <span class="hljs-function">(<span class="hljs-params">text: <span class="hljs-built_in">string</span></span>) =&gt;</span> {
      <span class="hljs-comment">// Business logic for adding todos</span>
    }
  }))
);
</code></pre>
<p>Full code here : <a target="_blank" href="https://github.com/Gillesf31/nx-ngrx-signal-store/blob/main/libs/todo-management/todo/store/src/lib/todo.store.ts">https://github.com/Gillesf31/nx-ngrx-signal-store/blob/main/libs/todo-management/todo/store/src/lib/todo.store.ts</a>  </p>
<p>The feature library orchestrates this store with UI components, while data-access libraries handle HTTP communication. Each layer has a single, clear responsibility.</p>
<h2 id="heading-benefits-in-practice">Benefits in Practice</h2>
<p>This architecture delivers measurable benefits:</p>
<ul>
<li><p><strong>Build Optimization</strong>: Nx's dependency graph allows incremental builds. When you change a UI component, only dependent libraries rebuild, not the entire application / repository.</p>
</li>
<li><p><strong>Testing Isolation</strong>: Each library can be tested independently. UI components can be tested without state management, stores can be tested without HTTP services, and business logic can be tested without UI concerns.</p>
</li>
<li><p><strong>Team Scalability</strong>: Different teams can work on different domains without stepping on each other's code. The dependency rules prevent accidental coupling between features.</p>
</li>
<li><p><strong>Code Reusability</strong>: UI components become truly reusable because they're isolated from business logic. Data access services can be shared across features without coupling.</p>
</li>
</ul>
<h2 id="heading-migration-strategy">Migration Strategy</h2>
<p>For existing Angular applications, migration to this architecture can happen incrementally. Start by identifying natural domain boundaries in your application, then extract libraries one layer at a time. Begin with utility libraries (models, types), then data access, then stores, and finally features and UI. The ESLint rules can be introduced gradually, allowing you to enforce architecture as you refactor rather than requiring a complete rewrite.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Nx helps you to create and maintain this library architecture which transforms state management from a technical concern into an organizational tool. By enforcing clear boundaries between data access, state management, business logic, and presentation, you create applications that scale with your team and requirements rather than against them. The investment in architectural discipline pays dividends through faster builds, easier testing, and more maintainable code. Most importantly, it prevents the architectural drift that turns promising applications into maintenance nightmares.</p>
<h3 id="heading-ressources">Ressources</h3>
<ul>
<li><p>https://github.com/Gillesf31/nx-ngrx-signal-store</p>
</li>
<li><p><a target="_blank" href="https://gillesferrand.com/series/nx">https://gillesferrand.com/series/nx</a></p>
</li>
<li><p><a target="_blank" href="https://nx.dev/getting-started/tutorials/angular-monorepo-tutorial">https://nx.dev/getting-started/tutorials/angular-monorepo-tutorial</a></p>
</li>
<li><p><a target="_blank" href="https://www.youtube.com/@nxdevtools">https://www.youtube.com/@nxdevtools</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Understanding useEffect: No dependencies vs empty array vs dependencies array]]></title><description><![CDATA[The useEffect hook is fundamental to React functional components, but its behaviour changes dramatically based on how you handle the dependencies array. Let's explore the three main patterns and when to use each one.
useEffect without dependencies ar...]]></description><link>https://gillesferrand.com/understanding-useeffect-no-dependencies-vs-empty-array-vs-dependencies-array</link><guid isPermaLink="true">https://gillesferrand.com/understanding-useeffect-no-dependencies-vs-empty-array-vs-dependencies-array</guid><category><![CDATA[React]]></category><category><![CDATA[ReactHooks]]></category><category><![CDATA[useEffect]]></category><dc:creator><![CDATA[Gilles Ferrand]]></dc:creator><pubDate>Tue, 12 Aug 2025 20:13:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1755029541637/47c23f47-11a0-4062-b5d1-4c1390dbcba3.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The <code>useEffect</code> hook is fundamental to React functional components, but its behaviour changes dramatically based on how you handle the dependencies array. Let's explore the three main patterns and when to use each one.</p>
<h2 id="heading-useeffect-without-dependencies-array">useEffect without dependencies array</h2>
<pre><code class="lang-typescript"><span class="hljs-comment">// ComponentA.tsx</span>
<span class="hljs-keyword">import</span> { useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> ComponentA = <span class="hljs-function">() =&gt;</span> {
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Component A mounted'</span>);
    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-comment">// <span class="hljs-doctag">NOTE:</span> Cleanup function, we will see this in a future blog post</span>
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Component A unmounted'</span>);
    };
  });

  <span class="hljs-keyword">return</span> &lt;p&gt;Component A works&lt;/p&gt;;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ComponentA;
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-comment">// App.tsx</span>
<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> ComponentA <span class="hljs-keyword">from</span> <span class="hljs-string">'./ComponentA'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [isComponentAVisible, setComponentAVisible] = useState(<span class="hljs-literal">true</span>);
  <span class="hljs-keyword">const</span> [count, setCounter] = useState(<span class="hljs-number">0</span>);

  <span class="hljs-keyword">return</span> (
    &lt;&gt;
      &lt;p&gt;App works&lt;/p&gt;
      &lt;p&gt;Counter: {count}&lt;/p&gt;
      &lt;button onClick={<span class="hljs-function">() =&gt;</span> setCounter(<span class="hljs-function">(<span class="hljs-params">prev</span>) =&gt;</span> prev + <span class="hljs-number">1</span>)}&gt;
        Increment Counter
      &lt;/button&gt;
      &lt;button onClick={<span class="hljs-function">() =&gt;</span> setComponentAVisible(!isComponentAVisible)}&gt;
        {isComponentAVisible ? <span class="hljs-string">'Hide'</span> : <span class="hljs-string">'Show'</span>} component A
      &lt;/button&gt;
      {isComponentAVisible &amp;&amp; &lt;ComponentA /&gt;}
    &lt;/&gt;
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Console output :</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Component A mounted (page loads)</span>
<span class="hljs-comment">// Component A mounted (page loads / Only if strict mode is activated)</span>
<span class="hljs-comment">// Component A unmounted (hide component A clicked)</span>
<span class="hljs-comment">// Component A mounted (show component A clicked)</span>
<span class="hljs-comment">// Component A unmounted (Only if strict mode is activated)</span>
<span class="hljs-comment">// Component A mounted (Only if strict mode is activated)</span>
</code></pre>
<p>In this case useEffects run :</p>
<ul>
<li><p>Initial render</p>
</li>
<li><p>Every state update</p>
</li>
<li><p>Every prop changed</p>
</li>
<li><p>Every parent re-render</p>
</li>
</ul>
<p><strong>Use case</strong> : Rare. Typically only when you need to respond to any component change, such as logging or analytics tracking.</p>
<h2 id="heading-useeffect-without-empty-dependencies-array">useEffect without empty dependencies array</h2>
<p>An empty dependencies array makes the effect run only once after the initial render.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// ComponentA.tsx</span>
<span class="hljs-keyword">import</span> { useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> ComponentA = <span class="hljs-function">() =&gt;</span> {
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Component A mounted'</span>);
    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-comment">// <span class="hljs-doctag">NOTE:</span> Cleanup function, we will see this in a future blog post</span>
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Component A unmounted'</span>);
    };
  }, []);

  <span class="hljs-keyword">return</span> &lt;p&gt;Component A works&lt;/p&gt;;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ComponentA;
</code></pre>
<p>Console output :</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Component A mounted (page loads)</span>
<span class="hljs-comment">// Component A mounted (page loads / Only if strict mode is activated)</span>

<span class="hljs-comment">// Clicking on increment counter doesn't log anything</span>

<span class="hljs-comment">// Component A unmounted (hide component A clicked)</span>
<span class="hljs-comment">// Component A mounted (show component A clicked)</span>
<span class="hljs-comment">// Component A unmounted (Only if strict mode is activated)</span>
<span class="hljs-comment">// Component A mounted (Only if strict mode is activated)</span>
</code></pre>
<p>In this case useEffects run :</p>
<ul>
<li><p>Only after the initial render</p>
</li>
<li><p>Never again until component unmounts</p>
</li>
</ul>
<p><strong>Use case</strong> : Component initialization, data fetching that happens once, setting up subscriptions, or DOM manipulations that should only happen on mount.</p>
<h2 id="heading-useeffect-with-dependencies-array">useEffect with dependencies array</h2>
<p>When you specify dependencies, the effect runs after the initial render and whenever any dependency changes.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// ComponentA.tsx</span>
<span class="hljs-keyword">import</span> { useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">interface</span> ComponentPropsA {
  <span class="hljs-keyword">readonly</span> userId: <span class="hljs-built_in">number</span>;
  <span class="hljs-keyword">readonly</span> theme: <span class="hljs-string">'light'</span> | <span class="hljs-string">'dark'</span>;
}

<span class="hljs-keyword">const</span> ComponentA = <span class="hljs-function">(<span class="hljs-params">{ userId, theme }: ComponentPropsA</span>) =&gt;</span> {
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(
      <span class="hljs-string">`Component A mounted with userId: <span class="hljs-subst">${userId}</span> and theme: <span class="hljs-subst">${theme}</span>`</span>
    );

    <span class="hljs-comment">// Example: fetch user-specific data or apply theme</span>
    <span class="hljs-keyword">if</span> (userId) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Fetching data for user <span class="hljs-subst">${userId}</span> with <span class="hljs-subst">${theme}</span> theme`</span>);
    }

    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-comment">// <span class="hljs-doctag">NOTE:</span> Cleanup function, we will see this in a future blog post</span>
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Component A unmounted with userId: deps changed`</span>);
    };
  }, [userId, theme]); <span class="hljs-comment">// Effect depends on userId and theme</span>

  <span class="hljs-keyword">return</span> &lt;p&gt;Component A works&lt;/p&gt;;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ComponentA;
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-comment">// App.tsx</span>
<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> ComponentA <span class="hljs-keyword">from</span> <span class="hljs-string">'./ComponentA'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [isComponentAVisible, setComponentAVisible] = useState(<span class="hljs-literal">true</span>);
  <span class="hljs-keyword">const</span> [userId, setUserId] = useState(<span class="hljs-number">1</span>);
  <span class="hljs-keyword">const</span> [theme, setTheme] = useState&lt;<span class="hljs-string">'light'</span> | <span class="hljs-string">'dark'</span>&gt;(<span class="hljs-string">'light'</span>);
  <span class="hljs-keyword">const</span> [count, setCount] = useState(<span class="hljs-number">0</span>);

  <span class="hljs-keyword">return</span> (
    &lt;&gt;
      &lt;p&gt;App works&lt;/p&gt;
      &lt;p&gt;Counter: {count}&lt;/p&gt;
      &lt;button onClick={<span class="hljs-function">() =&gt;</span> setCount(<span class="hljs-function">(<span class="hljs-params">prev</span>) =&gt;</span> prev + <span class="hljs-number">1</span>)}&gt;
        Increment Counter
      &lt;/button&gt;
      &lt;button onClick={<span class="hljs-function">() =&gt;</span> setUserId(<span class="hljs-function">(<span class="hljs-params">prev</span>) =&gt;</span> prev + <span class="hljs-number">1</span>)}&gt;
        Increment User ID
      &lt;/button&gt;
      &lt;button
        onClick={<span class="hljs-function">() =&gt;</span>
          setTheme(<span class="hljs-function">(<span class="hljs-params">prev</span>) =&gt;</span> (prev === <span class="hljs-string">'light'</span> ? <span class="hljs-string">'dark'</span> : <span class="hljs-string">'light'</span>))
        }
      &gt;
        Toggle Theme
      &lt;/button&gt;
      &lt;button onClick={<span class="hljs-function">() =&gt;</span> setComponentAVisible(!isComponentAVisible)}&gt;
        {isComponentAVisible ? <span class="hljs-string">'Hide'</span> : <span class="hljs-string">'Show'</span>} component A
      &lt;/button&gt;
      {isComponentAVisible &amp;&amp; &lt;ComponentA userId={userId} theme={theme} /&gt;}
    &lt;/&gt;
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Console output :</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Component A mounted with userId: 1 and theme: light (page loads)</span>
<span class="hljs-comment">// Fetching data for user 1 with light theme (page loads)</span>
<span class="hljs-comment">// Component A unmounted with userId: deps changed (page loads / Only if strict mode is activated)</span>
<span class="hljs-comment">// Component A mounted with userId: 1 and theme: light (page loads / Only if strict mode is activated)</span>
<span class="hljs-comment">// Fetching data for user 1 with light theme (page loads / Only if strict mode is activated)</span>

<span class="hljs-comment">// Clicking on increment counter doesn't log anything</span>

<span class="hljs-comment">// Clicking on increment userId</span>
<span class="hljs-comment">// Component A unmounted with userId: deps changed</span>
<span class="hljs-comment">// Component A mounted with userId: 2 and theme: light</span>
<span class="hljs-comment">// Fetching data for user 2 with light theme</span>

<span class="hljs-comment">// Clicking on toggle theme</span>
<span class="hljs-comment">// Component A unmounted with userId: deps changed</span>
<span class="hljs-comment">// Component A mounted with userId: 2 and theme: dark</span>
<span class="hljs-comment">// Fetching data for user 2 with dark theme</span>
</code></pre>
<p>In this case useEffects run :</p>
<ul>
<li><p>After the initial render</p>
</li>
<li><p>Whenever <code>query</code> changes</p>
</li>
<li><p>Whenever <code>category</code> changes</p>
</li>
<li><p>Not when other state variables change</p>
</li>
</ul>
<p><strong>Use case</strong> : Responding to specific state or prop changes, such as fetching data based on user input, updating derived state, or synchronizing with external systems.</p>
<h2 id="heading-quick-comparison-table">Quick Comparison Table</h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Pattern</td><td>Syntax</td><td>Runs When</td><td>Example Use Cases</td></tr>
</thead>
<tbody>
<tr>
<td><strong>No dependencies</strong></td><td><code>useEffect(() =&gt; {})</code></td><td>• Initial render<br />• Every state update<br />• Every prop change<br />• Every parent re-render</td><td>• Logging/analytics<br />• DOM updates that need to happen on every render<br />• Performance monitoring</td></tr>
<tr>
<td><strong>Empty dependencies</strong></td><td><code>useEffect(() =&gt; {}, [])</code></td><td>• Only on initial render<br />• Never again until unmount</td><td>• Data fetching on mount<br />• Setting up subscriptions<br />• Component initialization<br />• Event listeners setup</td></tr>
<tr>
<td><strong>With dependencies</strong></td><td><code>useEffect(() =&gt; {}, [a, b])</code></td><td>• Initial render<br />• When any dependency changes<br />• Not when other state changes</td><td>• Reactive data fetching<br />• Responding to prop changes<br />• Updating derived state<br />• Search/filter operations</td></tr>
</tbody>
</table>
</div><h3 id="heading-performance-impact">Performance Impact</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Pattern</td><td>Performance</td><td>When to Avoid</td></tr>
</thead>
<tbody>
<tr>
<td><strong>No dependencies</strong></td><td>⚠️ <strong>High overhead</strong></td><td>Components that re-render frequently</td></tr>
<tr>
<td><strong>Empty dependencies</strong></td><td>✅ <strong>Most efficient</strong></td><td>When you need to react to changes</td></tr>
<tr>
<td><strong>With dependencies</strong></td><td>✅ <strong>Efficient</strong></td><td>Never - this is the recommended pattern</td></tr>
</tbody>
</table>
</div>]]></content:encoded></item><item><title><![CDATA[Git Worktree : Managing multiple branches simultaneously]]></title><description><![CDATA[Git worktree is a Git feature that allows you to check out multiple branches at once in different directories, without cloning the repository again. This powerful capability transforms how developers handle parallel development workflows.
The Problem...]]></description><link>https://gillesferrand.com/git-worktree-managing-multiple-branches-simultaneously</link><guid isPermaLink="true">https://gillesferrand.com/git-worktree-managing-multiple-branches-simultaneously</guid><category><![CDATA[worktree]]></category><category><![CDATA[Git]]></category><dc:creator><![CDATA[Gilles Ferrand]]></dc:creator><pubDate>Fri, 08 Aug 2025 20:05:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1754683508158/dd605d84-db9c-4b3a-906c-0d7aa5f757b8.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Git worktree is a Git feature that allows you to check out multiple branches at once in different directories, without cloning the repository again. This powerful capability transforms how developers handle parallel development workflows.</p>
<h2 id="heading-the-problem-with-traditional-branch-switching">The Problem with Traditional Branch Switching</h2>
<p>Most developers are familiar with the standard Git workflow: switch branches, work on changes, commit, and switch again. This approach creates friction when you need to:</p>
<ul>
<li>Compare code between branches side by side</li>
<li>Test different features simultaneously</li>
<li>Apply hotfixes while working on a feature branch</li>
<li>Run builds on multiple branches without losing your current work state</li>
</ul>
<p>Traditional solutions involve stashing changes, switching branches, or maintaining multiple repository clones. Each approach introduces overhead and complexity.</p>
<h2 id="heading-what-git-worktree-solves">What Git Worktree Solves</h2>
<p>Git worktree eliminates these pain points by creating additional working directories that share the same Git repository. Each worktree operates independently while maintaining a connection to the central <code>.git</code> directory.</p>
<p>Think of it as having multiple desks in the same office. Each desk has different papers (files) spread out, but they all access the same filing cabinet (Git repository).</p>
<h2 id="heading-basic-worktree-operations">Basic Worktree Operations</h2>
<h3 id="heading-creating-a-new-worktree">Creating a New Worktree</h3>
<pre><code class="lang-bash"><span class="hljs-comment"># Create worktree for existing branch</span>
git worktree add ../feature-login feature/user-login

<span class="hljs-comment"># Create worktree with new branch</span>
git worktree add ../hotfix-payment -b hotfix/payment-bug
</code></pre>
<p>The first command creates a directory <code>../feature-login</code> containing the <code>feature/user-login</code> branch. The second creates both a new branch and worktree simultaneously.</p>
<h3 id="heading-listing-active-worktrees">Listing Active Worktrees</h3>
<pre><code class="lang-bash">git worktree list
</code></pre>
<p>This shows all worktrees with their paths and current branches:</p>
<pre><code>/home/user/myproject        a1b2c3d [main]
/home/user/feature-login    e4f5g6h [feature/user-login]
/home/user/hotfix-payment   h7i8j9k [hotfix/payment-bug]
</code></pre><h3 id="heading-removing-worktrees">Removing Worktrees</h3>
<pre><code class="lang-bash"><span class="hljs-comment"># Remove worktree (must be done from main repository)</span>
git worktree remove ../feature-login

<span class="hljs-comment"># Force removal if worktree has uncommitted changes</span>
git worktree remove --force ../feature-login
</code></pre>
<h2 id="heading-practical-development-scenarios">Practical Development Scenarios</h2>
<h3 id="heading-scenario-1-feature-development-with-hotfix">Scenario 1: Feature Development with Hotfix</h3>
<p>You're developing a new feature when a critical bug appears in production:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Currently working in main worktree on feature branch</span>
git worktree add ../hotfix-critical -b hotfix/critical-fix

<span class="hljs-comment"># Switch to hotfix directory</span>
<span class="hljs-built_in">cd</span> ../hotfix-critical

<span class="hljs-comment"># Fix the bug, commit, and push</span>
git add .
git commit -m <span class="hljs-string">"Fix critical payment processing bug"</span>
git push origin hotfix/critical-fix

<span class="hljs-comment"># Return to feature work without losing context</span>
<span class="hljs-built_in">cd</span> ../myproject
</code></pre>
<h3 id="heading-scenario-2-code-comparison-and-testing">Scenario 2: Code Comparison and Testing</h3>
<p>Compare implementations across branches without losing your current work:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Create worktrees for comparison</span>
git worktree add ../old-implementation legacy/payment-system
git worktree add ../new-implementation feature/payment-refactor

<span class="hljs-comment"># Run tests in parallel</span>
<span class="hljs-built_in">cd</span> ../old-implementation &amp;&amp; npm run <span class="hljs-built_in">test</span>
<span class="hljs-built_in">cd</span> ../new-implementation &amp;&amp; npm run <span class="hljs-built_in">test</span>
</code></pre>
<h3 id="heading-scenario-3-multiple-environment-builds">Scenario 3: Multiple Environment Builds</h3>
<p>Maintain separate builds for different environments:</p>
<pre><code class="lang-bash">git worktree add ../staging-build staging
git worktree add ../production-build production

<span class="hljs-comment"># Build staging while working on development</span>
<span class="hljs-built_in">cd</span> ../staging-build &amp;&amp; npm run build:staging
</code></pre>
<h2 id="heading-worktree-limitations-and-considerations">Worktree Limitations and Considerations</h2>
<h3 id="heading-shared-state-elements">Shared State Elements</h3>
<p>Certain Git elements are shared across all worktrees:</p>
<ul>
<li><strong>Branches</strong>: Checking out the same branch in multiple worktrees is prohibited</li>
<li><strong>Configuration</strong>: Repository configuration affects all worktrees</li>
<li><strong>Hooks</strong>: Git hooks execute from the main <code>.git</code> directory</li>
<li><strong>Stash</strong>: Stash entries are shared across worktrees</li>
</ul>
<h3 id="heading-best-practices">Best Practices</h3>
<p><strong>Keep worktrees focused</strong>: Use worktrees for specific, time-limited tasks rather than permanent parallel development.</p>
<p><strong>Clean up regularly</strong>: Remove unused worktrees to maintain a clean working environment:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Remove worktree and clean up references</span>
git worktree remove ../completed-feature
git worktree prune
</code></pre>
<p><strong>Avoid nested worktrees</strong>: Don't create worktrees inside other worktrees as this creates confusing repository relationships.</p>
<p><strong>Use descriptive paths</strong>: Choose directory names that clearly indicate the branch or purpose.</p>
<h2 id="heading-worktree-vs-alternatives">Worktree vs. Alternatives</h2>
<h3 id="heading-git-worktree-vs-multiple-clones">Git Worktree vs. Multiple Clones</h3>
<p>Worktrees share the object database, saving disk space and keeping branches synchronized. Multiple clones require separate <code>git fetch</code> operations and consume more storage.</p>
<h3 id="heading-git-worktree-vs-branch-switching">Git Worktree vs. Branch Switching</h3>
<p>Branch switching requires stashing or committing work in progress. Worktrees maintain independent working states without interruption.</p>
<h3 id="heading-git-worktree-vs-git-stash">Git Worktree vs. Git Stash</h3>
<p>Stashing saves work temporarily but doesn't allow parallel development. Worktrees enable simultaneous work on multiple branches.</p>
<p>Git worktree transforms parallel development from a cumbersome process into a streamlined workflow. By maintaining separate working directories while sharing the repository history, it eliminates context switching overhead and enables truly parallel development workflows. The key to effective worktree usage lies in treating them as focused, temporary workspaces rather than permanent parallel development environments.</p>
]]></content:encoded></item><item><title><![CDATA[Git push force vs force-with-lease: When and Why to use each]]></title><description><![CDATA[When working with Git in collaborative environments, you'll inevitably encounter situations where you need to overwrite remote history. Two commands come into play: git push --force and git push --force-with-lease. Understanding the difference betwee...]]></description><link>https://gillesferrand.com/git-push-force-vs-force-with-lease</link><guid isPermaLink="true">https://gillesferrand.com/git-push-force-vs-force-with-lease</guid><category><![CDATA[Git]]></category><dc:creator><![CDATA[Gilles Ferrand]]></dc:creator><pubDate>Mon, 04 Aug 2025 14:46:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1754318747706/0e68406b-2ea4-4e14-8f44-38099abddb4b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When working with Git in collaborative environments, you'll inevitably encounter situations where you need to overwrite remote history. Two commands come into play: <code>git push --force</code> and <code>git push --force-with-lease</code>. Understanding the difference between these commands can save you from accidentally destroying your teammates' work.</p>
<h2 id="heading-why-rewriting-history-can-happen">Why rewriting history can happen</h2>
<p>In professional development environments, clean Git history isn't just a preference, it's a requirement for maintainable codebases. Many teams follow a "one logical commit per feature" guideline, where each merge to the main branch represents a single, complete change. This approach makes code reviews more focused, rollbacks (git revert) cleaner, and debugging significantly easier when you need to trace issues months later. (git bisect)</p>
<p>During development, however, your feature branch accumulates multiple commits: initial implementations, bug fixes, code review responses, and style adjustments. Before merging, teams typically require you to squash these commits into a coherent story or rebase onto the latest main branch to avoid merge commits that clutter the project history.</p>
<p>Additionally, as main branch development continues, your feature branch falls behind. Rebasing your work onto the current main branch creates a linear history that's easier to follow than a web of merge commits. Some teams also enforce commit message standards or require sign-offs that weren't present in your original commits, necessitating history rewrites to meet project guidelines.</p>
<p>These practices, rebasing, squashing, and amending, all change commit hashes, creating the divergence that requires force pushing to update the remote repository.</p>
<p>Push force can be scary at the beginning but when you are used to it, it's pretty easy !</p>
<h2 id="heading-the-problem-with-standard-force-push">The problem with standard force push</h2>
<p>The <code>git push --force</code> command overwrites the remote branch with your local version, regardless of what changes might exist on the remote. This brute-force approach can lead to serious problems in team environments.</p>
<p>A good rule to follow is to only force push on your own feature branch, but sometimes you work on a bigger branch with a colleague</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Dangerous - overwrites everything on remote</span>
git push --force origin feature-branch
</code></pre>
<p>Consider this scenario: You're working on a feature branch, and a colleague pushes some critical bug fixes while you're doing a rebase. If you force push without checking, you'll completely erase their work.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Timeline of disaster:</span>
<span class="hljs-comment"># 1. You start with commit A</span>
<span class="hljs-comment"># 2. Colleague pushes commit B to remote</span>
<span class="hljs-comment"># 3. You rebase locally, creating commit A'</span>
<span class="hljs-comment"># 4. You force push, replacing A-B with just A'</span>
<span class="hljs-comment"># 5. Colleague's work (commit B) is gone forever</span>
</code></pre>
<h2 id="heading-force-with-lease-the-safer-alternative">Force-with-lease: the safer alternative</h2>
<p>The <code>--force-with-lease</code> option provides a safety net. It only allows the force push if your local reference matches what's currently on the remote. If someone else has pushed changes since your last fetch, the command will fail.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Safer - checks remote state first</span>
git push --force-with-lease origin feature-branch
</code></pre>
<p>Here's how it protects you:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Safe scenario:</span>
git fetch origin                    <span class="hljs-comment"># Get latest remote state</span>
git rebase origin/main             <span class="hljs-comment"># Rebase your work</span>
git push --force-with-lease origin feature-branch  <span class="hljs-comment"># Safe to push</span>

<span class="hljs-comment"># Protected scenario:</span>
<span class="hljs-comment"># Someone pushed while you were rebasing</span>
git push --force-with-lease origin feature-branch
<span class="hljs-comment"># Error: Updates were rejected because the remote contains work</span>
</code></pre>
<h2 id="heading-practical-code-examples">Practical code examples</h2>
<h3 id="heading-basic-usage-comparison">Basic Usage Comparison</h3>
<pre><code class="lang-bash"><span class="hljs-comment"># Traditional force push (dangerous)</span>
git push --force origin feature-branch

<span class="hljs-comment"># Force with lease (safer)</span>
git push --force-with-lease origin feature-branch
</code></pre>
<h3 id="heading-real-world-workflow">Real-world workflow</h3>
<p>Here's a typical development workflow using force-with-lease:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># 1. Fetch latest changes</span>
git fetch origin

<span class="hljs-comment"># 2. Rebase your feature branch</span>
git checkout feature-branch
git rebase origin/main

<span class="hljs-comment"># 3. Safely force push</span>
git push --force-with-lease origin feature-branch
</code></pre>
<h3 id="heading-handling-rejected-pushes">Handling rejected pushes</h3>
<p>When force-with-lease rejects your push, here's how to handle it:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Force-with-lease failed - someone pushed changes</span>
git fetch origin
git <span class="hljs-built_in">log</span> origin/feature-branch --oneline  <span class="hljs-comment"># See what changed</span>
git rebase origin/feature-branch         <span class="hljs-comment"># Incorporate new changes</span>
git push --force-with-lease origin feature-branch  <span class="hljs-comment"># Try again</span>
</code></pre>
<h2 id="heading-when-to-use-each-command">When to use each command</h2>
<h3 id="heading-use-force-with-lease-when">Use <code>--force-with-lease</code> when:</h3>
<ul>
<li>Working on shared feature branches</li>
<li>You've rebased or amended commits</li>
<li>Collaborating with other developers</li>
<li>You want protection against accidental overwrites</li>
</ul>
<h3 id="heading-use-force-only-when">Use <code>--force</code> only when:</h3>
<ul>
<li>You're certain no one else is working on the branch</li>
<li>You're working on a personal fork</li>
<li>You need to recover from a corrupted remote state</li>
<li>You've explicitly coordinated with your team</li>
</ul>
<h2 id="heading-the-bottom-line">The bottom line</h2>
<p>Force-with-lease should be your default choice for overwriting remote history. It provides the same functionality as force push while protecting against the most common cause of lost work: accidentally overwriting changes you haven't seen.</p>
<p>The extra safety check takes virtually no additional time and can save hours of recovery work. In collaborative environments, this small change in habit can prevent significant frustration and potential data loss.</p>
<p>Make force-with-lease your standard practice, and reserve regular force push for those rare situations where you're absolutely certain about the state of the remote repository.</p>
]]></content:encoded></item><item><title><![CDATA[TypeScript's [number] Index Signature: Extract Union Types from Arrays]]></title><description><![CDATA[Ever needed to create a union type from an array of objects in TypeScript? There's an elegant solution using the [number] index signature notation that can save you from maintaining duplicate type definitions.
The Problem
Let's say you have an array ...]]></description><link>https://gillesferrand.com/typescripts-number-index-signature-extract-union-types-from-arrays</link><guid isPermaLink="true">https://gillesferrand.com/typescripts-number-index-signature-extract-union-types-from-arrays</guid><category><![CDATA[TypeScript]]></category><category><![CDATA[TypeScript Tutorial]]></category><dc:creator><![CDATA[Gilles Ferrand]]></dc:creator><pubDate>Sat, 19 Jul 2025 21:31:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1752960594694/e2be9492-869f-4169-bb1a-950ee81a3887.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Ever needed to create a union type from an array of objects in TypeScript? There's an elegant solution using the <code>[number]</code> index signature notation that can save you from maintaining duplicate type definitions.</p>
<h2 id="heading-the-problem">The Problem</h2>
<p>Let's say you have an array of API status objects and need to create types from them:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> API_STATUSES = [
  { code: <span class="hljs-string">'success'</span>, message: <span class="hljs-string">'Request completed'</span>, httpCode: <span class="hljs-number">200</span> },
  { code: <span class="hljs-string">'error'</span>, message: <span class="hljs-string">'An error occurred'</span>, httpCode: <span class="hljs-number">500</span> },
  { code: <span class="hljs-string">'loading'</span>, message: <span class="hljs-string">'Request in progress'</span>, httpCode: <span class="hljs-literal">null</span> },
  { code: <span class="hljs-string">'timeout'</span>, message: <span class="hljs-string">'Request timed out'</span>, httpCode: <span class="hljs-number">408</span> }
] <span class="hljs-keyword">as</span> <span class="hljs-keyword">const</span>;

<span class="hljs-comment">// How do we get types from this array?</span>
</code></pre>
<p>You could manually define union types, but that means maintaining the same information in two places:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Manual approach - duplication!</span>
<span class="hljs-keyword">type</span> ApiStatusCode = <span class="hljs-string">'success'</span> | <span class="hljs-string">'error'</span> | <span class="hljs-string">'loading'</span> | <span class="hljs-string">'timeout'</span>;
<span class="hljs-keyword">type</span> ApiStatusObject = {
  code: ApiStatusCode;
  message: <span class="hljs-built_in">string</span>;
  httpCode: <span class="hljs-built_in">number</span> | <span class="hljs-literal">null</span>;
};
</code></pre>
<h2 id="heading-the-solution-number-index-signature">The Solution : [number] Index Signature</h2>
<p>The <code>[number]</code> notation extracts the type of elements that can be accessed with any numeric index:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> API_STATUSES = [
  { code: <span class="hljs-string">'success'</span>, message: <span class="hljs-string">'Request completed'</span>, httpCode: <span class="hljs-number">200</span> },
  { code: <span class="hljs-string">'error'</span>, message: <span class="hljs-string">'An error occurred'</span>, httpCode: <span class="hljs-number">500</span> },
  { code: <span class="hljs-string">'loading'</span>, message: <span class="hljs-string">'Request in progress'</span>, httpCode: <span class="hljs-literal">null</span> },
  { code: <span class="hljs-string">'timeout'</span>, message: <span class="hljs-string">'Request timed out'</span>, httpCode: <span class="hljs-number">408</span> }
] <span class="hljs-keyword">as</span> <span class="hljs-keyword">const</span>;

<span class="hljs-comment">// Extract the union of all object types</span>
<span class="hljs-keyword">type</span> ApiStatusObject = (<span class="hljs-keyword">typeof</span> API_STATUSES)[<span class="hljs-built_in">number</span>];

<span class="hljs-comment">// Extract specific property types</span>
<span class="hljs-keyword">type</span> ApiStatusCode = ApiStatusObject[<span class="hljs-string">'code'</span>]; <span class="hljs-comment">// 'success' | 'error' | 'loading' | 'timeout'</span>
</code></pre>
<h2 id="heading-how-it-works">How It Works</h2>
<p>Breaking down <code>(typeof API_STATUSES)[number]</code>:</p>
<ol>
<li><strong><code>typeof API_STATUSES</code></strong> - Gets the type of the array</li>
<li><strong><code>[number]</code></strong> - Accesses the type of elements at any numeric index</li>
<li><strong>Result</strong> - A union of all object types in the array</li>
</ol>
<p>The <code>[number]</code> essentially says "give me the type of whatever can be found at any number index in this array."</p>
<h2 id="heading-practical-example">Practical Example</h2>
<p>Here's how you might use this in practice:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> API_STATUSES = [
  { code: <span class="hljs-string">'success'</span>, message: <span class="hljs-string">'Completed'</span>, retryable: <span class="hljs-literal">false</span> },
  { code: <span class="hljs-string">'error'</span>, message: <span class="hljs-string">'Failed'</span>, retryable: <span class="hljs-literal">true</span> },
  { code: <span class="hljs-string">'loading'</span>, message: <span class="hljs-string">'In progress'</span>, retryable: <span class="hljs-literal">false</span> },
  { code: <span class="hljs-string">'timeout'</span>, message: <span class="hljs-string">'Timed out'</span>, retryable: <span class="hljs-literal">true</span> }
] <span class="hljs-keyword">as</span> <span class="hljs-keyword">const</span>;

<span class="hljs-keyword">type</span> ApiStatusObject = (<span class="hljs-keyword">typeof</span> API_STATUSES)[<span class="hljs-built_in">number</span>];
<span class="hljs-keyword">type</span> ApiStatusCode = ApiStatusObject[<span class="hljs-string">'code'</span>];

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStatusInfo</span>(<span class="hljs-params">code: ApiStatusCode</span>): <span class="hljs-title">ApiStatusObject</span> | <span class="hljs-title">undefined</span> </span>{
  <span class="hljs-keyword">return</span> API_STATUSES.find(<span class="hljs-function"><span class="hljs-params">status</span> =&gt;</span> status.code === code);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isRetryable</span>(<span class="hljs-params">code: ApiStatusCode</span>): <span class="hljs-title">boolean</span> </span>{
  <span class="hljs-keyword">const</span> status = getStatusInfo(code);
  <span class="hljs-keyword">return</span> status?.retryable ?? <span class="hljs-literal">false</span>;
}

<span class="hljs-comment">// TypeScript knows these are valid</span>
<span class="hljs-built_in">console</span>.log(isRetryable(<span class="hljs-string">'error'</span>)); <span class="hljs-comment">// true</span>
<span class="hljs-built_in">console</span>.log(isRetryable(<span class="hljs-string">'success'</span>)); <span class="hljs-comment">// false</span>

<span class="hljs-comment">// TypeScript error - invalid status code</span>
<span class="hljs-comment">// console.log(isRetryable('invalid')); // ❌</span>
<span class="hljs-comment">// Argument of type '"invalid"' is not assignable to parameter of type '"success" | "error" | "loading" | "timeout"'.(2345)</span>
</code></pre>
<h2 id="heading-why-this-matters">Why This Matters</h2>
<p><strong>Single source of truth</strong>: Your array serves as both runtime data and type definition. Add a new status object to the array, and the types update automatically.</p>
<p><strong>Type safety</strong>: TypeScript catches typos and invalid values at compile time.</p>
<p><strong>Better refactoring</strong>: Rename a property in your array objects, and TypeScript will help you find all the places that need updating.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>The <code>[number]</code> index signature is a simple but powerful TypeScript feature. It eliminates the need to manually maintain union types that mirror your array data, giving you better type safety with less code duplication.</p>
<p>Next time you find yourself writing the same information in both an array and a type definition, remember this elegant solution.</p>
]]></content:encoded></item><item><title><![CDATA[NX : From chaos to consistency - Enforcing Boundaries]]></title><description><![CDATA[Quick personal talk
This feature of NX completely changed my way of developing products, because at the end it’s “just” a nice tool but in fact it’s way more than that. You could build your own framework to do the same thing : enforcing a nice, devel...]]></description><link>https://gillesferrand.com/nx-from-chaos-to-consistency-enforcing-boundaries</link><guid isPermaLink="true">https://gillesferrand.com/nx-from-chaos-to-consistency-enforcing-boundaries</guid><category><![CDATA[Nx]]></category><category><![CDATA[nx-workspace]]></category><dc:creator><![CDATA[Gilles Ferrand]]></dc:creator><pubDate>Wed, 16 Jul 2025 17:56:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1752682553474/c7a92240-5ed4-449f-8b31-fe2599987d23.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-quick-personal-talk">Quick personal talk</h1>
<p>This feature of NX completely changed my way of developing products, because at the end it’s “just” a nice tool but in fact it’s way more than that. You could build your own framework to do the same thing : enforcing a nice, developer-friendly architecture. But it’ll cost a lot of effort.</p>
<p>And that’s why NX is really nice, it gives you this kind of tool directly. So you don’t spend hours and hours creating your own tool. If I can remember correctly it was one of the goals of the NX team, simplify life of smaller developer teams.</p>
<p>Let me quickly explain how it changed my developer’s life, I will dedicate a full article about other feature that changed my life too, now when I create a product I think deeper about the architecture, I try to split things into libraries, scopes, boundaries… to make them re-usable and easy to maintain. And NX helps me a lot with that.</p>
<p>So let's dive into how these boundary enforcement features work and how you can implement them in your own monorepo.</p>
<h1 id="heading-what-is-really-important">What is really important</h1>
<p>In the last article we talked about how to define libraries types, today we will talk about how we can enforce these rules through linting, dependency constraints, and automated checks so everyone on the monorepo can understand the architecture and be consistent. At the end we will see that you can extend this boundary concept through many things like scope, domains, and team ownership…</p>
<p>So NX give you a new rule on ESLint to add your libraries types, you can find this in eslint config file <em>( eslint.config.mjs in newer version of NX or .eslintrc.json in older version)</em> at the root of your NX project.</p>
<p>Here is an example on a monorepo with React</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> nx <span class="hljs-keyword">from</span> <span class="hljs-string">'@nx/eslint-plugin'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> [
    ...,
    <span class="hljs-attr">rules</span>: {
      <span class="hljs-string">'@nx/enforce-module-boundaries'</span>: [
        <span class="hljs-string">'error'</span>,
         {
             <span class="hljs-attr">enforceBuildableLibDependency</span>: <span class="hljs-literal">true</span>,
             <span class="hljs-attr">allow</span>: [<span class="hljs-string">'^.*/eslint(\\.base)?\\.config\\.[cm]?[jt]s$'</span>],
             <span class="hljs-attr">depConstraints</span>: [<span class="hljs-comment">/* Your rules here */</span>]
         }
      ],
    },
  },
  ...,
];
</code></pre>
<h2 id="heading-why-you-need-to-add-a-tag-on-your-libraries">Why you need to add a tag on your libraries</h2>
<p>NX needs to know which library and of what type in order to apply rules, so with each generation or creation of a library, you'll need to take care to specify its tag.</p>
<p>If you want to create a utility-type library for example, you’ll need to add this in <code>project.json</code> of your library</p>
<pre><code class="lang-json">  <span class="hljs-string">"tags"</span>: [<span class="hljs-string">"type:util"</span>],
</code></pre>
<p>or in <code>package.json</code> of your library</p>
<pre><code class="lang-json"><span class="hljs-string">"nx"</span>: {
  <span class="hljs-attr">"tags"</span>: [
    <span class="hljs-string">"type:util"</span>
  ]
}
</code></pre>
<p>Of course you can have multiple tags like this</p>
<pre><code class="lang-json"><span class="hljs-string">"tags"</span>: [<span class="hljs-string">"scope:fithelper-front"</span>, <span class="hljs-string">"type:util"</span>],
<span class="hljs-comment">// or</span>
<span class="hljs-string">"tags"</span>: [<span class="hljs-string">"scope:fithelper-front"</span>, <span class="hljs-string">"type:data-access"</span>],
<span class="hljs-comment">// or</span>
<span class="hljs-string">"tags"</span>: [<span class="hljs-string">"scope:fithelper-front"</span>, <span class="hljs-string">"type:app"</span>],
<span class="hljs-comment">// or</span>
<span class="hljs-string">"tags"</span>: [<span class="hljs-string">"scope:shared-components"</span>, <span class="hljs-string">"type:ui"</span>],
<span class="hljs-comment">// ...</span>
</code></pre>
<p>More here : <a target="_blank" href="https://nx.dev/features/enforce-module-boundaries#tags">https://nx.dev/features/enforce-module-boundaries#tags</a></p>
<h2 id="heading-a-slightly-more-concrete-example">A slightly more concrete example</h2>
<p>Now that we see how to create libraries with tags let’s bring back my previous example (<a target="_blank" href="https://gillesferrand.com/nx-library-types">https://gillesferrand.com/nx-library-types</a>)</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721601127961/75bf08ee-7ca5-475d-af6b-4e00e8e0b05e.png?auto=compress,format&amp;format=webp" alt /></p>
<p>We want to create a new rule to be sure everything is secured by linting</p>
<p>Let’s start with util rules</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> nx <span class="hljs-keyword">from</span> <span class="hljs-string">'@nx/eslint-plugin'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> [
    ...,
    <span class="hljs-attr">rules</span>: {
      <span class="hljs-string">'@nx/enforce-module-boundaries'</span>: [
        <span class="hljs-string">'error'</span>,
         {
             <span class="hljs-attr">enforceBuildableLibDependency</span>: <span class="hljs-literal">true</span>,
             <span class="hljs-attr">allow</span>: [<span class="hljs-string">'^.*/eslint(\\.base)?\\.config\\.[cm]?[jt]s$'</span>],
             <span class="hljs-attr">depConstraints</span>: [
                 {
                  <span class="hljs-attr">sourceTag</span>: <span class="hljs-string">'type:util'</span>,
                  <span class="hljs-attr">onlyDependOnLibsWithTags</span>: [<span class="hljs-string">'type:util'</span>],
                 },
             ]
         }
      ],
    },
  },
  ...,
];
</code></pre>
<p>With two lines of configuration I warn NX that every libraries tagged util can only import other libraries tagged util. This constraint exists because utility libraries are specifically designed for models, types, and static functions - they should never contain components, features, or services. If we allow util libraries to import from feature libraries, data-access libraries, or ui libraries, we break the foundational nature of these utilities.</p>
<p>This strict rule ensures that util libraries remain purely functional and can serve as the bedrock of your architecture. Components belong in UI libraries (tagged as 'ui'), which can depend on util libraries to access shared models and helper functions, but not the other way around. This one-way dependency flow - where UI components can use utilities, but utilities cannot use components - prevents circular dependencies and keeps your architecture clean and predictable.</p>
<p>Here’s a more complex example</p>
<pre><code class="lang-json">            <span class="hljs-string">"depConstraints"</span>: [
              {
                <span class="hljs-attr">"sourceTag"</span>: <span class="hljs-string">"type:app"</span>,
                <span class="hljs-attr">"onlyDependOnLibsWithTags"</span>: [
                  <span class="hljs-string">"type:shell"</span>,
                  <span class="hljs-string">"type:feature"</span>,
                ]
              },
              {
                <span class="hljs-attr">"sourceTag"</span>: <span class="hljs-string">"scope:fithelper-front"</span>,
                <span class="hljs-attr">"onlyDependOnLibsWithTags"</span>: [
                  <span class="hljs-string">"scope:fithelper-front"</span>,
                  <span class="hljs-string">"scope:shared"</span>
                ]
              },
              {
                <span class="hljs-attr">"sourceTag"</span>: <span class="hljs-string">"scope:shared"</span>,
                <span class="hljs-attr">"onlyDependOnLibsWithTags"</span>: [<span class="hljs-string">"scope:shared"</span>]
              },
              {
                <span class="hljs-attr">"sourceTag"</span>: <span class="hljs-string">"type:feature"</span>,
                <span class="hljs-attr">"onlyDependOnLibsWithTags"</span>: [
                  <span class="hljs-string">"type:feature"</span>,
                  <span class="hljs-string">"type:ui"</span>,
                  <span class="hljs-string">"type:util"</span>,
                  <span class="hljs-string">"type:data-access"</span>,
                  <span class="hljs-string">"type:facade"</span>
                ]
              },
              {
                <span class="hljs-attr">"sourceTag"</span>: <span class="hljs-string">"type:data-access"</span>,
                <span class="hljs-attr">"onlyDependOnLibsWithTags"</span>: [<span class="hljs-string">"type:data-access"</span>, <span class="hljs-string">"type:util"</span>]
              },
              {
                <span class="hljs-attr">"sourceTag"</span>: <span class="hljs-string">"type:state"</span>,
                <span class="hljs-attr">"onlyDependOnLibsWithTags"</span>: [<span class="hljs-string">"type:state"</span>, <span class="hljs-string">"type:util"</span>]
              },
              {
                <span class="hljs-attr">"sourceTag"</span>: <span class="hljs-string">"type:facade"</span>,
                <span class="hljs-attr">"onlyDependOnLibsWithTags"</span>: [<span class="hljs-string">"type:state"</span>, <span class="hljs-string">"type:util"</span>]
              },
              {
                <span class="hljs-attr">"sourceTag"</span>: <span class="hljs-string">"type:ui"</span>,
                <span class="hljs-attr">"onlyDependOnLibsWithTags"</span>: [<span class="hljs-string">"type:ui"</span>, <span class="hljs-string">"type:util"</span>]
              },
              {
                <span class="hljs-attr">"sourceTag"</span>: <span class="hljs-string">"type:util"</span>,
                <span class="hljs-attr">"onlyDependOnLibsWithTags"</span>: [<span class="hljs-string">"type:util"</span>]
              },
              {
                <span class="hljs-attr">"sourceTag"</span>: <span class="hljs-string">"type:shell"</span>,
                <span class="hljs-attr">"onlyDependOnLibsWithTags"</span>: [
                  <span class="hljs-string">"type:shell"</span>,
                  <span class="hljs-string">"type:feature"</span>,
                  <span class="hljs-string">"type:data-access"</span>,
                  <span class="hljs-string">"type:state"</span>,
                  <span class="hljs-string">"type:facade"</span>,
                  <span class="hljs-string">"type:ui"</span>,
                  <span class="hljs-string">"type:util"</span>
                ]
              }
            ]
</code></pre>
<p>As you can see, you can create whatever boundaries you need : scopes, domains, team ownership, or any custom rules that fit your architecture. NX provides the foundational tools, and you define the constraints that make sense for your project. The more thoughtfully you design these boundaries, the more NX can help you maintain architectural consistency and prevent violations.</p>
<p>The beauty of this approach is its flexibility, but also its potential pitfall. While you can create any boundaries you need resist the urge to over-engineer from the start. Creating 200 scopes and 200 library types will overwhelm your team rather than help them. Start simple with 3-4 clear library types and basic scopes, then add constraints only when you encounter real problems. NX scales with your needs, so let your architecture evolve naturally.</p>
<p><a target="_blank" href="https://nx.dev/concepts/decisions/project-dependency-rules#other-types">https://nx.dev/concepts/decisions/project-dependency-rules#other-types</a></p>
<h2 id="heading-ok-but-how-nx-enforce-it">Ok.. but how NX enforce it ?</h2>
<p>With ESlint !  </p>
<p>If I try to import UI library in Util my IDE will warn me that’s is not authorized</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752681661139/ab85be25-095e-429f-85bb-3adb0d6e166a.png" alt class="image--center mx-auto" /></p>
<p>And lint job will do it too</p>
<p><code>nx run shared-local-storage-util:lint</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752681802590/fb206dcc-72a0-4fa9-a58b-4e92593e4b61.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-other-ressource">Other ressource</h2>
<p><a target="_blank" href="https://www.youtube.com/watch?v=q0en5vlOsWY">https://www.youtube.com/watch?v=q0en5vlOsWY</a></p>
<p><a target="_blank" href="https://nx.dev/concepts/decisions/project-dependency-rules#other-types">https://nx.dev/concepts/decisions/project-dependency-rules#other-types</a></p>
<p><a target="_blank" href="https://nx.dev/features/enforce-module-boundaries#enforce-module-boundaries">https://nx.dev/features/enforce-module-boundaries#enforce-module-boundaries</a></p>
]]></content:encoded></item><item><title><![CDATA[React without JSX and why it's important]]></title><description><![CDATA[Quick setup
npm create vite@latest my-app -- --template react
cd my-app
npm install tailwindcss @tailwindcss/vite

// vite.config.ts
import tailwindcss from '@tailwindcss/vite'
import react from '@vitejs/plugin-react'
import { defineConfig } from 'vi...]]></description><link>https://gillesferrand.com/react-without-jsx-and-why-its-important</link><guid isPermaLink="true">https://gillesferrand.com/react-without-jsx-and-why-its-important</guid><category><![CDATA[React]]></category><category><![CDATA[JSX]]></category><dc:creator><![CDATA[Gilles Ferrand]]></dc:creator><pubDate>Mon, 14 Jul 2025 15:25:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1752506642453/a207eb34-27d5-4ab4-aa4a-a5eab1b47ab4.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-quick-setup">Quick setup</h2>
<pre><code class="lang-bash">npm create vite@latest my-app -- --template react
<span class="hljs-built_in">cd</span> my-app
npm install tailwindcss @tailwindcss/vite
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-comment">// vite.config.ts</span>
<span class="hljs-keyword">import</span> tailwindcss <span class="hljs-keyword">from</span> <span class="hljs-string">'@tailwindcss/vite'</span>
<span class="hljs-keyword">import</span> react <span class="hljs-keyword">from</span> <span class="hljs-string">'@vitejs/plugin-react'</span>
<span class="hljs-keyword">import</span> { defineConfig } <span class="hljs-keyword">from</span> <span class="hljs-string">'vite'</span>


<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> defineConfig({
  plugins: [
    react(), 
    <span class="hljs-comment">// Add this</span>
    tailwindcss()],
})
</code></pre>
<pre><code class="lang-css"><span class="hljs-comment">/* index.css */</span>
<span class="hljs-keyword">@import</span> <span class="hljs-string">"tailwindcss"</span>;
</code></pre>
<h2 id="heading-create-component-without-jsx">Create component without JSX</h2>
<p>And yes, you can write React componentg without JSX, I will show you how and why you shouldn’t</p>
<p>We will use React.createElement to generate our element instead of using JSX</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> { createRoot } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom/client'</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'./index.css'</span>

<span class="hljs-keyword">const</span> element = React.createElement(
  <span class="hljs-comment">// DOM element</span>
  <span class="hljs-string">'h1'</span>, 
  <span class="hljs-comment">// Attributes</span>
  {<span class="hljs-attr">className</span>: <span class="hljs-string">'text-3xl font-bold underline'</span>}, 
  <span class="hljs-comment">// Children</span>
  <span class="hljs-string">'Hello, world!'</span>)

createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>)).render(element)
</code></pre>
<p>Sweet it’s working</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752501929088/08d8f1f5-f8bf-4e47-8d6f-c7070e812c59.png" alt class="image--center mx-auto" /></p>
<p>But now what if I need nested element ? It’s also possible</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> { createRoot } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom/client'</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'./index.css'</span>

<span class="hljs-keyword">const</span> element = React.createElement(
  <span class="hljs-string">'section'</span>, 
  {<span class="hljs-attr">className</span>: <span class="hljs-string">'border border-red-500 border-solid'</span>, <span class="hljs-attr">id</span>: <span class="hljs-string">'main-heading'</span>}, 
  React.createElement(
    <span class="hljs-string">'h1'</span>,
    {<span class="hljs-attr">className</span>: <span class="hljs-string">'text-3xl font-bold underline'</span>}, 
    <span class="hljs-string">'Hello, world!'</span>
  ),
  React.createElement(
    <span class="hljs-string">'p'</span>,
    <span class="hljs-literal">null</span>, 
    <span class="hljs-string">'I am Gilles, a software engineer!'</span>
  )
)

createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>)).render(element)
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752502267912/613edb6b-7cd5-4c9d-9376-62993a24b43a.png" alt class="image--center mx-auto" /></p>
<p>We are starting to see the main problem of React.createElement but let me exagerate it</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { createRoot } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom/client'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./index.css'</span>;

<span class="hljs-keyword">const</span> element = React.createElement(
  <span class="hljs-string">'div'</span>,
  { 
    <span class="hljs-attr">className</span>: <span class="hljs-string">'min-h-screen bg-gradient-to-br from-slate-50 to-blue-50 flex items-center justify-center p-4'</span>
  },
  React.createElement(
    <span class="hljs-string">'div'</span>,
    { <span class="hljs-attr">className</span>: <span class="hljs-string">'max-w-2xl w-full bg-white rounded-2xl shadow-xl border border-slate-200 overflow-hidden'</span> },
    React.createElement(
      <span class="hljs-string">'div'</span>,
      { <span class="hljs-attr">className</span>: <span class="hljs-string">'bg-gradient-to-r from-blue-600 to-indigo-600 px-8 py-6'</span> },
      React.createElement(
        <span class="hljs-string">'h1'</span>,
        { 
          <span class="hljs-attr">className</span>: <span class="hljs-string">'text-3xl font-bold text-white mb-2'</span>,
          <span class="hljs-attr">id</span>: <span class="hljs-string">'main-heading'</span>
        },
        <span class="hljs-string">'Complex Nested Example'</span>
      ),
      React.createElement(
        <span class="hljs-string">'p'</span>,
        { <span class="hljs-attr">className</span>: <span class="hljs-string">'text-blue-100 text-lg'</span> },
        <span class="hljs-string">'This demonstrates more complex nesting with multiple elements and attributes.'</span>
      )
    ),
    React.createElement(
      <span class="hljs-string">'div'</span>,
      { <span class="hljs-attr">className</span>: <span class="hljs-string">'p-8 space-y-6'</span> },
      React.createElement(
        <span class="hljs-string">'div'</span>,
        { <span class="hljs-attr">className</span>: <span class="hljs-string">'space-y-4'</span> },
        React.createElement(<span class="hljs-string">'h2'</span>, { <span class="hljs-attr">className</span>: <span class="hljs-string">'text-2xl font-semibold text-slate-800 border-b border-slate-200 pb-2'</span> }, <span class="hljs-string">'Subheading'</span>),
        React.createElement(<span class="hljs-string">'p'</span>, { <span class="hljs-attr">className</span>: <span class="hljs-string">'text-slate-600 leading-relaxed'</span> }, <span class="hljs-string">'Another paragraph nested deeper in the structure with improved readability and spacing.'</span>)
      ),
      React.createElement(
        <span class="hljs-string">'div'</span>,
        { <span class="hljs-attr">className</span>: <span class="hljs-string">'bg-slate-50 rounded-lg p-6'</span> },
        React.createElement(<span class="hljs-string">'ul'</span>, { <span class="hljs-attr">className</span>: <span class="hljs-string">'space-y-3'</span> },
          React.createElement(<span class="hljs-string">'li'</span>, { <span class="hljs-attr">className</span>: <span class="hljs-string">'flex items-center text-slate-700'</span> }, 
            React.createElement(<span class="hljs-string">'span'</span>, { <span class="hljs-attr">className</span>: <span class="hljs-string">'w-2 h-2 bg-blue-500 rounded-full mr-3'</span> }),
            <span class="hljs-string">'Enhanced Item 1 with better styling'</span>
          ),
          React.createElement(<span class="hljs-string">'li'</span>, { <span class="hljs-attr">className</span>: <span class="hljs-string">'flex items-center text-slate-700'</span> }, 
            React.createElement(<span class="hljs-string">'span'</span>, { <span class="hljs-attr">className</span>: <span class="hljs-string">'w-2 h-2 bg-blue-500 rounded-full mr-3'</span> }),
            <span class="hljs-string">'Enhanced Item 2 with better styling'</span>
          ),
          React.createElement(<span class="hljs-string">'li'</span>, { <span class="hljs-attr">className</span>: <span class="hljs-string">'flex items-center text-slate-700'</span> }, 
            React.createElement(<span class="hljs-string">'span'</span>, { <span class="hljs-attr">className</span>: <span class="hljs-string">'w-2 h-2 bg-blue-500 rounded-full mr-3'</span> }),
            <span class="hljs-string">'Enhanced Item 3 with better styling'</span>
          )
        )
      ),
      React.createElement(
        <span class="hljs-string">'div'</span>,
        { <span class="hljs-attr">className</span>: <span class="hljs-string">'flex justify-center pt-4'</span> },
        React.createElement(<span class="hljs-string">'button'</span>, { 
          <span class="hljs-attr">className</span>: <span class="hljs-string">'bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to-indigo-700 text-white font-semibold px-8 py-3 rounded-full shadow-lg hover:shadow-xl transform hover:scale-105 transition-all duration-200 focus:outline-none focus:ring-4 focus:ring-blue-300'</span> 
        }, <span class="hljs-string">'Click me'</span>)
      )
    )
  )
);

createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>)).render(element)
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752502853375/d2fd76ae-0b00-472b-ba51-b562a46dcc63.png" alt class="image--center mx-auto" /></p>
<p>Nesting, nesting and… nesting, yes it does work but it’ll be horrible to maintain and to read, that’s why JSX is useful, JSX is immediately more readable, familiar to anyone who knows HTML, and significantly easier to maintain.</p>
<p>I will deep-dive into JSX in a future article but here is the code with JSX</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { createRoot } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom/client'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./index.css'</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"min-h-screen bg-gradient-to-br from-slate-50 to-blue-50 flex items-center justify-center p-4"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-2xl w-full bg-white rounded-2xl shadow-xl border border-slate-200 overflow-hidden"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-gradient-to-r from-blue-600 to-indigo-600 px-8 py-6"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> 
            <span class="hljs-attr">className</span>=<span class="hljs-string">"text-3xl font-bold text-white mb-2"</span> 
            <span class="hljs-attr">id</span>=<span class="hljs-string">"main-heading"</span>
          &gt;</span>
            Complex Nested Example
          <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-blue-100 text-lg"</span>&gt;</span>
            This demonstrates more complex nesting with multiple elements and attributes.
          <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-8 space-y-6"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"space-y-4"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-2xl font-semibold text-slate-800 border-b border-slate-200 pb-2"</span>&gt;</span>
              Subheading
            <span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-slate-600 leading-relaxed"</span>&gt;</span>
              Another paragraph nested deeper in the structure with improved readability and spacing.
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-slate-50 rounded-lg p-6"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"space-y-3"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center text-slate-700"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-2 h-2 bg-blue-500 rounded-full mr-3"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                Enhanced Item 1 with better styling
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center text-slate-700"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-2 h-2 bg-blue-500 rounded-full mr-3"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                Enhanced Item 2 with better styling
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center text-slate-700"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-2 h-2 bg-blue-500 rounded-full mr-3"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                Enhanced Item 3 with better styling
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex justify-center pt-4"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to-indigo-700 text-white font-semibold px-8 py-3 rounded-full shadow-lg hover:shadow-xl transform hover:scale-105 transition-all duration-200 focus:outline-none focus:ring-4 focus:ring-blue-300"</span>&gt;</span>
              Click me
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>)).render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span></span>)
</code></pre>
<p>And imagine if you just create component for each of your needs it will be cleaner and cleaner</p>
]]></content:encoded></item><item><title><![CDATA[How to use the JavaScript spread operator effectively]]></title><description><![CDATA[The spread operator (...) is one of the most useful features in modern JavaScript. It allows you to expand arrays, objects, and other iterable elements in places where multiple elements are expected. This article will explain how to use the spread op...]]></description><link>https://gillesferrand.com/how-to-use-the-javascript-spread-operator-effectively</link><guid isPermaLink="true">https://gillesferrand.com/how-to-use-the-javascript-spread-operator-effectively</guid><category><![CDATA[js]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Spread operator]]></category><dc:creator><![CDATA[Gilles Ferrand]]></dc:creator><pubDate>Fri, 11 Jul 2025 15:36:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1752248049800/05f93f9f-b39b-488e-ba37-c1e64ddec9fb.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The spread operator (...) is one of the most useful features in modern JavaScript. It allows you to expand arrays, objects, and other iterable elements in places where multiple elements are expected. This article will explain how to use the spread operator effectively.</p>
<h2 id="heading-what-is-the-spread-operator">What is the spread operator</h2>
<p>The spread operator uses three dots (...) before a variable name. It "spreads" or expands the contents of arrays, objects, or strings into individual elements.</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log([🍏,🍐,🍊]); <span class="hljs-comment">// Output: [🍏,🍐,🍊]</span>
<span class="hljs-comment">// With spread operator</span>
<span class="hljs-built_in">console</span>.log(...[🍏,🍐,🍊]); <span class="hljs-comment">// Output: 🍏 🍐 🍊</span>
</code></pre>
<h2 id="heading-using-spread-operator-with-arrays">Using spread operator with Arrays</h2>
<p>You can create a <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/Shallow_copy">shallow copy</a> of an array</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> originalArray = [🍏,🍐,🍊];
<span class="hljs-keyword">const</span> copiedArray = [...originalArray];

<span class="hljs-built_in">console</span>.log(copiedArray); <span class="hljs-comment">// [🍏,🍐,🍊]</span>
</code></pre>
<p>You can merge multiple arrays easily</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fruits = [🍏, 🍌];
<span class="hljs-keyword">const</span> vegetables = [🥕, 🍠];
<span class="hljs-keyword">const</span> food = [...fruits, ...vegetables];

<span class="hljs-built_in">console</span>.log(food); <span class="hljs-comment">// [🍏, 🍌, 🥕, 🍠]</span>
</code></pre>
<p>You can insert new elements while keeping existing ones</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> healthyFood = [🍏, 🍌, 🥕, 🍠];
<span class="hljs-keyword">const</span> moreHealthyFood = [🍑, ...healthyFood, 🥦, 🥑];

<span class="hljs-built_in">console</span>.log(moreHealthyFood); <span class="hljs-comment">// [🍑, 🍏, 🍌, 🥕, 🍠, 🥦, 🥑]</span>
</code></pre>
<h2 id="heading-using-spread-operator-with-object">Using spread operator with Object</h2>
<p>You can create a <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/Shallow_copy">shallow copy</a> of an object</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> person = { <span class="hljs-attr">name</span>: <span class="hljs-string">'Gilles'</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">29</span> };
<span class="hljs-keyword">const</span> personCopy = { ...person };

<span class="hljs-built_in">console</span>.log(personCopy); <span class="hljs-comment">// { name: 'Gilles', age: 29 }</span>
</code></pre>
<p>You can combine multiple objects into one</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> person = { <span class="hljs-attr">name</span>: <span class="hljs-string">'Gilles'</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">29</span> };
<span class="hljs-keyword">const</span> contactInfo = { <span class="hljs-attr">email</span>: <span class="hljs-string">'gilles@email.com'</span>, <span class="hljs-attr">phone</span>: <span class="hljs-string">'123-456-7890'</span> };
<span class="hljs-keyword">const</span> fullProfile = { ...person, ...contactInfo };

<span class="hljs-built_in">console</span>.log(fullProfile);
<span class="hljs-comment">// { name: 'Gilles', age: 29, email: 'gilles@email.com', phone: '123-456-7890' }</span>
</code></pre>
<p>You can override specific properties of an object while keeping others</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> person = { <span class="hljs-attr">name</span>: <span class="hljs-string">'Gilles'</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">29</span>, <span class="hljs-attr">city</span>: <span class="hljs-string">'Toulouse'</span> };
<span class="hljs-keyword">const</span> updatedPerson = { ...person, <span class="hljs-attr">age</span>: <span class="hljs-number">29</span>, <span class="hljs-attr">country</span>: <span class="hljs-string">'France'</span> };

<span class="hljs-built_in">console</span>.log(updatedPerson);
<span class="hljs-comment">// { name: 'Gilles', age: 29, city: 'Toulouse', country: 'France' }</span>
</code></pre>
<h2 id="heading-using-spread-with-function-arguments">Using Spread with Function Arguments</h2>
<p>You can pass array elements as separate arguments to functions:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addThreeNumbers</span>(<span class="hljs-params">a, b, c</span>) </span>{
    <span class="hljs-keyword">return</span> a + b + c;
}

<span class="hljs-keyword">const</span> numbers = [<span class="hljs-number">5</span>, <span class="hljs-number">10</span>, <span class="hljs-number">15</span>];
<span class="hljs-keyword">const</span> result = addThreeNumbers(...numbers);

<span class="hljs-built_in">console</span>.log(result); <span class="hljs-comment">// 30</span>
</code></pre>
<h2 id="heading-using-spread-with-strings">Using Spread with Strings</h2>
<p>You can spread a string into individual characters:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> word = <span class="hljs-string">'hello'</span>;
<span class="hljs-keyword">const</span> letters = [...word];

<span class="hljs-built_in">console</span>.log(letters); <span class="hljs-comment">// ['h', 'e', 'l', 'l', 'o']</span>
</code></pre>
<h2 id="heading-important-notes">Important Notes</h2>
<h3 id="heading-shallow-copy-limitation">Shallow Copy Limitation</h3>
<p>The spread operator creates shallow copies, not deep copies. This means nested objects or arrays are still referenced:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> original = { 
    <span class="hljs-attr">name</span>: <span class="hljs-string">'Gilles'</span>, 
    <span class="hljs-attr">hobbies</span>: [<span class="hljs-string">'reading'</span>, <span class="hljs-string">'coding'</span>] 
};

<span class="hljs-keyword">const</span> copy = { ...original };
copy.hobbies.push(<span class="hljs-string">'cycling'</span>);

<span class="hljs-built_in">console</span>.log(original.hobbies); <span class="hljs-comment">// ['reading', 'coding', 'cycling']</span>
<span class="hljs-comment">// The original object is affected!</span>
</code></pre>
<h3 id="heading-order-matters">Order Matters</h3>
<p>When merging objects, properties from later objects override earlier ones:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> obj1 = { <span class="hljs-attr">a</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">b</span>: <span class="hljs-number">2</span> };
<span class="hljs-keyword">const</span> obj2 = { <span class="hljs-attr">b</span>: <span class="hljs-number">3</span>, <span class="hljs-attr">c</span>: <span class="hljs-number">4</span> };
<span class="hljs-keyword">const</span> merged = { ...obj1, ...obj2 };

<span class="hljs-built_in">console</span>.log(merged); <span class="hljs-comment">// { a: 1, b: 3, c: 4 }</span>
<span class="hljs-comment">// obj2.b overrides obj1.b</span>
</code></pre>
<h2 id="heading-deep-copying-with-spread">Deep Copying with Spread</h2>
<p>While the spread operator creates shallow copies, you can achieve deep copying by combining it with other techniques:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// For simple nested objects (no functions, dates, etc.)</span>
<span class="hljs-keyword">const</span> original = {
    <span class="hljs-attr">name</span>: <span class="hljs-string">'Gilles'</span>,
    <span class="hljs-attr">address</span>: { <span class="hljs-attr">city</span>: <span class="hljs-string">'Toulouse'</span>, <span class="hljs-attr">country</span>: <span class="hljs-string">'France'</span> },
    <span class="hljs-attr">hobbies</span>: [<span class="hljs-string">'reading'</span>, <span class="hljs-string">'coding'</span>]
};

<span class="hljs-keyword">const</span> deepCopy = {
    ...original,
    <span class="hljs-attr">address</span>: { ...original.address },
    <span class="hljs-attr">hobbies</span>: [...original.hobbies]
};

<span class="hljs-comment">// Now changes to deepCopy won't affect original</span>
deepCopy.address.city = <span class="hljs-string">'Montréal'</span>;
deepCopy.hobbies.push(<span class="hljs-string">'cycling'</span>);

<span class="hljs-built_in">console</span>.log(original.address.city); <span class="hljs-comment">// 'Toulouse' (unchanged)</span>
<span class="hljs-built_in">console</span>.log(original.hobbies); <span class="hljs-comment">// ['reading', 'coding'] (unchanged)</span>
</code></pre>
<h2 id="heading-real-life-example-in-react-and-angular">Real life example in React and Angular</h2>
<h3 id="heading-react-use-cases">React Use Cases</h3>
<p>The spread operator is essential in React for:</p>
<ul>
<li><p><strong>State updates</strong>: Change one property in a state object while keeping others unchanged</p>
</li>
<li><p><strong>Props passing</strong>: Send multiple properties to child components at once</p>
</li>
<li><p><strong>Array state management</strong>: Add or remove items from lists without mutating the original array</p>
</li>
<li><p><strong>Event handling</strong>: Create new objects when updating form data</p>
</li>
<li><p><strong>Component composition</strong>: Combine default props with custom props</p>
</li>
</ul>
<h3 id="heading-angular-use-cases">Angular Use Cases</h3>
<p>In Angular, the spread operator helps with:</p>
<ul>
<li><p><strong>Data binding</strong>: Update component properties while preserving existing data</p>
</li>
<li><p><strong>Array manipulation</strong>: Add, remove, or modify items in lists for templates</p>
</li>
<li><p><strong>Form handling</strong>: Create updated objects when processing form submissions</p>
</li>
<li><p><strong>API responses</strong>: Merge server data with local component state</p>
</li>
<li><p><strong>Template data</strong>: Combine multiple data sources for display</p>
</li>
</ul>
<p>Both frameworks benefit from the spread operator because it helps create new objects and arrays instead of modifying existing ones, which prevents unexpected bugs and makes applications more predictable.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>The spread operator is a powerful tool that makes JavaScript code cleaner and more readable. It simplifies many common tasks like copying arrays, merging objects, and passing arguments to functions. With careful use, you can even achieve deep copying without external libraries.</p>
<p>Practice using the spread operator in your projects to become more comfortable with this essential JavaScript feature. Start with simple cases and gradually work your way up to more complex scenarios.</p>
]]></content:encoded></item><item><title><![CDATA[NX : Library types]]></title><description><![CDATA[Understanding libraries types
Hello friends 🚀! As we saw in the previous article, one of NX's core features is the ability to create libraries. These libraries can be categorized into different types, each serving a unique purpose and playing a spec...]]></description><link>https://gillesferrand.com/nx-library-types</link><guid isPermaLink="true">https://gillesferrand.com/nx-library-types</guid><category><![CDATA[Nx]]></category><category><![CDATA[nx-workspace]]></category><category><![CDATA[library]]></category><dc:creator><![CDATA[Gilles Ferrand]]></dc:creator><pubDate>Sun, 21 Jul 2024 22:49:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1721602132473/bb841475-de10-464a-8e04-e7be862d5652.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-understanding-libraries-types">Understanding libraries types</h2>
<p>Hello friends 🚀! As we saw in the <a target="_blank" href="https://gillesferrand.com/start-building-your-first-library-in-nx-a-simple-guide">previous article</a>, one of NX's core features is the ability to create libraries. These libraries can be categorized into different types, each serving a unique purpose and playing a specific role in your project. Understanding these library types is crucial for organizing your codebase efficiently and making the most of NX's powerful capabilities. Even without NX, it's a good idea to separate your codebase into libraries. NX helps you leverage all of these benefits.</p>
<h3 id="heading-feature-library">Feature library</h3>
<p>Feature libraries encapsulate a specific feature or functionality within your application. They are designed to be reusable and can be imported into multiple applications as a feature. The feature library will include everything you need to create a functionality. It can import all other types of libraries to build it. It can also import other feature libraries to create a larger one.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721585005462/b7343847-228c-463c-a5db-62a43a2aac33.png" alt class="image--center mx-auto" /></p>
<p><strong>Example :</strong> You could create a weather widget that you want to display in multiples of your application</p>
<p>So you will create a grouping folder named weather-widget and generate your library</p>
<blockquote>
<p>weather-widget/feature -&gt; your feature</p>
</blockquote>
<p>We will see what you can import on this library and why below</p>
<h3 id="heading-ui-library">Ui library</h3>
<p>UI libraries focus on providing reusable, simple UI components. These components are generally presentational and do not contain any business logic. By centralizing your UI components in libraries, you ensure consistency across your application and make it easier to update and maintain your UI. UI libraries can import utility libraries and other UI libraries, but they cannot import feature libraries or data-access libraries. A dumb component cannot contain an entire feature or a service to manage your application's data. It makes sense.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721585925073/7b584e66-5beb-4f0e-8da1-31ee6bb8e6e0.png" alt class="image--center mx-auto" /></p>
<p><strong>Example :</strong> For your weather-widget you will need to create a dumb component that will take some inputs coming from the back-end, and display the actual weather in a nice way.</p>
<blockquote>
<p>weather-widget/feature -&gt; your feature</p>
<p>weather-widget/ui -&gt; the dumb component stuff for your feature</p>
</blockquote>
<h3 id="heading-data-access-library">Data-access library</h3>
<p>Data access libraries handle interactions with external data sources, such as APIs or databases. They encapsulate the logic for making HTTP requests, handling data transformations, and managing state related to data access. This separation helps keep your feature libraries clean and focused on their specific responsibilities. Since you need to expose your interface in other libraries, you should store the interface linked to your service in another type: util. You can import both data-access and util types into data-access.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721586887752/6e8adf6e-41e6-426c-93a6-6c49b4c2bfa0.png" alt class="image--center mx-auto" /></p>
<p><strong>Example :</strong> For your weather-widget you will need to create a service so your feature will be able to get the current weather data and display it with it's dumb component</p>
<blockquote>
<p>weather-widget/feature -&gt; your functionnality</p>
<p>weather-widget/ui -&gt; the dumb component stuff for your feature</p>
<p>weather-widget/data-access -&gt; the service to get the data for your feature</p>
</blockquote>
<h3 id="heading-util-library">Util library</h3>
<p>As explained above, sometimes you will need to make imports that aren't possible without a type that doesn't depend on others. The Util library exists for this reason. Util(ity) libraries are collections of reusable types, interfaces, helper functions, pipes, and other utilities that can be used throughout your application. This library can be imported by any other existing types because it only depends on other util libraries.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721587177166/12bc3180-3b7b-4362-9a6e-c65a315c42ba.png" alt class="image--center mx-auto" /></p>
<p><strong>Example :</strong> For your weather-widget you will need to create an interface for the data so you can use this interface in : feature for the input, ui to structure your dumb component, and in data-access to correctly type the object coming from the back-end.</p>
<blockquote>
<p>weather-widget/feature -&gt; your functionnality</p>
<p>weather-widget/ui -&gt; the dumb component stuff for your feature</p>
<p>weather-widget/data-access -&gt; the service to get the data for your feature</p>
<p>weather-widget/util -&gt; the interface for the data for your data-access</p>
</blockquote>
<h3 id="heading-shell-library">Shell library</h3>
<p>In NX, a "shell" library refers to a routing library that exposes routes, allowing it to be imported into multiple applications seamlessly. This type of library is particularly useful in a microfrontend architecture or in scenarios where you want to share a common routing configuration across several applications.</p>
<h2 id="heading-overview">Overview</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721599794063/acc833d2-485e-490e-9b8a-77100d49851a.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-can-i-create-other-types">Can I create other types ?</h3>
<p>Of course you can create as much types as you need, a good practice is trying to keep the number of them low. Because it can be hard to understand or you will need to document it clearly so every new member of your team can understand the goal of each types.</p>
<p><strong>Example :</strong> You could create state libraries to separate data-access services and state management in your application. This way, feature libraries wouldn't depend directly on data-access services. You could also add a facade library so that features wouldn't depend on state libraries directly. Instead, the facade would depend only on state libraries.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721601127961/75bf08ee-7ca5-475d-af6b-4e00e8e0b05e.png" alt class="image--center mx-auto" /></p>
<p>In next article we will see how to enforce these rules with ESLint and NX.</p>
<h2 id="heading-ressources">Ressources</h2>
<p><a target="_blank" href="https://nx.dev/concepts/decisions/project-dependency-rules">https://nx.dev/concepts/decisions/project-dependency-rules</a></p>
]]></content:encoded></item><item><title><![CDATA[Start Building Your First Library in NX: A Simple Guide]]></title><description><![CDATA[Introduction
Hello friends 🚀! In a monorepo, the mindset shifts from thinking in terms of applications to thinking in terms of libraries. This approach encourages the creation of reusable, modular code that can be shared across multiple applications...]]></description><link>https://gillesferrand.com/start-building-your-first-library-in-nx-a-simple-guide</link><guid isPermaLink="true">https://gillesferrand.com/start-building-your-first-library-in-nx-a-simple-guide</guid><category><![CDATA[module bondaries]]></category><category><![CDATA[nx-libraries]]></category><category><![CDATA[Nx]]></category><category><![CDATA[nx-workspace]]></category><dc:creator><![CDATA[Gilles Ferrand]]></dc:creator><pubDate>Mon, 15 Jul 2024 22:26:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1720883336771/b19d29ec-739a-4304-b98d-96d5094dd5ff.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Hello friends 🚀! In a monorepo, the mindset shifts from thinking in terms of applications to thinking in terms of libraries. This approach encourages the creation of reusable, modular code that can be shared across multiple applications. To illustrate this concept, I will demonstrate how to create a reusable button component.</p>
<p>Initially, I could implement this button directly within the <code>apps</code> directory because my immediate need is to display it in my <code>register-front</code> application. However, by doing so, I limit the reusability of this component. What if, in the future, I need to use this button in a different application within the same monorepo? By coding it as a library from the start, I ensure that this button is easily accessible across all my applications.</p>
<p>Creating the button as a library doesn't require much extra effort, but it brings significant benefits:</p>
<ol>
<li><p><strong>Reusability</strong>: Libraries are designed to be reusable across multiple applications. By placing the button component in a library, I can import and use it in any current or future applications within the monorepo.</p>
</li>
<li><p><strong>Maintainability</strong>: Centralizing the button component in a library makes maintenance easier. Any updates or bug fixes to the button can be made in one place, and all applications using the library will automatically benefit from the changes.</p>
</li>
<li><p><strong>Consistency</strong>: Using a library ensures that the button component behaves consistently across all applications. This helps in maintaining a uniform user experience and reduces the risk of discrepancies.</p>
</li>
<li><p><strong>Separation of Concerns</strong>: Libraries promote the separation of concerns by encapsulating specific functionalities. This modularity makes the codebase cleaner and easier to understand.</p>
</li>
<li><p><strong>NX Advantages</strong>: NX provides powerful tools for managing libraries, such as dependency graph visualization, and efficient incremental builds. Leveraging these tools enhances the development experience and optimizes the build process.</p>
</li>
</ol>
<p>By coding the button component as a library, I am taking full advantage of NX's capabilities, ensuring my code is modular, reusable, and maintainable. This approach aligns with best practices in modern software development and sets the foundation for scalable and efficient applications.</p>
<h2 id="heading-lets-create-our-first-library">Let's create our first library</h2>
<p>The first step to create a library is to create a folder <code>libs</code> at the root of the project</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720882788310/c5b66819-e725-428d-9f31-434b44ae4d0d.png" alt class="image--center mx-auto" /></p>
<p>To determine the scope of my library, I need to ask where this feature will be used. For a button, it's straightforward—I need to use it everywhere. So, I will create a new folder called <code>shared</code>. This <code>shared</code> folder can be considered as a scope.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720882921863/faf3b3e8-c5e3-400c-8219-0f7d3ee88025.png" alt class="image--center mx-auto" /></p>
<p>I could put my library directly in the shared folder, but with more experience, you'll see that it's easier to be very precise. So, I will create a grouping folder for all my shared dumb components and another grouping folder for my button.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720883044643/31130b4f-f8cf-40be-bc22-73253f313fa5.png" alt class="image--center mx-auto" /></p>
<p>Finally, I can create my library. As a developer, I appreciate simplicity, and thankfully NX makes it easy. I will use the NX CLI to create it. However, since using the CLI can be tedious, I will use the <a target="_blank" href="https://nx.dev/getting-started/editor-setup#official-integrations">NX Console</a> instead.</p>
<p>I use Angular so I choose <code>Library @nx/angular</code> in NX Console, and I can fill the form</p>
<blockquote>
<p>Library name: It's a good practice to name libraries in their grouping folders by their types. We will discuss library types in the next article. I will use ui for the name. "ui" will be the type of library for every dumb component.</p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721012647644/9a285be4-451e-4377-b731-1176cd78f037.png" alt class="image--center mx-auto" /></p>
<p>Directory : Pretty straightforward, I need to put my library in <code>shared/ui-components/button</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721012644915/33cf1921-fb88-4ec3-a5c9-dfb6406f6b47.png" alt class="image--center mx-auto" /></p>
<p>Tags: In a future article, you will see that tags are very important. The scope of my library is shared, and the type of my library is UI: <code>scope:shared,type:ui</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721012650139/25d44a96-8a39-48dd-af18-d3ba322636d6.png" alt class="image--center mx-auto" /></p>
<p>In your console you can see the command that will be launched when you are done. What you see is called a dry run. A "dry run" in NX allows you to simulate the effects of a command without making actual changes. This is done using the <code>--dry-run</code> (or <code>-d</code>) flag.</p>
<blockquote>
<p><code>nx g @nx/angular:library --name=ui --directory=shared/ui-components/button --projectNameAndRootFormat=derived --skipTests=true --tags=scope:shared,type:ui --no-interactive --dry-run</code></p>
</blockquote>
<p>Now you understand why it's easier to generate a library with NX Console!</p>
<p>You can also check the result in the console to make sure it's correct:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721081301617/c552bbad-bc71-405f-badf-7504a6ed55a8.png" alt class="image--center mx-auto" /></p>
<p>Then you can just run it :</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721082033390/4124548d-1585-4137-9b72-b98457fbdf3a.png" alt class="image--center mx-auto" /></p>
<p>Here you go! Your first library is generated. In the next article, I will explain module boundaries and how to use scope and types.</p>
<p>In the future I will explain how we can just infer the task and get rid of all these configuration files.</p>
<h2 id="heading-ressources">Ressources</h2>
<p>NX Console for your IDE : <a target="_blank" href="https://nx.dev/getting-started/editor-setup#official-integrations">https://nx.dev/getting-started/editor-setup#official-integrations</a><br />Project Crystal NX, Inferred Tasks : <a target="_blank" href="https://nx.dev/concepts/inferred-tasks">https://nx.dev/concepts/inferred-tasks</a><br />Module boundaries : <a target="_blank" href="https://nx.dev/features/enforce-module-boundaries">https://nx.dev/features/enforce-module-boundaries</a></p>
]]></content:encoded></item><item><title><![CDATA[NX Project structure]]></title><description><![CDATA[Hello friends 🚀! In the last article we saw how to create a monorepo with NX project : Getting started with NX & Angular



.github: This folder contains the configuration for GitHub Actions. We will cover how to use it in another article.
.nx: This...]]></description><link>https://gillesferrand.com/nx-project-structure</link><guid isPermaLink="true">https://gillesferrand.com/nx-project-structure</guid><category><![CDATA[Nx]]></category><category><![CDATA[nx-workspace]]></category><category><![CDATA[Angular]]></category><category><![CDATA[Jest]]></category><dc:creator><![CDATA[Gilles Ferrand]]></dc:creator><pubDate>Thu, 11 Jul 2024 23:27:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1720660841296/fadaa969-e43d-49a2-b024-79ebece15d98.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello friends 🚀! In the last article we saw how to create a monorepo with NX project : <a target="_blank" href="https://gillesferrand.com/getting-started-with-nx-angular">Getting started with NX &amp; Angular</a></p>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720570552994/adadd160-98b3-4140-a107-35a54e2f8250.png" alt class="image--center mx-auto" /></p>
</blockquote>
<p><code>.github</code>: This folder contains the configuration for <a target="_blank" href="https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions">GitHub Actions</a>. We will cover how to use it in another article.</p>
<p><code>.nx</code>: This hidden folder stores various configuration and cache files used by the NX tool.</p>
<ol>
<li><p><strong>Cache Files</strong>: These files store the results of previous builds, linting, and testing tasks. NX uses these cache files to speed up future runs of the same tasks, making the build process more efficient.</p>
</li>
<li><p><strong>Temporary Files</strong>: NX may use this directory to store temporary files needed during the execution of various tasks.</p>
</li>
<li><p><strong>Configuration Files</strong>: Some settings specific to NX are stored here. These settings can include task runner configurations, workspace configurations, and other metadata.</p>
</li>
</ol>
<p>The <code>.nx</code> folder is crucial for NX's ability to optimize and manage builds and other tasks in a monorepo setup. It ensures that tasks are executed efficiently by using caching and incremental builds. I will explain more about this in details soon.</p>
<p><code>apps</code>: This folder is important as it contains all your applications. In my project, you can see two apps: one for the Angular app and one for the E2E tests. However, you can have many others here, including Angular, React, Nest, Node apps...</p>
<p>But here's the trick: we won't code much in the <code>apps</code> folder because, with NX, you will think like a library creator.</p>
<p><code>.eslintrc.json</code>: NX enhances ESLint by adding smart features that make linting faster and more efficient in a monorepo setup</p>
<ol>
<li><p><strong>Unified Configuration</strong>: NX helps you manage a single set of linting rules that can be shared across all projects in your monorepo, ensuring consistency.</p>
</li>
<li><p><strong>Faster Linting with Caching</strong>: NX uses caching to remember which files have been linted before, so it only checks the files that have changed, speeding up the process.</p>
</li>
<li><p><strong>Linting Only What Matters</strong>: Instead of running ESLint on the entire codebase, NX allows you to lint only the projects that were affected by recent changes, saving time and money.</p>
</li>
</ol>
<p>In essence, NX makes ESLint smarter and faster, helping maintain code quality efficiently in large monorepos.</p>
<p><code>jest.config.ts &amp; jest.preset.js</code>: NX comes with Jest automatically integrated, making it easy to set up and run tests in your projects. Jest is a popular testing framework, and NX ensures that it’s seamlessly incorporated into your development workflow.</p>
<p>NX’s integration with Jest simplifies the testing process, providing a ready-to-use setup and powerful customization options. By automating the configuration and offering easy commands to run tests, NX helps you maintain high code quality with minimal effort. Whether you’re working on a single project or managing a complex monorepo, NX and Jest together make testing straightforward and efficient.</p>
<p><code>nx.json</code>: This file is structured to provide detailed configuration for various aspects of your workspace/monorepo, such as:</p>
<ul>
<li><p><strong>Named Inputs</strong>: Defines sets of files that influence the caching mechanism. You can specify which files should be considered when determining whether to re-execute tasks like builds or tests, allowing for both default and environment-specific configurations.</p>
</li>
<li><p><strong>Target Defaults</strong>: Configures default behaviors for specific tasks (referred to as targets). This includes settings like caching, dependency rules (<code>dependsOn</code>), and specific inputs required for the task execution. It allows for optimizing performance and ensuring consistency across environments.</p>
</li>
<li><p><strong>Plugins</strong>: Defines configurations for plugins used within the NX workspace, such as Cypress or ESLint. This section details how these tools should interact with your projects, including target names and specific execution options.</p>
</li>
<li><p><strong>Generators</strong>: Specifies default configurations for generating assets, such as applications or libraries, using tools like Angular CLI or NX's own schematics. Settings can include which test runner or linter to use, what style format to apply, and other project-specific defaults.</p>
</li>
<li><p><strong>Access Tokens</strong>: In cases where NX Cloud is used, this field might contain access tokens to authenticate and connect your local development environment with NX Cloud.</p>
</li>
</ul>
<p><code>package.json</code>: I understand, you already know what is a <code>package.json</code> file, but here is a twist, in a monorepo you should find only one package.json that define dependencies</p>
<p>Using a single <code>package.json</code> in an NX monorepo offers several advantages:</p>
<ol>
<li><p><strong>Consistency</strong>: Ensures all projects use the same versions of dependencies, avoiding conflicts.</p>
</li>
<li><p><strong>Simplified Management</strong>: One place to manage updates and audits, making maintenance easier.</p>
</li>
<li><p><strong>Efficient Installation</strong>: Single installation step for all projects speeds up setups and CI pipelines.</p>
</li>
<li><p><strong>Resource Savings</strong>: Reduces disk space by avoiding duplicate package installations.</p>
</li>
<li><p><strong>Tooling Efficiency</strong>: Centralizes tools and scripts, improving build and automation processes.</p>
</li>
<li><p><strong>Easier Collaboration</strong>: Simplifies onboarding and collaboration by standardizing the development environment across projects.</p>
</li>
</ol>
<p>These benefits make a single <code>package.json</code> essential for scalable and efficient development in NX monorepos.</p>
<p><code>tsconfig.base.json</code>: If you are familiar with Typescript you already know, this is a centralized configuration of TypeScript on your monorepo, all the others projects can inherit of this base.</p>
<p>Understanding the structure of an NX project is essential for efficiently managing a monorepo. By leveraging the various folders and configuration files, you can optimize your workflow, ensure consistency, and maintain high code quality. NX's powerful features, including caching, incremental builds, and integrated tools like ESLint and Jest, make it a robust solution for modern development needs.</p>
<p>In the next article, we will create our first library, and more importantly, I will introduce module boundaries.</p>
<h2 id="heading-ressources"><strong>Ressources</strong></h2>
<p><a target="_blank" href="https://nx.dev/"><strong>https://nx.dev/</strong></a></p>
]]></content:encoded></item><item><title><![CDATA[Starting with NX and Angular: A Beginner's Tutorial]]></title><description><![CDATA[Hello friends 🚀! In this article, I'll walk you through the steps to install NX and Angular.
But what is NX ?

I discovered NX in 2019, I used it to manage several Angular apps for a big french bank, and I still use it in my day to day job. I love t...]]></description><link>https://gillesferrand.com/starting-with-nx-and-angular-a-beginners-tutorial</link><guid isPermaLink="true">https://gillesferrand.com/starting-with-nx-and-angular-a-beginners-tutorial</guid><category><![CDATA[Nx]]></category><category><![CDATA[Angular]]></category><dc:creator><![CDATA[Gilles Ferrand]]></dc:creator><pubDate>Tue, 09 Jul 2024 23:00:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1720531193886/2d30dbc0-92e6-4147-a0f9-67feb152586d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello friends 🚀! In this article, I'll walk you through the steps to install NX and Angular.</p>
<h2 id="heading-but-what-is-nxhttpsnxdev">But what is <a target="_blank" href="https://nx.dev/">NX</a> ?</h2>
<p><img src="https://seeklogo.com/images/N/nx-logo-8EB5A23B44-seeklogo.com.png" alt="Nx Logo PNG Vector (SVG) Free Download" /></p>
<p>I discovered NX in 2019, I used it to manage several Angular apps for a big french bank, and I still use it in my day to day job. I love this tool and it completly changed my way of coding.</p>
<p>NX is a smart, extensible build framework for monorepos but you can use it outside a monorepo too, it helps developers manage and scale multiple projects with ease.</p>
<p>Developed by Nrwl, NX supports modern front-end frameworks like Angular, React, and others, providing powerful tools for code generation, testing, and optimization. It promotes best practices in software development, such as modularization, incremental builds, and a robust dependency graph, making it ideal for large-scale applications and teams.</p>
<h2 id="heading-installation">Installation</h2>
<h3 id="heading-basic-stuff">Basic stuff</h3>
<p>NX gives you a nice command</p>
<pre><code class="lang-bash">npx create-nx-workspace@latest
</code></pre>
<blockquote>
<p><strong>You can choose a workspace name</strong> : blog-monorepo in my example</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720478874093/e0cef20e-b0ca-41d9-af66-f693cbe2b1ba.png" alt class="image--center mx-auto" /></p>
<p><strong>This is not an application name</strong>; it's the name of your monorepo. It can be your organization name.</p>
<p><strong>You can choose your stack</strong> : Angular</p>
</blockquote>
<p>NX will configurate your favorite stack, of course if you need more you will be able to do so after the installation, it's very extensible</p>
<h3 id="heading-integrated-or-standalone">Integrated or standalone ?</h3>
<p>Earlier in the article, I mentioned that you can use NX with or without a monorepo.</p>
<blockquote>
<p>Here I want to show you how to work in a monorepo, but you can use NX for just one application</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720479076333/34b40beb-c286-4dc8-8901-581274d36b20.png" alt class="image--center mx-auto" /></p>
</blockquote>
<h3 id="heading-application">Application</h3>
<blockquote>
<p>You can choose your Angular app name</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720479297332/fa5b95fd-4f45-4039-9b12-f6f6a4e1a4ea.png" alt class="image--center mx-auto" /></p>
<p>You can choose your bundler : I will recommand esbuild, it's the new default of Angular since version 17</p>
</blockquote>
<h3 id="heading-other-stuff">Other stuff</h3>
<blockquote>
<p>You can also choose</p>
<ul>
<li><p>Default stylesheet format</p>
</li>
<li><p>If you will need SSR or not</p>
</li>
<li><p>Your E2E test runner</p>
</li>
<li><p>You can choose whether or not to use <a target="_blank" href="https://nx.app/">NX Cloud</a>. I will write articles about this tool</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720479465337/0f4099dd-1294-4314-85e3-b1d69e98fb06.png" alt class="image--center mx-auto" /></p>
</blockquote>
<h3 id="heading-boom-you-are-all-set">Boom 💥 you are all set</h3>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720479848358/71dc63b4-fb3b-4b55-bd59-d743c633df9c.png" alt class="image--center mx-auto" /></p>
</blockquote>
<p>That's it! Yes, I know, it's amazing.</p>
<p>NX set up everything for you, installed dependencies, and now you are ready to work!</p>
<p>In the next article, I will show you the project structure and explain the purpose of all the files.</p>
<h2 id="heading-ressources">Ressources</h2>
<p><a target="_blank" href="https://nx.dev/">https://nx.dev/</a></p>
]]></content:encoded></item><item><title><![CDATA[Install TailwindCSS in Angular]]></title><description><![CDATA[Today we will see how to install TailwindCSS in an Angular project
Create or use your Angular project
ng new project
cd project

**Install and configure TailwindCSS **
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init # Will genera...]]></description><link>https://gillesferrand.com/install-tailwindcss-in-angular</link><guid isPermaLink="true">https://gillesferrand.com/install-tailwindcss-in-angular</guid><category><![CDATA[Tailwind CSS]]></category><category><![CDATA[Angular]]></category><category><![CDATA[CSS]]></category><dc:creator><![CDATA[Gilles Ferrand]]></dc:creator><pubDate>Sat, 07 Jan 2023 15:28:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1720655192032/da1f2fa4-a035-4576-8d21-4b754e78afdd.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Today we will see how to install TailwindCSS in an Angular project</p>
<h2 id="heading-create-or-use-your-angular-project"><strong>Create or use your Angular project</strong></h2>
<pre><code class="lang-typescript">ng <span class="hljs-keyword">new</span> project
cd project
</code></pre>
<h2 id="heading-install-and-configure-tailwindcss">**Install and configure TailwindCSS **</h2>
<pre><code class="lang-typescript">npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init # Will generate a file tailwind.config.js
</code></pre>
<h2 id="heading-configure-the-paths-of-all-your-template-files"><strong>Configure the paths of all your template files</strong></h2>
<p>Edit your <em>tailwind.config.js</em> to add these lines :</p>
<pre><code class="lang-typescript"><span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  content: [
    <span class="hljs-string">"./src/**/*.{html,ts}"</span>,
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
</code></pre>
<h2 id="heading-add-tailwindcss-directives-to-your-css-file-stylecss"><strong>Add TailwindCSS directives to your CSS file <em>style.css</em></strong></h2>
<pre><code class="lang-typescript"><span class="hljs-meta">@tailwind</span> base;
<span class="hljs-meta">@tailwind</span> components;
<span class="hljs-meta">@tailwind</span> utilities;
</code></pre>
<p>**Enjoy using TailwindCSS ** <code>ng serve</code></p>
]]></content:encoded></item><item><title><![CDATA[How to install Jest in Angular 13]]></title><description><![CDATA[Jest
When you generate a new Angular project, it comes with some tools for unit testing, Karma and Jasmine
Sometimes you need to replace theses tools with another framework like Jest
What is Jest ?
Jest is a testing framework developed by Facebook, i...]]></description><link>https://gillesferrand.com/how-to-install-jest-in-angular-13</link><guid isPermaLink="true">https://gillesferrand.com/how-to-install-jest-in-angular-13</guid><category><![CDATA[Jest]]></category><category><![CDATA[Angular]]></category><category><![CDATA[Testing]]></category><dc:creator><![CDATA[Gilles Ferrand]]></dc:creator><pubDate>Sat, 07 Jan 2023 15:25:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1720655234834/39f20ac9-6c0a-4101-8193-549dbb52fde3.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-jest">Jest</h1>
<p>When you generate a new Angular project, it comes with some tools for unit testing, Karma and Jasmine</p>
<p>Sometimes you need to replace theses tools with another framework like Jest</p>
<h2 id="heading-what-is-jest">What is Jest ?</h2>
<p>Jest is a testing framework developed by Facebook, it is very popular for unit testing in React. It comes with a lot of tools :</p>
<ul>
<li><p>Mocking tools</p>
</li>
<li><p>Assertions tools</p>
</li>
<li><p>Code coverage</p>
</li>
<li><p>JSDOM library to allow Jest to run outside a browser, it is very useful to run test on CI</p>
</li>
<li><p>Watch mode to re-run only affected tests ...</p>
</li>
</ul>
<h2 id="heading-why-jest-instead-of-karma-and-jasmine">Why Jest instead of Karma and Jasmine</h2>
<p>We like to use Jest instead of Karma and Jasime because it can run without a browser, and it can run easily on CI. Also Jest is way faster than Karma, it's well documented, you can run only affected tests...</p>
<p>Jest can come with <code>@types/jest</code> package which contains type declaration, useful for type checking for example</p>
<h2 id="heading-jest-preset-angular">Jest Preset Angular</h2>
<p><a target="_blank" href="https://www.npmjs.com/package/jest-preset-angular"><code>jest-preset-angular</code></a> is Jest preset configuration and TypeScript preprocessor with source map support for Jest that lets you use Jest to test Angular projects.</p>
<h3 id="heading-installation">Installation</h3>
<p>To install jest-preset-angular and dependencies all at once you can use</p>
<p>with npm <code>npm install -D jest jest-preset-angular @types/jest</code> or with yarn <code>yarn add -D jest jest-preset-angular @types/jest</code></p>
<h3 id="heading-configuration">Configuration</h3>
<p>In your project root create a file <code>setup-jest.ts</code></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> <span class="hljs-string">'jest-preset-angular/setup-jest'</span>;
</code></pre>
<p>and a file <code>jest.config.js</code></p>
<pre><code class="lang-typescript"><span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  preset: <span class="hljs-string">'jest-preset-angular'</span>,
  setupFilesAfterEnv: [<span class="hljs-string">'&lt;rootDir&gt;/setup-jest.ts'</span>],
  globalSetup: <span class="hljs-string">'jest-preset-angular/global-setup'</span>,
};
</code></pre>
<p>Edit your <code>tsconfig.spec.json</code> like this <code>{ "extends": "./tsconfig.json", "compilerOptions": { "outDir": "./out-tsc/spec", "module": "CommonJs", "types": ["jest"] }, "include": ["src/**/*.spec.ts", "src/**/*.d.ts"] }</code> Edit your package.json <code>... "watch": "jest --watch", "test": "jest" ...</code></p>
<p>You can now run test with <code>npm run test</code></p>
<h3 id="heading-clean-up-karma-and-jasmine">Clean up Karma and Jasmine</h3>
<p>You can now remova Karma and Jasmine from your project</p>
<p>Delete <code>src/test.js</code></p>
<p>Delete in angular.json</p>
<pre><code class="lang-typescript">        <span class="hljs-string">"test"</span>: {
          ...
        }
</code></pre>
<p>Run in terminal this command to clean up all dependencies</p>
<pre><code class="lang-typescript">npm uninstall <span class="hljs-meta">@types</span>/jasmine jasmine-core karma karma-chrome-launcher karma-coverage karma-jasmine karma-jasmine-html-reporter
</code></pre>
<p>or</p>
<pre><code class="lang-typescript">yarn remove <span class="hljs-meta">@types</span>/jasmine jasmine-core karma karma-chrome-launcher karma-coverage karma-jasmine karma-jasmine-html-reporter
</code></pre>
<p>Sources :</p>
<p><a target="_blank" href="https://www.xfive.co/blog/testing-angular-faster-jest/">https://www.xfive.co/blog/testing-angular-faster-jest/</a></p>
<p><a target="_blank" href="https://thymikee.github.io/jest-preset-angular/docs/">https://thymikee.github.io/jest-preset-angular/docs/</a></p>
]]></content:encoded></item><item><title><![CDATA[undefined vs null in JavaScript]]></title><description><![CDATA[In last article I explained how to use variables in JavaScript but I also mentioned undefined, here I will try my best to explain to you what is undefined, what is the difference with null, why both are existing and I will give you some examples.
und...]]></description><link>https://gillesferrand.com/undefined-vs-null-in-javascript</link><guid isPermaLink="true">https://gillesferrand.com/undefined-vs-null-in-javascript</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[js]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[Gilles Ferrand]]></dc:creator><pubDate>Sun, 27 Sep 2020 11:49:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1720655340538/9ecead84-cff6-4e59-a527-0aad730ccd55.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In last article I explained how to use variables in JavaScript but I also mentioned undefined, here I will try my best to explain to you what is undefined, what is the difference with null, why both are existing and I will give you some examples.</p>
<h2 id="heading-undefined">undefined</h2>
<p>In JavaScript, undefined means a variable has been declared but has not yet been assigned a value or assigned undefined :</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// console.warn(notDeclared); // Impossible not defined</span>
<span class="hljs-built_in">console</span>.warn(<span class="hljs-keyword">typeof</span> notDeclared); <span class="hljs-comment">// logs : undefined</span>

<span class="hljs-keyword">let</span> test;
<span class="hljs-built_in">console</span>.warn(test); <span class="hljs-comment">// logs : undefined</span>
<span class="hljs-built_in">console</span>.warn(<span class="hljs-keyword">typeof</span> test); <span class="hljs-comment">// logs : undefined</span>

<span class="hljs-keyword">const</span> testConst = <span class="hljs-literal">undefined</span>;
<span class="hljs-built_in">console</span>.warn(testConst); <span class="hljs-comment">// logs : undefined</span>
<span class="hljs-built_in">console</span>.warn(<span class="hljs-keyword">typeof</span> testConst); <span class="hljs-comment">// logs : undefined</span>

<span class="hljs-comment">// Impossible, missing initializer in const declaration</span>
<span class="hljs-comment">/* const testConst2; 
console.warn(testConst2); // Broken code
console.warn(typeof testConst2); // Broken code */</span>
</code></pre>
<h2 id="heading-null">null</h2>
<p>Unlike undefined, null is an assignment value, null can be assigned to a variable as a representation of no value :</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> test = <span class="hljs-literal">null</span>;
<span class="hljs-built_in">console</span>.warn(test); <span class="hljs-comment">// logs : null</span>
<span class="hljs-built_in">console</span>.warn(<span class="hljs-keyword">typeof</span> test); <span class="hljs-comment">// logs : object</span>
</code></pre>
<p>As you can see undefined and null are very different undefined is a type itself, and null seems like an object but no it is in reality a primitive value</p>
<p>To understand why null is not an object I will quote a sentence from the book <em>Professional JavaScript for Web Developers</em> :* "You may wonder why the typeof operator returns 'object' for a value that is null. This was actually an error in the original JavaScript implementation that was then copied in ECMAScript. Today, it is rationalized that null is considered a placeholder for an object, even though, technically, it is a primitive value."*</p>
<h2 id="heading-more-examples">More examples</h2>
<p>Sometimes JavaScript is fun, or horrible depending on how you feel 🤒</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.warn(<span class="hljs-literal">null</span> === <span class="hljs-literal">undefined</span>); <span class="hljs-comment">// logs : false</span>
<span class="hljs-built_in">console</span>.warn(<span class="hljs-literal">null</span> == <span class="hljs-literal">undefined</span>); <span class="hljs-comment">// logs : true</span>
<span class="hljs-built_in">console</span>.warn(<span class="hljs-literal">null</span> === <span class="hljs-literal">null</span>); <span class="hljs-comment">// logs : true</span>

<span class="hljs-comment">// null = 'value'; // Impossible ReferenceError</span>
<span class="hljs-comment">// let undefined = 'value'; Impossible trick :</span>
<span class="hljs-comment">// Identifier 'undefined' has already been declared</span>

<span class="hljs-comment">// /!\ DON'T DO THIS /!\</span>
(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">var</span> <span class="hljs-literal">undefined</span> = <span class="hljs-string">'wtf'</span>;
  <span class="hljs-built_in">console</span>.warn(<span class="hljs-literal">undefined</span>, <span class="hljs-keyword">typeof</span> <span class="hljs-literal">undefined</span>); <span class="hljs-comment">// logs : wtf string</span>
})();

<span class="hljs-comment">// /!\ DON'T DO THIS /!\</span>
(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">undefined</span>) </span>{
  <span class="hljs-built_in">console</span>.warn(<span class="hljs-literal">undefined</span>, <span class="hljs-keyword">typeof</span> <span class="hljs-literal">undefined</span>); <span class="hljs-comment">// logs: wtf2 string</span>
})(<span class="hljs-string">'wtf2'</span>);
</code></pre>
<p>That's it for undefined and null !</p>
<p>🚀 In my next article you can learn how to use conditions in JavaScript 🚀</p>
]]></content:encoded></item><item><title><![CDATA[Variables in JavaScript]]></title><description><![CDATA[Variables
In JavaScript likes others languages we are using variables ! 😱
They are containers for storing data values, in this article I will just explain how to use them, because the entire subject is a little bit hard, and at the beginning you don...]]></description><link>https://gillesferrand.com/variables-in-javascript</link><guid isPermaLink="true">https://gillesferrand.com/variables-in-javascript</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[js]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Frontend Development]]></category><dc:creator><![CDATA[Gilles Ferrand]]></dc:creator><pubDate>Sat, 19 Sep 2020 18:39:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1720655456762/66558385-3ac8-4cbd-9f0a-785f47eab689.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-variables">Variables</h1>
<p>In JavaScript likes others languages we are using variables ! 😱</p>
<p>They are containers for storing data values, in this article I will just explain how to use them, because the entire subject is a little bit hard, and at the beginning you don't need to know everything to start using them.</p>
<h2 id="heading-examples">Examples</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1600540354966/QW6rhOoDP.png" alt="carbon (3).png" /></p>
<p>If you want to know the difference between let and var I can recommend this fantastic article by  <a target="_blank" href="https://twitter.com/flaviocopes">Flavio Copes</a> : <a target="_blank" href="https://flaviocopes.com/javascript-difference-let-var/">Click me</a> </p>
<p>In all cases you should try it ! It's very simple but it's a must in every language 🤘</p>
<p>🚀 In my next post you can learn what is undefined in JavaScript 🚀</p>
]]></content:encoded></item><item><title><![CDATA[Hello World in JS !]]></title><description><![CDATA[Hello World
As usual the first thing to do when you are beginning a new language : Hello World !
 Why Hello World ? 😉
In JS they are multiple different ways to do that :

Using alert box
Using the console
Modifying the DOM
...

I coded for you few e...]]></description><link>https://gillesferrand.com/hello-world-in-js</link><guid isPermaLink="true">https://gillesferrand.com/hello-world-in-js</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[js]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[beginner]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Gilles Ferrand]]></dc:creator><pubDate>Fri, 18 Sep 2020 18:02:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1720655477882/926781b9-03c1-451b-a936-bc05b1382b5a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1600450814535/AtBY_2Yt6.png" alt="image.png" /></p>
<h1 id="heading-hello-world">Hello World</h1>
<p>As usual the first thing to do when you are beginning a new language : Hello World !</p>
<p> <a target="_blank" href="https://en.wikipedia.org/wiki/%22Hello,_World!%22_program">Why Hello World ?</a> 😉</p>
<p>In JS they are multiple different ways to do that :</p>
<ul>
<li>Using alert box</li>
<li>Using the console</li>
<li>Modifying the DOM
...</li>
</ul>
<p>I coded for you few examples, feel free to do the same thing on your computer, you just need a text editor and a web browser to open your HTML file 👊</p>
<h2 id="heading-code">Code</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1600451064429/plcC5Hzw3.png" alt="html.png" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1600451066797/8-f9lEaMm.png" alt="js.png" /></p>
<h2 id="heading-explanations">Explanations</h2>
<p>alert() method will open an alert box when the page is loaded containing the string that you passed in</p>
<p>console.log() method is logging your string as a message in the console</p>
<p>console.warn() method is logging your string as a warning in the console</p>
<p>document.querySelector("#id") is returning the DOM element with ID, and textContent will help to add text to this element </p>
<p>🚀 In my next post you can see how to declare variables in JS 🚀</p>
]]></content:encoded></item><item><title><![CDATA[What is JavaScript ?]]></title><description><![CDATA[JavaScript
JavaScript or JS is now considered as a high-level programming language and it's currently one of the most popular language in use, it was originally developed as a scripting language by Netscape to make websites more dynamic.
Possibilitie...]]></description><link>https://gillesferrand.com/what-is-javascript</link><guid isPermaLink="true">https://gillesferrand.com/what-is-javascript</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[beginner]]></category><category><![CDATA[js]]></category><dc:creator><![CDATA[Gilles Ferrand]]></dc:creator><pubDate>Thu, 17 Sep 2020 18:21:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1720655553807/bd55ce0c-407e-488a-a0a8-8f18f1a43dc6.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1600366015468/dwbBWFPln.png" alt="rsz_1024px-unofficial_javascript_logo_2svg.png" /></p>
<h1 id="heading-javascript">JavaScript</h1>
<p>JavaScript or JS is now considered as a high-level programming language and it's currently one of the most popular language in use, it was originally developed as a scripting language by Netscape to make websites more dynamic.</p>
<h2 id="heading-possibilities-of-javascript">Possibilities of JavaScript</h2>
<ul>
<li>Literally everything 😱
...</li>
<li>Change DOM (Document Object Model)</li>
<li>Add CSS dynamically</li>
<li>Track users move on your website</li>
<li>Validate inputs in HTML form</li>
<li>Use AJAX to load data without refreshing page</li>
<li>Create re-usable components</li>
<li>HTTP Request to your back-end</li>
<li>Unit testing</li>
<li>End-to-end testing</li>
<li>Create your back-end</li>
<li>Create animations</li>
<li>Create PWA (Progressive Web Apps)</li>
<li>Create Mobile Apps</li>
<li>Create games</li>
<li>Create software (VS Code)
...</li>
</ul>
<p>It's impossible to cite everything, JavaScript is just too big 💪</p>
<p>That's why JS is fascinating, and that's why you should learn it ! In the beginning It may seem a little bit difficult compared to others languages, but practice makes perfect !</p>
<p>🚀 In my next post you can see some example of JS 🚀</p>
<h2 id="heading-ressources">Ressources</h2>
<p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript">Mozilla Developer</a> </p>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/JavaScript">Wikipedia</a> </p>
<p><a target="_blank" href="https://www.w3schools.com/js/default.asp">W3Schools</a> </p>
]]></content:encoded></item></channel></rss>