<?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" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Rahul gupta - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Rahul gupta - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 24 May 2026 22:23:59 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/rahulgupta32/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How Microfrontends Work: From iframes to Module Federation ]]>
                </title>
                <description>
                    <![CDATA[ Microfrontends are transforming how teams build and deploy frontend applications at scale. This tutorial explores the architectural landscape, from traditional approaches to modern Module Federation implementations. By the end, you'll be equipped to ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-microfrontends-work-iframes-to-module-federation/</link>
                <guid isPermaLink="false">6839c4a906e067fe415d54b4</guid>
                
                    <category>
                        <![CDATA[ frontend ]]>
                    </category>
                
                    <category>
                        <![CDATA[ architecture ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Microfrontend ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Frontend Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Rahul gupta ]]>
                </dc:creator>
                <pubDate>Fri, 30 May 2025 14:46:01 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1748613557891/39037981-d514-4f26-8a48-be0cdd9ca29b.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Microfrontends are transforming how teams build and deploy frontend applications at scale. This tutorial explores the architectural landscape, from traditional approaches to modern Module Federation implementations.</p>
<p>By the end, you'll be equipped to evaluate whether microfrontends are the right solution for your team's specific needs.</p>
<h3 id="heading-ill-cover-the-following"><strong>I’ll cover the following:</strong></h3>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-are-microfrontends">What are Microfrontends?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-traditional-microfrontend-patterns">Traditional Microfrontend Patterns</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-server-side-composition">Server-Side Composition</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-iframes">iframes</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-build-time-integration-packages">Build Time Integration – Packages</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-modern-microfrontend-patterns">Modern Microfrontend Patterns</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-module-federation">Module Federation</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-single-spa">Single SPA</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-detailed-comparison">Detailed Comparison</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-tradeoffs-and-challenges-with-module-federation">Tradeoffs and Challenges with Module Federation</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-setup-complexity">Setup Complexity</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-runtime-challenges">Runtime Challenges</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-operational-concerns">Operational Concerns</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusions">Conclusions</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-whats-next">What’s next?</a></li>
</ul>
</li>
</ul>
<h2 id="heading-what-are-microfrontends">What are Microfrontends?</h2>
<p>If you've heard about microservices on the backend, microfrontends represent a similar approach in the frontend world, with many of the same benefits.</p>
<p>Your team might adopt a microfrontend approach to enable team autonomy, reduce deployment risks, and scale development across multiple teams. Each team owns its technology stack, deployment cadence, and workflows. Yet they still deliver a single, cohesive user interface.</p>
<p>The overall idea is to move away from a big monolithic UI to decoupled UI codebases that can be owned, managed, and deployed by separate teams independently.</p>
<p>The simplest way to think about Microfrontends is the following:</p>
<blockquote>
<p>Integrate one piece of UI into another</p>
</blockquote>
<p>What can this <strong>piece</strong> of UI be, you may ask? Here are some examples:</p>
<ul>
<li><p><strong>Pages</strong> – parts of a website owned by specific teams. For example, the Auth team may own login/signup pages, whereas the engagement team may own the marketing pages, and so on.</p>
</li>
<li><p><strong>Components</strong> – Components like header and footer are good candidates for a microfrontend approach as well. They’re relatively static but need to stay consistent across the website and may integrate with teams who own different sets of pages.</p>
</li>
<li><p><strong>Widgets</strong> – A recommendation widget may be owned by a recommendations team, for example, and it can be integrated into different parts of the page based on the context. This is different from a static component, as given the context, the recommendation widget may also fetch relevant data via APIs (also owned by the recommendations teams).</p>
</li>
</ul>
<h2 id="heading-traditional-microfrontend-patterns">Traditional Microfrontend Patterns</h2>
<p>After reading the definition of a microfrontend, you might be thinking, oh, wait, who builds UI with a big monolith these days anyway (except giants like Google)? If that’s the case, your team is most likely using one of these traditional approaches to building Microfrontends:</p>
<h3 id="heading-server-side-composition"><strong>Server-Side Composition</strong></h3>
<p>This is the most common approach I've encountered across various organisations. The idea is to split your website based on route patterns or pages. For example, you might route users to the accounts team for any routes starting with <code>/account/*</code> (<code>/account/login</code> or <code>/account/signup</code> may fall under this pattern). Or you may have a similar route prefix for other parts of your web app, like <code>/blog/*</code> for the marketing section of your app.</p>
<p>This is typically implemented at the reverse proxy layer (such as using NGINX), which routes traffic to the appropriate downstream UI service based on the path matching.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747496226912/fda979cd-c95c-4d48-a7dc-87956672b24d.png" alt="Diagram showing a reverse proxy setup with nginx. The proxy routes `/blog/*` requests to the Marketing UI and `/account/*` requests to the Accounts UI." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-iframes"><strong>iframes</strong></h3>
<p>Another common approach is using iframes, though this method has significant limitations.</p>
<p>Unlike server-side composition, which operates at the page level, iframes can integrate as widgets within pages. Using iframes, you can load another website as a part of the website you want to integrate it within using the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/iframe">&lt;iframe&gt;</a> tag.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747496936962/7c24a43a-80d4-45f4-a2df-3de0e0e0bc1c.png" alt="Diagram illustrating iframe integration, showing website.com/blog embedding a 'Widget' using an iframe with source 'website.com/widget'." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Some examples of this approach, which you may have seen, are websites that integrate Twitter feeds, Google Maps, and so on. Although these are examples of external widget integrations with iframes, companies may integrate certain widgets that are powered through iframes.</p>
<h3 id="heading-build-time-integration-packages"><strong>Build Time Integration – Packages</strong></h3>
<p>This approach involves publishing components as a UI library that other applications can integrate.</p>
<p>This is useful if you want to integrate full-blown apps with multiple pages, widgets, or static components like headers and footers, where this approach is pretty common.</p>
<p>Typically, this approach means that one team publishes their components as a package, while other teams integrate a specific version of this package.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747497485861/70385841-28c6-441e-ae4d-c977b3563ecf.png" alt="Diagram illustrating build-time integration via packages, showing website.com/blog integrating a 'Widget' component, version 1.0.0, fetched from a company's NPM registry." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>In this example, it’s important to note that the Widget component is pulled in during the dependency install phase of the app. The web app can utilise this widget like its own component, which gets built together as one module and shipped to the users.</p>
<h2 id="heading-modern-microfrontend-patterns">Modern Microfrontend Patterns</h2>
<h3 id="heading-module-federation">Module Federation</h3>
<p>Module Federation enables you to integrate remote UI pieces within a host application at runtime. These pieces can be full pages, widgets, or components.</p>
<p>Module Federation originated as a <a target="_blank" href="https://webpack.js.org/concepts/module-federation/">Webpack 5 feature</a>, extending the bundler's capabilities to load JavaScript code from remote sources at runtime.</p>
<p><a target="_blank" href="https://module-federation.io/">Module Federation 2.0</a> is the evolution/improvement of the original Webpack 5 feature, with implementations available for other popular bundlers like RSPack and Vite as well.</p>
<p>Even if you’re using Webpack 5, I would recommend using Module Federation 2.0 as it takes care of some common gotchas that exist in the original Webpack 5 implementation.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748011963774/fae404c6-efc9-4e0f-8667-4427dbcdfc0f.png" alt="Diagram illustrating Module Federation, showing a host application at website.com/blog loading a 'Widget' component at runtime from a remote application at Recommendation.com via 'remotes: recommendation/remoteEntry'." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Let’s take an example to understand some of the common pieces of Module Federation.</p>
<p>Imagine that we’ve a blog application, owned by the Content Team &amp; a Widget, which is owned by the Recommendations team.</p>
<p>Now, let’s say the content team wants to integrate a recommendation widget within their application. Assume these teams have separate codebases hosted on different domains. The content team is on <code>website.com</code> &amp; the recommendations team is on <code>recommendation.com</code></p>
<p>Here’s how you can achieve this MFE integration via Module Federation:</p>
<h4 id="heading-remote"><strong>Remote</strong></h4>
<p>Responsible for exposing JavaScript files as remote (for example, utilities, components, and so on).</p>
<p>In our example, it would be the Recommendation’s team acting as a remote &amp; would require a configuration to ‘expose’ the Widget.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">new</span> ModuleFederationPlugin({
  name: <span class="hljs-string">'recommendation'</span>,
  exposes: {
    <span class="hljs-string">'./Widget'</span>: <span class="hljs-string">'./src/Widget.js'</span>,
  }
})
</code></pre>
<h4 id="heading-remote-entry"><strong>Remote Entry</strong></h4>
<p>Remote entry is the URL for the entry point for a remote. A remote may expose multiple JavaScript files, &amp; remoteEntry file would be aware of all of them.</p>
<p>Module Federation by default hosts the remote entry file at the root. In our example, recommendation teams might host their remote entry on <code>https://recommendation.com/remoteEntry.js</code></p>
<h4 id="heading-host"><strong>Host</strong></h4>
<p>An independent website that consumes JavaScript from one or more remotes via <strong>Remote Entry.</strong> Think of remote entry as a namespace for your app under which it can export multiple things like components, utils, and so on, as exposed by a particular remote.</p>
<p>In our example, the Content Team would act as a Host &amp; they’ll define the recommendation team’s remote entry within remotes configuration.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">new</span> ModuleFederationPlugin({
  name: <span class="hljs-string">'content-blog'</span>,
  remotes: {
    <span class="hljs-string">"recommendation"</span>: <span class="hljs-string">'recommendation@https://recommendation.com/remoteEntry.js'</span>,
  },
  <span class="hljs-comment">// ... other configs</span>
})
</code></pre>
<h4 id="heading-shared"><strong>Shared</strong></h4>
<p>Both hosts and remote can specify dependencies as SemVer that are automatically negotiated and shared during runtime. These can include common framework dependencies, such as React, which may require being a singleton, or other vendor libraries that can be potentially shared.</p>
<p>Having the right shared configuration ensures that the client does not download libraries or code that is already available on the host when fetching UI pieces from a remote location, which is key for optimal performance when integrating Module Federation.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> deps = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./package.json"</span>).dependencies;

<span class="hljs-keyword">new</span> ModuleFederationPlugin({
  shared: {
    ...deps,
    react: {
      singleton: <span class="hljs-literal">true</span>,
      requiredVersion: deps.react,
    }
  },
  <span class="hljs-comment">// ... other configs</span>
})
</code></pre>
<h4 id="heading-imports-and-usage"><strong>Imports and Usage</strong></h4>
<p>Module Federation integration lets you use imports as if those JS files were available locally. Module Federation does all the stitching behind the scenes at runtime, in terms of fetching the remote entry and appropriate dependencies to make it available when you use it.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Import is of the format - &lt;remote&gt;/&lt;expose-from-remote&gt;</span>
<span class="hljs-keyword">import</span> Widget <span class="hljs-keyword">from</span> <span class="hljs-string">'recommendation/Widget'</span>;

<span class="hljs-comment">// Render somewhere, making sure to handle loading via Suspense</span>
<span class="hljs-comment">// &amp; errors via error boundary in React</span>
&lt;ErrorBoundary&gt;
  &lt;Suspense fallback={&lt;Loading /&gt;}
    &lt;Widget /&gt;
  &lt;/Suspense&gt;
&lt;/ErrorBoundary&gt;
</code></pre>
<p>In a nutshell, the module federation concept is this simple —</p>
<blockquote>
<p>Fetching JS code (components, utils, and so on) from a remote server at runtime and still being able to share dependencies and be performant while doing so.</p>
</blockquote>
<h3 id="heading-single-spa">Single SPA</h3>
<p>When you look up microfrontends, <a target="_blank" href="https://single-spa.js.org">Single SPA</a> often appears as a popular solution. But its primary use case is quite specific: integrating components across multiple frameworks (for example, React + Angular + Vue in the same application). Here's how it works in practice:</p>
<p>Single SPA acts as a JavaScript router that mounts and unmounts entire applications based on URL routes. Each "single-spa application" is a framework-specific app that gets loaded when its route becomes active.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Register applications with Single SPA</span>
registerApplication({
 name: <span class="hljs-string">'@mycompany/react-app'</span>,
 app: <span class="hljs-function">() =&gt;</span> System.import(<span class="hljs-string">'@mycompany/react-app'</span>),
 activeWhen: [<span class="hljs-string">'/react-app'</span>]
});

registerApplication({
 name: <span class="hljs-string">'@mycompany/angular-app'</span>, 
 app: <span class="hljs-function">() =&gt;</span> System.import(<span class="hljs-string">'@mycompany/angular-app'</span>),
 activeWhen: [<span class="hljs-string">'/angular-app'</span>]
});
</code></pre>
<p>Single SPA handles the "orchestration" part – deciding which app should be active and managing their lifecycles. It doesn't solve the "how do I load remote code" problem – you still need to pair it with one of the approaches we've discussed (Module Federation, build-time packages, and so on).</p>
<p>If your applications use the same framework (like all React), you can skip Single SPA entirely and use Module Federation directly. Single SPA adds complexity that's only justified when you truly need multi-framework integration.</p>
<h2 id="heading-detailed-comparison">Detailed Comparison</h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Criteria</strong></td><td><strong>Module Federation</strong></td><td><strong>Server-side composition</strong></td><td><strong>iframe</strong></td><td><strong>Build time integration (package)</strong></td></tr>
</thead>
<tbody>
<tr>
<td><strong>Independent deployments</strong></td><td>💚 Microfrontends are loaded at runtime on the client. This means that teams can do independent deployments and make changes that reflect immediately.</td><td>💚 Deployments stay independent, as each route pattern points to an individual app’s independent deployments</td><td>💚 Since iframes are also loaded at runtime, the deployments can be independent.</td><td>💔 Deployments are coupled from the host application. A change in the package would require publishing a new version and bumping it up in the host app.</td></tr>
<tr>
<td><strong>Performance</strong></td><td>💚 Enables shared dependencies and optimised loading, maintaining SPA performance.</td><td>💔 Requires full page reloads when navigating between applications, losing SPA benefits.</td><td>💔 Completely isolated and loads all the dependencies of the website in an iframe, which means a slower overall page load.</td><td>💚 Possible to share package dependencies to a certain extent by <a target="_blank" href="https://yarnpkg.com/cli/dedupe">deduping</a> dependencies when integrating a package, but it requires appropriate dev tooling. Otherwise, duplicate dependencies may sneak in for the same package.</td></tr>
<tr>
<td><strong>Scalability &amp; maintenance</strong></td><td>💚 Works well at scale. A page can be completely composed of federated components, with the smallest of the building blocks being pulled in from different remotes.</td><td>💔 Usually requires duplicating things like header/footer, to make it ‘look like’ the user is in the same app, but is being served by two different servers/codebases. The approach is limited to route-based segregation of apps’ entry points – so, a granular integration isn’t possible.</td><td>💔 Typically good to power whole pages and not portions of pages, can really slow down the app at scale and may encounter issues when optimising the app for SEO or building dynamic responsive layouts.</td><td>💔 Requires maintenance of package publishing, upgrades and version conflicts at scale. This can be simplified to some extent by CI tooling, but developers would still require significant effort in bumping the versions, verifying the impact from a feature/performance standpoint.</td></tr>
<tr>
<td><strong>Setup effort</strong></td><td>💔 Might be high depending on how your app is being built currently. A deeper level of understanding of your build tool may be required to make your desired integration work, or when you face issues. This is covered in detail in the next section.</td><td>💚 Simpler to implement, as there is no coupling apart from the reverse proxy layer, which is responsible for redirecting the traffic to the appropriate service.</td><td>💔 Easier to integrate but requires handling a lot of edge cases, which can take significant time. Some examples are communication between iframe/host app, layout issues, rendering beyond the boundaries of iframe (for example, toasts), cross-domain iframe restrictions and ensuring security, impact on SEO and a11y.</td><td>💔 Requires significant effort to stabilise the development pipeline for publishing a new package, maintaining a changeset, bumping a new version, and resolving version conflicts. Every change requires making sure there is no unintended impact on transitive dependencies of the host app due to the package bump.</td></tr>
<tr>
<td><strong>Authentication &amp; Authorisation</strong></td><td>💚 Depending on your app’s setup, module federated components can call the remote app’s server for any data fetching needs. Might require handling CORS if your remote is on a different domain than the host, and for the browser to send authentication cookies for such requests.</td><td>💚 Each app can independently integrate with a central authentication service.</td><td>💔 It can be challenging for iframes to access the parent website’s browser details like auth cookies, and so on. It also may require some trickery to get the authentication to work, especially if the iframe URL is on a different domain/subdomain than the application.</td><td>💚 Package components can choose to call APIs via a proxy API within the host application or directly integrate with an independent service’s endpoints.</td></tr>
<tr>
<td><strong>Devloop</strong></td><td>💚 Mature devloop with Module Federation 2.0, you can view source maps with hot reloading across these apps. Overall a seamless integration out of the box. You can also point to any federated endpoint from local to be able to integrate and verify end-to-end integration.</td><td>💔 Requires setting up both services and a reverse proxy locally to verify integration touchpoints, which may be non-trivial.</td><td>💔 Local testing doesn’t accurately mimic the issues that you may face due to cross-domain challenges with iframe.</td><td>💔 An appropriate dev workflow is required to test the in-development package changes within the host app locally. This is typically done with pre-publishing the package or by <a target="_blank" href="https://classic.yarnpkg.com/lang/en/docs/cli/link/">linking</a> local packages or using a tool like <a target="_blank" href="https://github.com/wclr/yalc">yalc</a>.</td></tr>
<tr>
<td><strong>Overall Recommendation ✨</strong></td><td>Suited for apps that are composed of integration with different teams who want to own their deployments and release cycles with low coupling.</td><td>Suited for apps that are rather isolated (subdomains) within a larger business domain. A question to ask is, how often would the user need to navigate between these apps? If the answer is ‘not often’, then this may be a suitable approach.</td><td>Not recommended due to the limitations that come with it. It may be suitable for some third-party integrations, for example, Twitter exposes a part of its feed which can be integrated within a website via iframe. This is rather more convenient than any of the other approaches.</td><td>Suited for apps where the changes need to be more controlled, with the host app upgrading the package, and may perform appropriate checks before releasing it to their end users.</td></tr>
</tbody>
</table>
</div><h2 id="heading-tradeoffs-and-challenges-with-module-federation">Tradeoffs and Challenges with Module Federation</h2>
<p>The primary tradeoff in using Module Federation is the initial setup effort, which I briefly discussed in the previous comparison table.</p>
<p>Here are some other challenges to anticipate when integrating via Module Federation:</p>
<h3 id="heading-setup-complexity"><strong>Setup Complexity</strong></h3>
<ol>
<li><p><strong>Bundler-specific challenges</strong> – Some things may require you to know your bundler's internals to make the integration work for your app. For example, with Webpack 5, if your remote not only exposes federated components but also serves a user experience, you’ll need the appropriate chunk setup to make that work. This is because Module Federation by default expects a certain chunk optimisation strategy and exposes the remoteEntry from the root of the app.</p>
</li>
<li><p><strong>Shared dependencies</strong> – You'll need to review your dependencies to make sure you share as many dependencies as possible to optimise bundle size and loading performance. You’ll also need to mark critical libraries (like React) as singletons to prevent runtime conflicts.</p>
</li>
</ol>
<h3 id="heading-runtime-challenges"><strong>Runtime Challenges</strong></h3>
<ol>
<li><p><strong>Cross domain</strong> – if your remote is on a different subdomain, for example <code>remote.website.com</code> and is being loaded from <code>host.website.com</code> You’ll need appropriate handling for CORS on your server to allow data fetching from the host’s subdomain. You’ll also need an appropriate <code>credentials</code> fetch configuration to make sure the browser sends the authentication cookies in data fetching requests to your remote endpoints.</p>
</li>
<li><p><strong>Styling conflicts</strong> – You’ll want to make sure the remote’s styles don’t override the host’s styles and that the remote components don’t inherit unintended styles from the host. There are multiple strategies here, from using styled components to a virtual DOM.</p>
</li>
</ol>
<h3 id="heading-operational-concerns"><strong>Operational Concerns</strong></h3>
<ol>
<li><p><strong>Observability and Analytics</strong> – Based on your requirements, you may want to either share an instance of your observability scripts, for example, an error monitoring service, or instantiate a completely different one within your MFE’s context. This becomes challenging, as there is no ‘index’ file being rendered, but rather components that are being exposed from the remotes.</p>
</li>
<li><p><strong>Deployment &amp; Caching</strong> – It’s recommended that MFE remote bundles be hosted on S3 buckets for high reliability as opposed to loading them from a remote server. You may require appropriate long-term caching for files other than the <code>remoteEntry.js</code> which is typically non-hashed and contains the link to other dependencies to be loaded.</p>
</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Microfrontends offer a compelling solution for scaling frontend development across multiple teams, with Module Federation emerging as the most flexible modern approach.</p>
<p>While traditional methods like server-side composition remain valuable for specific use cases, Module Federation provides the runtime flexibility and performance characteristics needed for complex applications.</p>
<p>The decision ultimately depends on your team’s structure, technical requirements, and tolerance for implementation complexity. Start with simpler approaches if you're new to microfrontends, then consider Module Federation as your needs evolve.</p>
<h3 id="heading-whats-next">What’s next?</h3>
<p>This article was more about giving you a bird’s-eye view of the landscape. I’ll be writing more on Module Federation and going beyond the basics next. I’ll cover the technical challenges in more detail, along with possible solutions. Watch out for the same!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn JavaScript Reactivity: How to Build Signals from Scratch ]]>
                </title>
                <description>
                    <![CDATA[ If you're learning JavaScript, you may have heard the terms reactivity or signals. But perhaps you haven't gotten to use them in practice yet. If so – or if you just want to learn more about these concepts – you're in the right place. In this article... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-javascript-reactivity-build-signals-from-scratch/</link>
                <guid isPermaLink="false">66b90800e8c4e204927a90f8</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Rahul gupta ]]>
                </dc:creator>
                <pubDate>Thu, 18 Jul 2024 21:17:44 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1727437093214/d99314da-415e-4a4b-8d7e-f00aaf3db9a8.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you're learning JavaScript, you may have heard the terms reactivity or signals. But perhaps you haven't gotten to use them in practice yet. If so – or if you just want to learn more about these concepts – you're in the right place.</p>
<p>In this article, you'll learn what reactivity means, what signals are, and then you'll build your own implementation of Signals from scratch.</p>
<h2 id="heading-what-well-cover">What We'll Cover</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-reactivity">What is Reactivity?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-are-signals">What are Signals?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-your-own-signals">How to Build Your Own Signals</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-what-is-reactivity">What is Reactivity?</h2>
<p>Here's a generic definition for reactivity:</p>
<blockquote>
<p>"Reactivity is the way a system reacts to data changes."</p>
</blockquote>
<p>At it's heart, reactivity in UI applications refers to changes in the UI in response to changes in the data.</p>
<p>Having an understanding of how Reactivity works behind the scenes gives you a deeper understanding of some of the common paradigms that you already use when developing web applications. But it also helps deepen your understanding of the frameworks / libraries you work with on a daily basis that use Reactivity under the hood.</p>
<p>Here are some common paradigms where reactivity comes into play behind the scenes, along with some examples:</p>
<ul>
<li><p><strong>React to data fetched from an API</strong>: Show loading / error / success indicators based on the state of data being fetched.</p>
</li>
<li><p><strong>Single data, multiple Reactive UI elements:</strong> In an ecommerce website, when an item is added to a cart, it should be marked as added and the cart badge's count should also increment.</p>
</li>
<li><p><strong>React to a task being completed</strong>: Show a checkmark when a user is done uploading an image.</p>
</li>
<li><p><strong>React to events</strong>: Show a promotional banner when a user is at the bottom of the page.</p>
</li>
<li><p><strong>Reactivity in CSS</strong>: Recalculate the spacing based on the height of the component via <code>calc(--height)</code>.</p>
</li>
</ul>
<p>Here are some of the popular frameworks / libraries and how they depend on Reactivity at their core:</p>
<p><strong>React</strong> let's you save data in form of state via hooks like <code>useState</code> , anytime this state changes, the corresponding UI element where the state is used is also updated reactively.</p>
<p>Under the hood, React achieves this by re-constructing and comparing the Virtual DOM when some state updates so that it only updates the relevant part of the UI element on the screen.</p>
<p><strong>RxJS</strong> uses observables to produce data and observers to consume that data, notifying them whenever new values are produced. You can <a target="_blank" href="https://rxjs.dev/guide/observable">read more about this here.</a></p>
<p><strong>Vue</strong> uses objects and <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy">proxies</a> to provide reactivity via <code>ref()</code>. Proxy, in a nutshell, lets Vue intercept when an object's property is accessed or set, which is the basis of its reactivity system. <a target="_blank" href="https://vuejs.org/guide/extras/reactivity-in-depth.html">You can read more here</a>.</p>
<p><strong>SolidJS</strong> uses <em>Signals</em> to achieve fine-grained reactivity. This means that it can update specific parts of the DOM when data changes, without the need of a virtual DOM.</p>
<h2 id="heading-what-are-signals">What are Signals?</h2>
<p>Signals are an important concept in Reactivity within JavaScript. Signals can hold a value and then allow a piece of code to react to it when this value changes.</p>
<p>Signals allow you to manage the state in a more controlled manner. They also allow fine-grained reactivity where components can update selectively based on the specific state changes, rather than re-rendering entirely.</p>
<p>Different frameworks have their own implementations of Signals like I mentioned earlier (for example, Vue calls them <code>ref</code>, while <a target="_blank" href="https://angular.io/guide/signals">Angular</a>, <a target="_blank" href="https://preactjs.com/guide/v10/signals/">Preact</a>, <a target="_blank" href="https://qwik.builder.io/docs/components/state/#usesignal">Qwik</a> call them signals) and they differ slightly in their implementations.</p>
<p>In this article, we'll try to rebuild signals from scratch as they exist within the <a target="_blank" href="https://docs.solidjs.com/concepts/signals">SolidJS</a> framework.</p>
<h3 id="heading-signals-in-solidjs">Signals in SolidJS</h3>
<p>Let's start by understanding how signals work in SolidJS. Then we'll be recreating the same with just JavaScript.</p>
<p><code>**createSignal**</code> is used to create a signal, takes <code>initialValue</code> as an argument, and returns a pair of <code>getter</code>s and <code>setter</code>s. Here's what this looks like:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [count, setCount] = createSignal(<span class="hljs-number">0</span>);
        ^ Getter   ^ Setter
</code></pre>
<p>Here:</p>
<ul>
<li><p><code>count()</code> is used to access the value in the signal</p>
</li>
<li><p><code>setCount(newValue)</code> is used to set a new value in the signal</p>
</li>
</ul>
<p>The <code>**createEffect**</code> function allows arbitrary code ("side effects") to be reactive and re-run whenever its dependencies change. It accepts a callback function and re-executes this function whenever any signal dependencies accessed within the callback change.</p>
<p>Unlike <a target="_blank" href="https://react.dev/reference/react/useEffect#useeffect">effects in React</a>, there is no need to explicitly list dependencies in an array. <strong>createEffect</strong> automatically determines signal dependencies by tracking which signal getters are accessed within the callback.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [count, setCount] = createSignal(<span class="hljs-number">0</span>);

<span class="hljs-comment">// Runs once with value at this point in time</span>
<span class="hljs-comment">// Print 0</span>
<span class="hljs-built_in">console</span>.log(count());

createEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// Prints 0</span>
    <span class="hljs-comment">// Prints 1</span>
    <span class="hljs-built_in">console</span>.log(count());
});


<span class="hljs-comment">// Updates the count to 1</span>
setCount(<span class="hljs-number">1</span>);
</code></pre>
<p>In the above example, the first <code>console.log</code> is printed only once, as SolidJS runs everything just once, whereas the callback within the effect runs every time the "count" signal's value is changed.</p>
<h2 id="heading-how-to-build-your-own-signals">How to Build Your Own Signals</h2>
<p>Let's try to re-build a simpler implementation of the above demonstrated SolidJS Signals by breaking it down:</p>
<ul>
<li><p><strong>Implement</strong> <code>Signal</code> Class – which manages handling of a Pub-Sub mechanism to power <code>createSignal</code></p>
</li>
<li><p><strong>Implement</strong> <code>**createSignal**</code> – uses the Signal class to implement this function, which should accept an initial value &amp; returns getter &amp; setters.</p>
</li>
<li><p><strong>Implement</strong> <code>createEffect</code> – runs the callback provided to it once, and re-runs it when a signal value changes</p>
</li>
</ul>
<h3 id="heading-implement-the-signal-class">Implement the <code>Signal</code> class</h3>
<p>This class will use the Pub-Sub pattern, which means it should:</p>
<ul>
<li><p>Maintain a value and provide a getter to access this value</p>
</li>
<li><p>Maintains a list of subscribers as an array and a method to subscribe</p>
</li>
<li><p>Provides a setter to set a new value and communicate the updated value to all subscribers</p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Signal</span> </span>{
  <span class="hljs-keyword">constructor</span>(value) {
    <span class="hljs-built_in">this</span>.value = value;
    <span class="hljs-built_in">this</span>.subscribers = [];
  }

  getValue() {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.value;
  }

  setValue(newValue) {
    <span class="hljs-built_in">this</span>.value = newValue;
    <span class="hljs-built_in">this</span>.emit();
  }

  emit() {
    <span class="hljs-built_in">this</span>.subscribers.forEach(<span class="hljs-function">(<span class="hljs-params">subscriber</span>) =&gt;</span> subscriber(<span class="hljs-built_in">this</span>.value));
  }

  subscribe(callback) {
    <span class="hljs-built_in">this</span>.subscribers.push(callback);
  }
}
</code></pre>
<p>A use case for the above may look like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> signal = <span class="hljs-keyword">new</span> Signal(<span class="hljs-number">0</span>);

<span class="hljs-comment">// Subscriber callback is re-run by the class when value changes</span>
signal.subscribe(<span class="hljs-function">(<span class="hljs-params">value</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(value));

<span class="hljs-comment">// There can be as many subscribers</span>
signa.subscribe(...);

<span class="hljs-comment">// Updates the value within the class</span>
<span class="hljs-comment">// Emits the value to all subscribers</span>
signal.setValue(<span class="hljs-number">1</span>);
</code></pre>
<p>The <code>subscribe</code> method pushes callback functions provided within an array of <code>subscribers</code> while <code>setValue</code> calls the <code>emit</code> method which loops through those subscribers and runs each subscriber callback with the <code>newValue</code>.</p>
<h3 id="heading-implement-the-createsignal-method">Implement the <code>createSignal</code> method</h3>
<p>Let's try to use the above to implement a <code>createSignal</code> method which should:</p>
<ul>
<li><p>Accept an initial value as an argument</p>
</li>
<li><p>Return an array of getter and setter methods</p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> createSignal = <span class="hljs-function">(<span class="hljs-params">value</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> signal = <span class="hljs-keyword">new</span> Signal(value);

  <span class="hljs-keyword">return</span> [
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">value</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">return</span> signal.getValue();
    },
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setValue</span>(<span class="hljs-params">newVal</span>) </span>{
      signal.setValue(newVal);
    },
  ];
};

<span class="hljs-keyword">const</span> [value, setValue] = createSignal(<span class="hljs-number">0</span>);

<span class="hljs-comment">// Logs 0</span>
<span class="hljs-built_in">console</span>.log(value());

setValue(<span class="hljs-number">1</span>);

<span class="hljs-comment">// Logs 1</span>
<span class="hljs-built_in">console</span>.log(value());
</code></pre>
<p>The above <code>createSignal</code> creates a new instance of the <code>Signal</code> class with the initial value provided to it.</p>
<p>It currently also returns a getter and setter which internally calls the respective getter and setter of the signal instance.</p>
<p>You'll notice that we're still writing <code>console.log(value())</code> twice manually when we want to access the latest <code>value()</code> as there are no subscriptions to the signal yet.</p>
<p>We'll achieve that with <code>createEffect</code>'s implementation next.</p>
<h3 id="heading-implement-createeffect">Implement <code>createEffect</code></h3>
<p>Our <code>createEffect</code> should:</p>
<ul>
<li><p>Receive a callback as an argument</p>
</li>
<li><p>Execute the callback once, immediately</p>
</li>
<li><p>Subscribe to the signals used within the callback</p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> createEffect = <span class="hljs-function">(<span class="hljs-params">callback</span>) =&gt;</span> {    
  <span class="hljs-comment">// Let's execute the callback</span>
  callback();

  <span class="hljs-comment">// Wait how do I subscribe?</span>
};
</code></pre>
<p>So you might be wondering: how can I possibly know whether this callback uses a signal getter or not?</p>
<p>Short answer is, you can't. As <code>createEffect</code> is a generic method, it can't possibly know what signals are being used within the callback passed to it. It can only execute this callback with different arguments at the very best.</p>
<p>If we think differently, there is still a way this function can <em>communicate</em> with the code within the callback (getter).</p>
<p>Let's introduce a new variable, <code>effectCallback</code>, which is an intermediate variable used to communicate between the effect and signal getter method. This variable should hold the callback that an effect receives.</p>
<p>An effect registers a callback subscription based on signal's <code>getter</code> that has been accessed within it.</p>
<p>Let's modify our <code>createSignal</code> code to handle that:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> createSignal = <span class="hljs-function">(<span class="hljs-params">value</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> signal = <span class="hljs-keyword">new</span> Signal(value);

  <span class="hljs-keyword">return</span> [
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">value</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-comment">// Subscribes the effectCallback if exists</span>
      <span class="hljs-keyword">if</span> (effectCallback) {
        signal.subscribe(effectCallback);
      }

      <span class="hljs-keyword">return</span> signal.getValue();
    },
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setValue</span>(<span class="hljs-params">newVal</span>) </span>{
      signal.setValue(newVal);
    },
  ];
};
</code></pre>
<p>Let's see when we can set the <code>effectCallback</code>. We know that <code>createEffect</code> should execute the callback immediately once, which means we can capture the callback in this variable before executing it and clear it up after it's done executing the callback.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> createEffect = <span class="hljs-function">(<span class="hljs-params">callback</span>) =&gt;</span> {
   effectCallback = callback;
   callback();
   effectCallback = <span class="hljs-literal">null</span>;
};
</code></pre>
<p>Putting everything together:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> effectCallback = <span class="hljs-literal">null</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> createEffect = <span class="hljs-function">(<span class="hljs-params">callback</span>) =&gt;</span> {
   effectCallback = callback;
   callback();
   effectCallback = <span class="hljs-literal">null</span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> createSignal = <span class="hljs-function">(<span class="hljs-params">value</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> signal = <span class="hljs-keyword">new</span> Signal(value);

  <span class="hljs-keyword">return</span> [
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">value</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">if</span> (effectCallback) {
        signal.subscribe(effectCallback);
      }

      <span class="hljs-keyword">return</span> signal.getValue();
    },
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setValue</span>(<span class="hljs-params">newVal</span>) </span>{
      signal.setValue(newVal);
    },
  ];
};
</code></pre>
<p>Here is a <a target="_blank" href="https://codesandbox.io/p/sandbox/solidjs-reactivity-diy-f5zh8x?file=%2Fsrc%2Fsignal.js%3A35%2C26-35%2C40&amp;layout=%257B%2522sidebarPanel%2522%253A%2522EXPLORER%2522%252C%2522rootPanelGroup%2522%253A%257B%2522direction%2522%253A%2522horizontal%2522%252C%2522contentType%2522%253A%2522UNKNOWN%2522%252C%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522id%2522%253A%2522ROOT_LAYOUT%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522UNKNOWN%2522%252C%2522direction%2522%253A%2522vertical%2522%252C%2522id%2522%253A%2522clyac8qxx00063b6kcdj0r3jb%2522%252C%2522sizes%2522%253A%255B100%252C0%255D%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522EDITOR%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522EDITOR%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522EDITOR%2522%252C%2522id%2522%253A%2522clyac8qxx00023b6kg4nyqgiz%2522%257D%255D%257D%252C%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522SHELLS%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522SHELLS%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522SHELLS%2522%252C%2522id%2522%253A%2522clyac8qxx00033b6krfbo5b6p%2522%257D%255D%252C%2522sizes%2522%253A%255B100%255D%257D%255D%257D%252C%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522DEVTOOLS%2522%252C%2522direction%2522%253A%2522vertical%2522%252C%2522id%2522%253A%2522DEVTOOLS%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522DEVTOOLS%2522%252C%2522id%2522%253A%2522clyac8qxx00053b6kv5v81n4d%2522%257D%255D%252C%2522sizes%2522%253A%255B100%255D%257D%255D%252C%2522sizes%2522%253A%255B50%252C50%255D%257D%252C%2522tabbedPanels%2522%253A%257B%2522clyac8qxx00023b6kg4nyqgiz%2522%253A%257B%2522tabs%2522%253A%255B%257B%2522id%2522%253A%2522clyac8qxx00013b6kq57p479j%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522type%2522%253A%2522FILE%2522%252C%2522filepath%2522%253A%2522%252Fsrc%252Findex.js%2522%252C%2522state%2522%253A%2522IDLE%2522%257D%252C%257B%2522id%2522%253A%2522clyagpsv900023b6jketxf2fz%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522type%2522%253A%2522FILE%2522%252C%2522initialSelections%2522%253A%255B%257B%2522startLineNumber%2522%253A35%252C%2522startColumn%2522%253A26%252C%2522endLineNumber%2522%253A35%252C%2522endColumn%2522%253A40%257D%255D%252C%2522filepath%2522%253A%2522%252Fsrc%252Fsignal.js%2522%252C%2522state%2522%253A%2522IDLE%2522%257D%255D%252C%2522id%2522%253A%2522clyac8qxx00023b6kg4nyqgiz%2522%252C%2522activeTabId%2522%253A%2522clyagpsv900023b6jketxf2fz%2522%257D%252C%2522clyac8qxx00053b6kv5v81n4d%2522%253A%257B%2522tabs%2522%253A%255B%257B%2522id%2522%253A%2522clyac8qxx00043b6k34nafcmv%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522type%2522%253A%2522UNASSIGNED_PORT%2522%252C%2522port%2522%253A0%252C%2522path%2522%253A%2522%252F%2522%257D%255D%252C%2522id%2522%253A%2522clyac8qxx00053b6kv5v81n4d%2522%252C%2522activeTabId%2522%253A%2522clyac8qxx00043b6k34nafcmv%2522%257D%252C%2522clyac8qxx00033b6krfbo5b6p%2522%253A%257B%2522tabs%2522%253A%255B%255D%252C%2522id%2522%253A%2522clyac8qxx00033b6krfbo5b6p%2522%257D%257D%252C%2522showDevtools%2522%253Atrue%252C%2522showShells%2522%253Afalse%252C%2522showSidebar%2522%253Atrue%252C%2522sidebarPanelSize%2522%253A18.53200883002208%257D">CodeSandbox</a> where you can play around with this code.</p>
<p>The order of execution would be something like this:</p>
<ul>
<li><p><code>createEffect</code> is executed with a callback function, and the same is stored within <code>effectCallback</code>.</p>
</li>
<li><p>The callback is executed and will invoke any getter signal methods used within it.</p>
</li>
<li><p>The getter method <code>value</code> within <code>createSignal</code> is executed and enters the conditional which checks whether the getter is accessed from within an effect callback.</p>
</li>
<li><p>The callback is subscribed for any further value changes and re-executes when setter is called.</p>
</li>
</ul>
<p>Here's something to help you visualise this process:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/image-38.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Diagram illustrating order of execution of the final solution</em></p>
<p>This was of course a rudimentary implementation of the concept.</p>
<p>SolidJS does a lot of things under the hood which can include:</p>
<ul>
<li><p>Optimisations: a signal will maintain its observers until they're manually disposed. This can become complex in web apps where nesting is common.</p>
</li>
<li><p>Allowing a way to batch updates</p>
</li>
<li><p>Supporting async subscribers</p>
</li>
</ul>
<p>and much more.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, we explored the concept of reactivity and its role in web applications. We examined how various frameworks implement reactivity, with many using signals as a foundational mechanism.</p>
<p>By breaking down the SolidJS implementation of signals, we created our own version from scratch using the Pub-Sub pattern.</p>
<p>I hope this provided you with valuable insights into reactivity, signals, and enhanced your understanding of JavaScript.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How I Made VIM's Project-wide Search Seamless with ripgrep ]]>
                </title>
                <description>
                    <![CDATA[ Yes, I ditched grep & the_silver_searcher(ag) for ripgrep. Whether you're forced to use VIM at your workplace or you're a mad VIM fan like I am who obsesses about productivity, the project-wide keyword search is a basic requirement every developer ne... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-search-project-wide-vim-ripgrep-ack/</link>
                <guid isPermaLink="false">66b907fcff5ca4264bc37d19</guid>
                
                    <category>
                        <![CDATA[ Productivity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vim ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Rahul gupta ]]>
                </dc:creator>
                <pubDate>Mon, 08 Jun 2020 16:57:07 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/06/markus-winkler-afW1hht0NSs-unsplash--1-.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Yes, I ditched grep &amp; the_silver_searcher(ag) for ripgrep.</p>
<p>Whether you're forced to use VIM at your workplace or you're a mad VIM fan like I am who obsesses about productivity, the project-wide keyword search is a basic requirement every developer needs in their editor's arsenal. And we expect it to be blazing fast. ⚡️</p>
<p>I've been using VIM for about 3 years now. And coming from a <a target="_blank" href="https://www.sublimetext.com/">Sublime</a> background, the need for project-wide search was essential.</p>
<p><a target="_blank" href="https://github.com/BurntSushi/ripgrep">ripgrep</a> and <a target="_blank" href="https://github.com/mileszs/ack.vim">a</a>ck.vim were things I adopted early on after my unfulfilling experiences with grep and the_silver_searcher(ag). I haven't looked back since then.</p>
<p>This article is the result of experimenting with different search tools and incremental improvements I made over a period of time until it felt just right.</p>
<h2 id="heading-why-ackvim-amp-ripgrep">Why ack.vim &amp; ripgrep?</h2>
<ol>
<li><p><strong>Fast:</strong> I've worked on Symfony and JavaScript projects with thousands of files and it is just blazing fast. Here's a quick <a target="_blank" href="https://github.com/BurntSushi/ripgrep#quick-examples-comparing-tools">comparison</a> with other search tools.<br> My benchmark for speed is, "it should never feel slow". I noticed a tremendous improvement after I moved from grep, the_silver_searcher and ack.</p>
</li>
<li><p><strong>Quick navigation</strong>: ack.vim takes care of populating the Quickfix list, which lets you conveniently move through all those search results across different files.</p>
</li>
<li><p><strong>Sensible defaults:</strong> ripgrep by default considers gitignore and automatically skips hidden files/directories and binary files.</p>
</li>
</ol>
<h2 id="heading-overview">Overview</h2>
<p><strong>ack.vim</strong> is a VIM plugin that acts as a wrapper to search keywords and populate the Quickfix list for navigating the results.</p>
<p><strong>ripgrep (rg)</strong> is a command-line tool that ack.vim will internally use to perform the actual project-wide search.</p>
<h2 id="heading-steps">Steps</h2>
<h3 id="heading-step-1-install-ripgrep"><strong>Step 1</strong>: Install ripgrep</h3>
<p>If you prefer <a target="_blank" href="https://brew.sh/">Homebrew</a> like I do, run the following to install rg:</p>
<pre><code class="lang-bash">brew tap burntsushi/ripgrep https://github.com/BurntSushi/ripgrep.git
brew install burntsushi/ripgrep/ripgrep-bin
</code></pre>
<p>Here's an <a target="_blank" href="https://gist.github.com/PezCoder/72ba0f5eba3ca5dc7271bde1a1fcfe5e">automated script</a> which I use as part of my <a target="_blank" href="https://github.com/pezcoder/dotfiles">dotfiles</a>.</p>
<p>If you prefer any other mode of installation, refer to ripgrep's official <a target="_blank" href="https://github.com/BurntSushi/ripgrep#installation">installation</a> section.</p>
<h3 id="heading-step-2-install-ackvim"><strong>Step 2</strong>: Install ack.vim</h3>
<p>To install ack.vim using the <a target="_blank" href="https://github.com/junegunn/vim-plug">vim-plug</a> package manager, add the following in your vimrc:</p>
<pre><code class="lang-plaintext">Plug 'mileszs/ack.vim'
</code></pre>
<p>or refer to the ack.vim's <a target="_blank" href="https://github.com/mileszs/ack.vim#installation">installation</a> section.</p>
<h3 id="heading-step-3-configure-ackvim-to-use-rg"><strong>Step 3</strong>: Configure ack.vim to use rg</h3>
<p>Add the following configuration in your vimrc:</p>
<pre><code class="lang-plaintext">" ack.vim --- {{{

" Use ripgrep for searching ⚡️
" Options include:
" --vimgrep -&gt; Needed to parse the rg response properly for ack.vim
" --type-not sql -&gt; Avoid huge sql file dumps as it slows down the search
" --smart-case -&gt; Search case insensitive if all lowercase pattern, Search case sensitively otherwise
let g:ackprg = 'rg --vimgrep --type-not sql --smart-case'

" Auto close the Quickfix list after pressing '&lt;enter&gt;' on a list item
let g:ack_autoclose = 1

" Any empty ack search will search for the work the cursor is on
let g:ack_use_cword_for_empty_search = 1

" Don't jump to first match
cnoreabbrev Ack Ack!

" Maps &lt;leader&gt;/ so we're ready to type the search keyword
nnoremap &lt;Leader&gt;/ :Ack!&lt;Space&gt;
" }}}

" Navigate quickfix list with ease
nnoremap &lt;silent&gt; [q :cprevious&lt;CR&gt;
nnoremap &lt;silent&gt; ]q :cnext&lt;CR&gt;
</code></pre>
<p>Note: <code>let g:ackprg</code> defines the command which ack.vim will internally run.<br>Also note that we're using <code>rg</code> here with some options. Look at the <code>man rg</code> to modify the options that may meet your requirements.</p>
<p>To explore options for ack.vim, look into the following <a target="_blank" href="https://github.com/mileszs/ack.vim/blob/master/doc/ack.txt">documentation</a>.</p>
<h2 id="heading-usage">Usage</h2>
<p>Now that we're up and ready, here are the most common use-cases:</p>
<h3 id="heading-look-for-a-word-under-the-cursor">Look for a word under the cursor</h3>
<p><em>Press / followed by enter</em>.<br>Since we've set <code>let g:ack_use_cword_for_empty_search = 1</code>, Ack falls back to the current word under the cursor for the search, so no need to type that word.</p>
<h3 id="heading-word-search">Word search</h3>
<p><em>Press / followed by the word (without any quotes) &amp; enter.</em><br>Since we're using smart case with ripgrep, that'll do a case insensitive search if the word is all lowercase, and a case sensitive search otherwise.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/Screenshot-2020-06-04-at-3.33.02-AM-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>word search with ack.vim</em></p>
<h3 id="heading-regex-search">Regex search</h3>
<p><em>Press / followed by a regex pattern in quotes &amp; enter.</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/Screenshot-2020-06-04-at-3.38.21-AM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>regex search with ack.vim</em></p>
<h3 id="heading-navigation-through-the-results">Navigation through the results</h3>
<p>Ack.vim populates the results in the Quickfix list, which opens up as a separate bottom window. There are multiple ways to navigate the results list:</p>
<ul>
<li><p>You can navigate the Quickfix list using <code>j/k</code> and press <code>enter</code> to close the Quickfix list. VIM will take you to the exact location of the found word.</p>
</li>
<li><p>You can also use the hotkeys <code>]q</code> or <code>[q</code>. VIM will move the cursor to the next/previous result and will open the file in a new buffer if required.<br>  To close the Quickfix list once you're done, you can either go to the bottom Quickfix window and close it or just run <code>:cclose</code></p>
</li>
<li><p>To open the Quickfix list back up, run <code>:copen</code></p>
</li>
</ul>
<h2 id="heading-closing-note">Closing Note</h2>
<p>And there you have it, a seamless search and navigation for your next project-wide keyword search!</p>
<p>If you're stuck anywhere, look for the respective ack.vim and ripgrep docs/issues in their respective repositories, or send me a message. Share the configuration you're proud of, so it can help others improve theirs.</p>
<p>Here are my <a target="_blank" href="https://github.com/pezcoder/dotfiles">dotfiles</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
