<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Emmanuel Isenah </title>
    <description>The latest articles on DEV Community by Emmanuel Isenah  (@emmanuelisenah).</description>
    <link>https://dev.to/emmanuelisenah</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1083273%2F1722152e-9b38-4a04-98e3-8c7d18477013.jpg</url>
      <title>DEV Community: Emmanuel Isenah </title>
      <link>https://dev.to/emmanuelisenah</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/emmanuelisenah"/>
    <language>en</language>
    <item>
      <title>Password Composition Policies Are Bad and Here's Why</title>
      <dc:creator>Emmanuel Isenah </dc:creator>
      <pubDate>Mon, 23 Dec 2024 07:38:40 +0000</pubDate>
      <link>https://dev.to/emmanuelisenah/password-composition-policies-are-bad-and-heres-why-5d9p</link>
      <guid>https://dev.to/emmanuelisenah/password-composition-policies-are-bad-and-heres-why-5d9p</guid>
      <description>&lt;p&gt;Passwords are the most widely used form of authentication on the internet. And unless you're Nelson Dellisa-six-time USA Memory Champion-most of us tend to pick the easiest passwords we can remember when creating one.&lt;/p&gt;

&lt;p&gt;I must admit, I've never been a big fan of passwords, especially with the availability of more secure authentication options like OAuth, magic links, and passkeys. Passwords inherently carry more security risks compared to other alternatives and have to be paired with Multi-Factor Authentication (MFA) to be considered truly secure.&lt;/p&gt;

&lt;p&gt;Secure password generation is complicated by the tradeoff between developing passwords which are both easy to remember and difficult to crack. To help guard against the latter, password composition policies are enforced to coerce users to create secure passwords. However, they often fail to achieve their intended purpose.&lt;/p&gt;

&lt;p&gt;I'm sure you've experienced this before: you go to a website's sign-up page, and you're prompted to create a password with minimum 8 characters, 1 uppercase letter, 1 lowercase letter, 1 number, and 1 special character. Next thing you know, you find yourself substituting letters for special characters(e.g, &lt;code&gt;a&lt;/code&gt; with &lt;code&gt;@&lt;/code&gt;) and appending numbers to the end of your password. This can be really frustrating because your password may be secure already.&lt;/p&gt;

&lt;p&gt;Fortunately, in recent years, the rise of password managers has helped dampen this issue. We are now able to create long, random passwords for each site we visit and at the same store them securely. But password managers aren't widely adopted yet in the space, so the original issue still semi persists.&lt;/p&gt;

&lt;p&gt;This matter of subject is luckily very well researched and has been discussed by many security experts, with the most notable being the National Institute of Standards and Technology (NIST). They have published guidelines on digital identity management, which one of them talks about password composition policies called &lt;a href="https://pages.nist.gov/800-63-4/sp800-63b.html" rel="noopener noreferrer"&gt;SP 800-63B&lt;/a&gt;. Not gonna lie--It's a long read. But it's definitely worth it, as it gets updated regularly to keep up with latest findings.&lt;/p&gt;

&lt;p&gt;Also there's a &lt;a href="https://doi.org/10.1145/1866307.1866327" rel="noopener noreferrer"&gt;published paper by Florida State University&lt;/a&gt; on password creation policies where they test real leaked passwords from database breaches against composition policies to examine the result effect.&lt;/p&gt;

&lt;p&gt;I'll be referencing both of these in this article to better explain to you why password composition policies are bad and what better approaches we can take to encourage users to create secure passwords. It's also good note that I'll be focusing only in the application of online environments, not offline.&lt;/p&gt;

&lt;p&gt;Without no further ado, let's dive in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Composition Policies and Entropy
&lt;/h2&gt;

&lt;p&gt;Composition policies are rules that dictate what constitutes an acceptable password to the user before they can proceed to create it. These rules typically include requirements like a minimum length, a mix of uppercase and lowercase letters, numbers, and special characters. The goal is to make the password more secure by increasing the entropy (more on that later). For example, a policy might mandate users include at least one digit in their password.&lt;/p&gt;

&lt;p&gt;However, research consistently shows that users respond to these requirements in predictable ways when forced. In the &lt;a href="https://doi.org/10.1145/1866307.1866327" rel="noopener noreferrer"&gt;Florida State University research paper&lt;/a&gt;, after performing a dictionary attack on 14 million passwords from &lt;a href="https://en.wikipedia.org/wiki/RockYou" rel="noopener noreferrer"&gt;RockYou&lt;/a&gt; database breach, researchers found that users often appended a digit to the end of an otherwise weak password. This highlights how composition policies can fail to deliver their intended security benefits. Heres what they further had to say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"It shouldnt come as a surprise that most people simply add digits to the end of a base word when creating a password. If we filter the training list to only include passwords that also contained one non-digit, the number of users who appended a digit to the end of their password jumped to 77.46%."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can utilize &lt;a href="https://haveibeenpwned.com/API/v3" rel="noopener noreferrer"&gt;Have I Been Pwned&lt;/a&gt; API to confirm this yourself if in doubt.&lt;/p&gt;

&lt;p&gt;Another important observation is that the numbers users choose are often predictable too. What do I mean? According to the same &lt;a href="https://doi.org/10.1145/1866307.1866327" rel="noopener noreferrer"&gt;research paper&lt;/a&gt;, the digits &lt;strong&gt;1&lt;/strong&gt; through &lt;strong&gt;9&lt;/strong&gt; account for &lt;strong&gt;36.25%&lt;/strong&gt; of the top 10 most common digits used in passwords, with &lt;strong&gt;1&lt;/strong&gt; being the most frequent.&lt;/p&gt;

&lt;p&gt;The above pattern extends to uppercase letters and special characters as well. Over &lt;strong&gt;50%&lt;/strong&gt; of users capitalize the first letter of their password when required to include an uppercase character, while &lt;strong&gt;36.37%&lt;/strong&gt; append a special character to the end of their password.&lt;/p&gt;

&lt;p&gt;Interestingly, when composition policies require both a &lt;strong&gt;special character&lt;/strong&gt; and a &lt;strong&gt;digit&lt;/strong&gt; -a common requirement seen in most policiesit was found that special characters are more often followed by a digit rather than the other way around.&lt;/p&gt;

&lt;p&gt;All these significantly reduces the key-space of possible passwords, making them easier to guess. In the event of an attack, a malicious actor would be fully aware of these constraints and their predictable effects. They would leverage this knowledge to reduce the number of possible guesses needed to crack the password.&lt;/p&gt;

&lt;p&gt;Quoting NIST, here's what they have to say on composition policy:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Verifiers and CSPs SHALL NOT impose other composition rules (e.g., requiring mixtures of different character types) for passwords."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;Verifiers are entities that verify user credentials during the authentication process, while CSPs (Credential Service Provider) are the entities that manage and store the user's credentials.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It might not be obvious, but increasing the key-space (the total number of possible combinations for a password) through composition policies doesn't out right reduce the number of guesses needed to crack the password. Yes, youre correct-it increases the entropy. But higher entropy doesn't always equate to lower guessability. Why?&lt;/p&gt;

&lt;p&gt;Well &lt;a href="https://en.wikipedia.org/wiki/Entropy_(information_theory)" rel="noopener noreferrer"&gt;Shannon's entropy&lt;/a&gt; theoretically assumes outcomes are evenly distributed which isn't true for most real-world password distributions. For example, &lt;strong&gt;"123456"&lt;/strong&gt; is far more common to be found in human-choosen password than, say, &lt;strong&gt;"vH8$dq@"&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Shannon's Entropy is the measure of theoretical unpredictability of a password based on the possible combinations of characters.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So in essence, even if it's higher, it doesn't necessarily convey to us how secure the password is. It's like saying a password with 10 bits of entropy is more secure than a password with 8 bits of entropy--it's hard to tell without extra analysis.&lt;/p&gt;

&lt;p&gt;For example, &lt;strong&gt;"Abcdef123456@"&lt;/strong&gt; has a higher entropy than &lt;strong&gt;"ohgreatsully"&lt;/strong&gt; when calculated, yet the latter is significantly less guessable in a dictionary attack and would take centuries to crack using brute-force.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Entropy&lt;/th&gt;
&lt;th&gt;Strength&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Qw3rtyui!&lt;/td&gt;
&lt;td&gt;28.53&lt;/td&gt;
&lt;td&gt;Weak&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ohgreatsully&lt;/td&gt;
&lt;td&gt;41.00&lt;/td&gt;
&lt;td&gt;Strong&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;YjCK^i0jMYvjfp&lt;/td&gt;
&lt;td&gt;46.55&lt;/td&gt;
&lt;td&gt;Strong&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Abcdef123456@&lt;/td&gt;
&lt;td&gt;48.11&lt;/td&gt;
&lt;td&gt;Weak&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sillyunicornsflyhigh&lt;/td&gt;
&lt;td&gt;68.93&lt;/td&gt;
&lt;td&gt;Strong&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This highlights that entropy &lt;strong&gt;alone&lt;/strong&gt; isnt a reliable indicator.&lt;/p&gt;

&lt;p&gt;Highly complex passwords introduce another challenge: they're harder to remember, making users more likely to write them down or store them insecurely.&lt;/p&gt;

&lt;p&gt;This comic from &lt;a href="https://xkcd.com/936/" rel="noopener noreferrer"&gt;xkcd&lt;/a&gt; perfectly summarizes it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2qwetqjo777odidynf6x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2qwetqjo777odidynf6x.png" alt="xkcd: Password Strength" width="740" height="601"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While secure storage solutions like password managers exist, survey shows that only about &lt;strong&gt;32% of people&lt;/strong&gt; (at best, based on data from a subset of countries) actually use them, according to Bitwarden's &lt;a href="https://bitwarden.com/resources/world-password-day/" rel="noopener noreferrer"&gt;World Password Day Survey 2024&lt;/a&gt;. With such low adoption rates, I would say this should be an extra motivation not to enforce long and complex passwords upfront.&lt;/p&gt;

&lt;p&gt;Despite everything I've said so far, there's one exception to the rule: &lt;strong&gt;the minimum length requirement&lt;/strong&gt;. It is the only useful recommended composition policy--provided it's &lt;strong&gt;used within reason.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is because the number of possible combinations increases exponentially with the length of the password. For example, &lt;strong&gt;a 10-character password&lt;/strong&gt; has 26^10 possible combinations, while a &lt;strong&gt;20-character password&lt;/strong&gt; has 26^20 possible combinations.&lt;/p&gt;

&lt;p&gt;Here's &lt;strong&gt;NIST's&lt;/strong&gt; take on password length:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Verifiers and CSPs SHALL require passwords to be a minimum of eight characters in length and SHOULD require passwords to be a minimum of 15 characters in length."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Password length is the primary factor in characterizing password strength, so users should be encouraged to make their passwords as lengthy as they want. The more characters in a password, the more secure it is. Too short would put the users at risk to brute-force and dictionary attacks.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Better Approach
&lt;/h2&gt;

&lt;p&gt;So far, we're looked at &lt;strong&gt;what not to do&lt;/strong&gt;. Now, let's touch on &lt;strong&gt;what to do&lt;/strong&gt; to improve password security without the need for composition policies:&lt;/p&gt;

&lt;h3&gt;
  
  
  Check Passwords Against a Blacklist
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;"...verifiers SHALL compare the prospective secret against a blocklist that contains known commonly used, expected, or compromised passwords"&lt;/p&gt;

&lt;p&gt;"If the chosen password is found on the blocklist, the CSP or verifier SHALL require the subscriber to select a different secret and SHALL provide the reason for rejection"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One of the most effective ways to improve password security is to check passwords against a blacklist. This typically includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compromised passwords from previous database breaches.&lt;/li&gt;
&lt;li&gt;Common dictionary words.&lt;/li&gt;
&lt;li&gt;Context-specific words, such as the name of the service or platform.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a password matches an entry on the blacklist, it should be rejected, and the user should be prompted to choose a different password, with a clear reason for rejection provided.&lt;/p&gt;

&lt;p&gt;According to one of the test cases carried out in the Florida research paper, a blacklist of 50,000 entries was tested against 32 million compromised passwords with a maximum of 256 guesses. The results showed that the percentage pool of passwords found to be crackable &lt;strong&gt;with the blacklist was 0.058%&lt;/strong&gt; , compared to &lt;strong&gt;up to 14% without one&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You can use the &lt;a href="https://haveibeenpwned.com/API/v3" rel="noopener noreferrer"&gt;Have I Been Pwned API&lt;/a&gt; to access up-to-date list of compromised passwords for your blacklist.&lt;/p&gt;

&lt;p&gt;However, in as much as blacklists are incredibly useful, they come with a hard limitation: they can only compare entire strings, not substrings or individual words contained within a password. This caveat makes it impossible to detect sub-patterns.&lt;/p&gt;

&lt;p&gt;But wait--theres solution!&lt;/p&gt;

&lt;h3&gt;
  
  
  Evaluate Password Strength, not Complexity
&lt;/h3&gt;

&lt;p&gt;Building upon blacklists, we can take it a step further by creating a function to dynamically evaluate the guessability of the password based on multiple factors such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Length&lt;/li&gt;
&lt;li&gt;Dates&lt;/li&gt;
&lt;li&gt;Repeated characters (e.g., &lt;code&gt;aaaaaa&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Sequences (e.g., &lt;code&gt;abcdef&lt;/code&gt;, &lt;code&gt;123456&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Keyboard layout (e.g., &lt;code&gt;qwerty&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Leet-speak substitutions (e.g., &lt;code&gt;H3ll0&lt;/code&gt;&lt;code&gt;Hello&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Brute-force weaknesses&lt;/li&gt;
&lt;li&gt;Entropy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We take into account all these factors and score them individually, with their total sum forming the guessability score for the password. With this score in hand, we can reject any password whose guessability falls below a set threshold.&lt;/p&gt;

&lt;p&gt;You might be thinking to yourself-- &lt;strong&gt;"That's sound like a lot of work"&lt;/strong&gt;. And you're absolutely right. Fortunately for us, some fantastic engineer at Dropbox already created a tool to solve this very issue a while back called &lt;a href="https://github.com/dropbox/zxcvbn" rel="noopener noreferrer"&gt;zxcvbn&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Albeit, it's now old and unmaintained, there are fork implementations available for nearly every programming language out there. For JavaScript users, you can check out &lt;a href="https://github.com/zxcvbn-ts/zxcvbn" rel="noopener noreferrer"&gt;zxcvbn-ts&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here's what NIST has to say on password strength estimation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Verifiers SHALL offer guidance to the subscriber to assist the user in choosing a strong password."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Effectively, with the guessability data from our password strength estimator of choice, we can use that response to create strength meters, alert cards, etc. to guide the user into creating more secure passwords.&lt;/p&gt;

&lt;h2&gt;
  
  
  Live Demo 🔴
&lt;/h2&gt;

&lt;p&gt;To showcase estimating password strength, I built a web app that lets you compare composition policies against guessability metrics using &lt;a href="https://github.com/dropbox/zxcvbn" rel="noopener noreferrer"&gt;zxcvbn-ts&lt;/a&gt; and &lt;a href="https://haveibeenpwned.com/API/v3" rel="noopener noreferrer"&gt;Have I Been Pwned API&lt;/a&gt;. You can &lt;a href="https://password-strength-checker-eta-navy.vercel.app" rel="noopener noreferrer"&gt;check it out here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Upon inputting your password, you'll get to see its guessability score, estimated time to crack, pattern matches, and whether it has been compromised. You can find the &lt;a href="https://github.com/Armadillidiid/password-strength-checker" rel="noopener noreferrer"&gt;source code here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As shown in the screenshot below, &lt;code&gt;P@ssword1&lt;/code&gt; meets all composition policy requirements but returns a terrible guessability metric. Go ahead and give it a try for yourself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm17bo2967crczmkif859.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm17bo2967crczmkif859.png" alt=" raw `P@ssword1` endraw  Strength Result" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Hopefully, I was able to demonstrate to you that the concept of password entropy, as commonly applied by the most websites (through composition policies), fails to serve as a reliable metric for assessing the security of password &lt;strong&gt;when used on its own&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A significant subset of users will still choose easy-to-guess passwords, like &lt;code&gt;P@ssword1&lt;/code&gt;, that technically comply with the policy but remain highly vulnerable to attackers.&lt;/p&gt;

&lt;p&gt;It's time we move past strict password composition policies--they're not helping anyone. We've seen that it's possible to improve password security without sacrificing user experience.&lt;/p&gt;

&lt;p&gt;If you're still not convinced, you can also consider implementing Multi-Factor Authentication (MFA). That way even if a password is compromised, the attacker can't gain access without the second factor.&lt;/p&gt;

&lt;p&gt;That's all I have for now. Thanks for reading and I hope you found this article helpful.&lt;/p&gt;

</description>
      <category>passwords</category>
      <category>security</category>
      <category>authentication</category>
    </item>
    <item>
      <title>Unveiling React Server Components</title>
      <dc:creator>Emmanuel Isenah </dc:creator>
      <pubDate>Tue, 23 Apr 2024 07:20:24 +0000</pubDate>
      <link>https://dev.to/emmanuelisenah/unveiling-react-server-components-7j7</link>
      <guid>https://dev.to/emmanuelisenah/unveiling-react-server-components-7j7</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--irPQOtk0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1713253147290/da5a8e46-43ae-4c85-892a-e76d4012d11c.png%3Fw%3D1600%26h%3D840%26fit%3Dcrop%26crop%3Dentropy%26auto%3Dcompress%2Cformat%26format%3Dwebp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--irPQOtk0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1713253147290/da5a8e46-43ae-4c85-892a-e76d4012d11c.png%3Fw%3D1600%26h%3D840%26fit%3Dcrop%26crop%3Dentropy%26auto%3Dcompress%2Cformat%26format%3Dwebp" alt="Cover" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;React has undergone a significant evolution since its inception in 2013, transitioning from Higher-Order Components (HOCs) and lifecycle methods to the introduction of hooks in 2019. Now, one of the most recent and monumental changes is the advent of &lt;strong&gt;&lt;em&gt;React Server Components&lt;/em&gt;&lt;/strong&gt;. It opens the doors to running React code exclusively on the server.&lt;/p&gt;

&lt;p&gt;Similar to how hooks revolutionized how we code in React, &lt;strong&gt;&lt;em&gt;RSCs&lt;/em&gt;&lt;/strong&gt; represent another paradigm shift. However, there's been widespread confusion surrounding their functionality, particularly regarding how they tie well with traditional &lt;strong&gt;&lt;em&gt;Client components&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this blog post, we'll walk through the timeline of React, explaining Server-Side Rendering (SSR), Suspense, Component Boundaries, RSCs, what they aim to solve, and how they all interconnect to shape the React as we know today.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Server Side Rendering?
&lt;/h2&gt;

&lt;p&gt;To understand React Server Components (RSCs), we need first to understand how Server Side Rendering works (SSR) and what it tackles. So what is the SSR you might ask? In the simplest terms, it is the generation of HTML from React components on the server. This server-rendered HTML is then sent down to the browser allowing users to view the content of the page while the JavaScript bundle loads and runs.&lt;/p&gt;

&lt;p&gt;Before SSR became a thing, users would stare at a blank white page before React could bootstrap the page and attach event handlers. This rendered a bad user experience for users with a poor internet connection (because you have to download the JS bundle first) and users with low-end devices as the JS script has to be parsed and executed, leading to longer &lt;a href="https://developer.chrome.com/docs/lighthouse/performance/first-contentful-paint"&gt;FCP&lt;/a&gt; (First Contentful Paint).&lt;/p&gt;

&lt;p&gt;The typical HTML file sent down looks a lot like the below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;!&lt;/span&gt;&lt;span class="nx"&gt;DOCTYPE&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;module&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/assets/js/bundle.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/body&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/html&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;bundle.js&lt;/code&gt; (usually named with random hash strings as the filename) is the minified bundled output of our application code and contains everything including third-party dependencies needed to run on the browser. This is commonly referred to as the traditional "client-side" rendering strategy (CSR).&lt;/p&gt;

&lt;p&gt;Server Side Rendering was introduced specifically to solve this very problem. Instead of viewing a blank page till React bootstraps the page, the server can send a pre-rendered HTML presentation of the content. Albeit, it won't be interactive still event handlers are attached. This illusion creates a better UX.&lt;/p&gt;

&lt;p&gt;It is achieved using &lt;a href="https://react.dev/reference/react-dom/server"&gt;&lt;code&gt;react-dom/server&lt;/code&gt;&lt;/a&gt; APIs, specifically the &lt;a href="https://react.dev/reference/react-dom/server/renderToString"&gt;&lt;code&gt;renderToString&lt;/code&gt;&lt;/a&gt; method. This API method helps render a React tree to an HTML string like so:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//SERVER&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;renderToString&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-dom/server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./App.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;renderToString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then on the client, the browser calls &lt;a href="https://react.dev/reference/react-dom/client/hydrateRoot#root-render"&gt;&lt;code&gt;hydrateRoot&lt;/code&gt;&lt;/a&gt; to make the server-generated HTML interactive. This is accomplished through a technique called &lt;code&gt;hydration&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//CLIENT&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;hydrateRoot&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-dom/client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;domNode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hydrateRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;domNode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reactNode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;&lt;em&gt;Hydration&lt;/em&gt;&lt;/strong&gt; you say? What is that?&lt;/p&gt;

&lt;p&gt;Well, &lt;strong&gt;&lt;em&gt;hydration&lt;/em&gt;&lt;/strong&gt; is the process of using client-side JavaScript to add application state and interactivity to server-rendered HTML. To quote &lt;a href="https://twitter.com/dan_abramov"&gt;Dan Abramov&lt;/a&gt; on his GitHub gist about SSR:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hydration is like watering the “dry” HTML with the “water” of interactivity and event handlers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;React will attach to the HTML that exists inside the &lt;code&gt;domNode&lt;/code&gt;, and take over managing the DOM inside it. It will attach event handlers, fire off any effects, and so on.&lt;/p&gt;

&lt;p&gt;However, for frameworks like Next.js, Remix, etc., SSR could come in different forms or rendering strategies. It could be static or dynamic. Let me explain:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Static Rendering&lt;/strong&gt;: With static rendering, components are pre-rendered at build time, or in the background after data revalidation. The output is then cached and pushed to be served by a &lt;a href="https://developer.mozilla.org/docs/Glossary/CDN"&gt;CDN&lt;/a&gt;. This rendering strategy is only used when the data in a component can be known at build time, such as a static blog.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Rendering:&lt;/strong&gt; With dynamic rendering, all components or routes are rendered each time at &lt;strong&gt;request time.&lt;/strong&gt; This means when a client fetches UI components from the server, it is rendered dynamically based on information that can only be known at request time such as cookies or URL search params. This strategy ensures that the returned response is always up-to-date and tailored to the specific request.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And that's everything to know about Server Side Rendering. It's not a new concept and has actually been part of React since its inception. Don't believe me? &lt;a href="https://github.com/facebook/react/blob/main/CHANGELOG.md#040-july-17-2013"&gt;Here are the release notes from v0.4.0.&lt;/a&gt; Albeit, the SSR back then wasn't the same as what we have today, it was always in the works.&lt;/p&gt;

&lt;p&gt;That aside, SSR until recently posed two major imperfections despite being better than "client-side" rendering (CSR).&lt;/p&gt;
&lt;h2&gt;
  
  
  Flaws of Legacy SSR
&lt;/h2&gt;

&lt;p&gt;With the previous SSR, pre-rendering of the HTML and hydration were an "&lt;strong&gt;all-or-nothing&lt;/strong&gt;" decision. This meant for the server to respond with HTML to the client, all components must have their data ready beforehand. It needed to wait for &lt;strong&gt;all blocking components&lt;/strong&gt; to be ready before it could start sending any pre-rendered HTML. This was its first flaw.&lt;/p&gt;

&lt;p&gt;The second major flaw was that React had to hydrate every JavaScript code before you could interact with the UI. This meant that once React starts calling your component functions, it won't stop until it's done with your entire tree. While this issue may be arguable for users with high-end devices, it proves untenable for general use cases. Especially if the user wants to navigate out of the current page quickly, but can't do so due to hydration blocking interactions.&lt;/p&gt;

&lt;p&gt;The above problems contain one common pattern: &lt;strong&gt;they require the selection of performing only one task at a time&lt;/strong&gt;. As recently discussed, in SSR, a sequence of stages must be completed before users can view and interact with a page. Due to this sequential nature, they act as blocking operations, preventing the server from advancing to the next stage until the preceding one is finished.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cPo16mmg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711223310269/86728ec4-a699-45c5-8f64-e066dc4430f3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cPo16mmg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711223310269/86728ec4-a699-45c5-8f64-e066dc4430f3.png" alt="" width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What if we could split up these sequential stages to be handled asynchronously for each part of the page?&lt;/p&gt;

&lt;p&gt;Luckily, the React team foresaw this problem and created what we know today as &lt;a href="https://react.dev/reference/react/Suspense"&gt;&lt;strong&gt;&lt;em&gt;Suspense&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Streaming with React Suspense
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Streaming&lt;/strong&gt; allows us to break down a page's HTML into smaller chunks and progressively send those chunks, bit by bit, from the server to the client. The result of this is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pages display earlier, eliminating the need to wait for data loading on the server.&lt;/li&gt;
&lt;li&gt;Interactivity with the page is enabled sooner, bypassing the necessity to wait for the entire DOM tree to complete hydration. (More on this later on)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rGFbPSJn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711300473280/aa847545-5820-45b5-b456-5c03b23a7d23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rGFbPSJn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711300473280/aa847545-5820-45b5-b456-5c03b23a7d23.png" alt="" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is accomplished through the API &lt;a href="https://react.dev/reference/react-dom/server/renderToPipeableStream"&gt;&lt;code&gt;renderToPipeableStream&lt;/code&gt;&lt;/a&gt;, which utilizes &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Streams_API"&gt;Streams API&lt;/a&gt; under the hood.&lt;/p&gt;

&lt;p&gt;Streaming isn't anything new as browsers have long utilized it for handling media assets; videos buffer and play as additional content downloads.&lt;/p&gt;

&lt;p&gt;It aligns perfectly with React's core component model as each component could be classified as a chunk. Components that don't depend on dynamic data, such as a &lt;code&gt;Navbar&lt;/code&gt;, can be prioritized and sent down first for earlier hydration. Subsequently, other components could be transmitted once all their required data has been fetched.&lt;/p&gt;

&lt;p&gt;For example, consider we have the following component structure:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Layout&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;NavBar&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Sidebar&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PostFeed&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Comments&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Layout&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Which will be rendered to this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XsiANumZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711306707206/afa2e4da-b7b1-4fc1-b7ec-e0ca75546e9c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XsiANumZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711306707206/afa2e4da-b7b1-4fc1-b7ec-e0ca75546e9c.png" alt="" width="800" height="585"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The components &lt;code&gt;&amp;lt;Comments/&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;PostFeed/&amp;gt;&lt;/code&gt; require data fetching. Thus, it's preferable to instruct the server not to wait for their readiness and instead send a fallback UI (e.g. skeleton, spinner) in their place. We can achieve this by wrapping them both in &lt;code&gt;&amp;lt;Suspense&amp;gt;&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Suspense&lt;/span&gt; &lt;span class="nx"&gt;fallback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Spinner&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Post&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Comments&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Suspense&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;React will now display a spinner component while they get ready:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fuW5JpgJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711308930577/71667508-e570-4983-a17f-a5c185d427fa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fuW5JpgJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711308930577/71667508-e570-4983-a17f-a5c185d427fa.png" alt="" width="800" height="585"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we further inspect the returned HTML, we'll find neither component in the DOM tree - &lt;code&gt;&amp;lt;Comments /&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;PostFeed /&amp;gt;&lt;/code&gt; .&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"root"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;nav&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!--NavBar --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Home&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;aside&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Sidebar --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/profile"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Profile&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/aside&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Spinner --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"200"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"200"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/static/spinner.gif"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Loading..."&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Once both components are ready on the server, using the pre-existing stream, additional HTML, along with an inline &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; , will be sent to replace the fallback element. Since this comprises solely of HTML, React doesn't even need to be loaded at the time for the components HTML to display.&lt;/p&gt;

&lt;p&gt;With this approach, we don't have to delay our pre-rendered HTML from being sent down anymore due to a component or groups of components.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Early Adoption&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Suspense queitly made its debut in 2018 in the form of &lt;code&gt;React.lazy&lt;/code&gt;. Initially, it only supported lazy-loading code on the client. Despite its limited scope upon release though, its overarching goal was to integrate with Server-Side Rendering.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I previously hinted at the advantage of "&lt;strong&gt;&lt;em&gt;Interactivity with the page is enabled sooner&lt;/em&gt;&lt;/strong&gt;" when discussing the benefits of Suspense. This is enabled by a concept called "&lt;strong&gt;&lt;em&gt;Selective Hydration&lt;/em&gt;&lt;/strong&gt;."&lt;/p&gt;
&lt;h2&gt;
  
  
  Quick Memo on Selective Hydration
&lt;/h2&gt;

&lt;p&gt;Wrapping our components with &lt;code&gt;&amp;lt;Suspense&amp;gt;&lt;/code&gt; brings one more improvement that's not immediately apparent: &lt;strong&gt;hydration no longer blocks the browser from performing other tasks.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This improvement is due to React's intelligent prioritization of hydration based on user interaction. For instance, when a user triggers an event like a click, React ensures that the corresponding components along the interaction path are prioritized for hydration. This includes traversing up the component tree, ensuring that every relevant component is hydrated until a Suspense boundary is encountered.&lt;/p&gt;

&lt;p&gt;Also when React hydrates components within a Suspense boundary, it does so in small intervals where the browser still retains its ability to handle events. This guarantees the UI remains responsive during prolonged hydration periods.&lt;/p&gt;

&lt;p&gt;Now, let's imagine that hydration for &lt;code&gt;&amp;lt;Comments /&amp;gt;&lt;/code&gt; hasn't occurred yet, while the &lt;code&gt;&amp;lt;PostFeed /&amp;gt;&lt;/code&gt; component is currently undergoing hydration. Both their code has being downloaded also.&lt;/p&gt;

&lt;p&gt;Now, if we were to click on &lt;code&gt;&amp;lt;Comments /&amp;gt;&lt;/code&gt; rendered HTML.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vEW5Ey-H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711355223553/dcaeb1bf-168e-4c0e-afbb-507486d732b2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vEW5Ey-H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711355223553/dcaeb1bf-168e-4c0e-afbb-507486d732b2.png" alt="" width="800" height="585"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the same capture phase of the click, React will stop whatever it's doing and urgently hydrate &lt;code&gt;&amp;lt;Comments /&amp;gt;&lt;/code&gt; just in time to respond to the click event.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8rvc5PxZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711356090641/9ada9154-65eb-4969-9a46-0beac6593fc8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8rvc5PxZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711356090641/9ada9154-65eb-4969-9a46-0beac6593fc8.png" alt="" width="800" height="585"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To quote &lt;a href="https://twitter.com/dan_abramov"&gt;Dan Abramov&lt;/a&gt; again:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;This creates an illusion that hydration is instant because components on the interaction path get hydrated first.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Following that, React will proceed to hydrate the remainder of the application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LYJrUHWP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711356571885/2526e666-d3b9-4a43-a8e0-0b8997f01ccc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LYJrUHWP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711356571885/2526e666-d3b9-4a43-a8e0-0b8997f01ccc.png" alt="" width="800" height="585"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And that's how our pages appear to be more responsive more quickly. By utilizing &lt;code&gt;Suspense&lt;/code&gt;, we automatically opt into all these features. For more details, you can explore the &lt;a href="https://react.dev/reference/react/Suspense"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So far, we've discussed what Server-Side Rendering (SSR) is and how well it integrates with Suspense. However, there's one more ingredient we could add to the mix to make our dish complete.&lt;/p&gt;

&lt;p&gt;In all our previous examples, our React code has consistently run on the server to generate an initial shell and then is sent down to the client, to enhance the loading experience to feel somewhat faster. We've even explored the possibility of streaming the chunks of HTML. However, what if we wanted to execute code exclusively on the server and send down only the outputs (without the source code)?&lt;/p&gt;

&lt;p&gt;For instance, imagine we want to query our remote database. This hasn't been feasible so far with React, even with Server-Side Rendering. Our components still get rendered on both the server and the client.&lt;/p&gt;

&lt;p&gt;Meta frameworks like Next.js and Remix each introduced their own solutions. Next.js implemented &lt;a href="https://nextjs.org/docs/pages/building-your-application/data-fetching/get-server-side-props"&gt;&lt;code&gt;getServerSideProps&lt;/code&gt;&lt;/a&gt;, Remix introduced &lt;a href="https://remix.run/docs/en/main/route/loader"&gt;&lt;code&gt;loader&lt;/code&gt;&lt;/a&gt; functions etc. These solutions enabled us to run some code ahead of rendering our components. However, they each had their drawbacks, including inconsistent implementations (no official standard) and limitations such as only functioning at the route level (components at the top of the tree).&lt;/p&gt;

&lt;p&gt;Fortunately, the React team came up with an official standard to address this problem: &lt;strong&gt;React Server Components&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  New Paradigm: React Server Components
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;React Server Components&lt;/em&gt;&lt;/strong&gt; (RSCs) represent a fundamental shift by executing code on the server rather than the client. This also grants us access to server infrastructure such as file systems and data stores. Essentially, anything runnable in a Node environment can be executed within RSCs. But this also comes with a trade-off; &lt;strong&gt;a significant portion of React and Web APIs become incompatible.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here is a simple example of a server component:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PrismaClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@prisma/client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Connect to the database&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PrismaClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Fetch all blog posts that contains keyword "Next"&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findMany&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Next&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Blog&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/article&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;))}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;There's a lot to address here. Initially, one might wonder how our component is capable of being asynchronous. You might argue our async call is going to trigger on every render. While this skepticism would be valid for a "&lt;strong&gt;&lt;em&gt;Client component"&lt;/em&gt;&lt;/strong&gt; (more on this later), it doesn't apply in this case.&lt;/p&gt;

&lt;p&gt;The thing is, &lt;strong&gt;&lt;em&gt;Server Components&lt;/em&gt;&lt;/strong&gt; do not actually &lt;strong&gt;re-render&lt;/strong&gt;. They're rendered only once on the server to the generate UI, and the result is sent down. Hence, why certain React APIs become incompatible as interactivity isn't needed.&lt;/p&gt;

&lt;p&gt;If a state change occurs and we wish to display the fresh update, we can call &lt;a href="https://nextjs.org/docs/app/api-reference/functions/use-router#userouter"&gt;&lt;code&gt;router.refresh&lt;/code&gt;&lt;/a&gt;. This action will trigger a new request to the server, prompting the re-rendering of Server Components, and then merge the updated RSC payload without losing the client-side state.&lt;/p&gt;

&lt;p&gt;In the code example, we're also establishing a connection to our database using our preferred ORM. Due to the environment isolation of RSCs, we avoid exposing confidential secrets (e.g., DATABASE_URL) while eliminating unnecessary round trips (zero waterfalls).&lt;/p&gt;

&lt;p&gt;Considering that our servers are also consistently provisioned closer to our data sources (e.g., database, message broker), RSCs will always resolve quicker (in terms of latency).&lt;/p&gt;

&lt;p&gt;It's good to know in this shifting landscape, what we commonly refer to as "&lt;strong&gt;Client components&lt;/strong&gt;" are traditional React components imbued with interactivity. Even though the name implies they're only rendered on the client, this isn't the fact as they're pre-rendered on the server too due to SSR. Honestly, the naming convention can be a bit misleading—a misnomer, if you will—but it's what everyone calls it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Component Boundaries and Directive
&lt;/h2&gt;

&lt;p&gt;By default, all components are opted-in as "&lt;strong&gt;Server Components&lt;/strong&gt;". To make a component or module client-side, we have to &lt;strong&gt;explicitly opt-in&lt;/strong&gt; using the "&lt;code&gt;use client&lt;/code&gt;" directive. This is usually carried out by specifying it at the top of the file:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Increment&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This directive signals React to execute the module on the client side. Additionally, it's important to note that by adding a directive, the same effect is applied to transitive dependencies—modules that are directly imported.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: There's also an additional directive called "&lt;code&gt;use server&lt;/code&gt;". It is currently used for Server Actions and has a totally different behaviour.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When a file is marked with '&lt;code&gt;use client&lt;/code&gt;' and is imported from a Server Component, it serves as a boundary in the module dependency tree between code intended for server-side execution and that meant for client-side execution.&lt;/p&gt;

&lt;p&gt;It's important to differentiate between a module dependency tree and a render tree because they each capture a different hierarchical structure of an app. What leads to this distinction?&lt;/p&gt;

&lt;p&gt;The module dependency tree outlines the relationships between modules in terms of their dependencies and imports. This tree helps bundlers determine the dependencies of each module and how they should be packaged for deployment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uATq40mk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711737680719/8827550c-cd44-4bed-8c2d-9cf45a7e2d12.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uATq40mk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711737680719/8827550c-cd44-4bed-8c2d-9cf45a7e2d12.png" alt="" width="800" height="492"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the other hand, the render tree focuses solely on component modules, excluding non-component modules. It represents the flow of components as they render in the application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5tQBZibQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711737894663/7beb65b5-d8d3-4da8-a1d0-e6b4fd953874.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5tQBZibQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711737894663/7beb65b5-d8d3-4da8-a1d0-e6b4fd953874.png" alt="" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In my personal opinion, I find it much simpler to visualize boundaries within a dependency tree compared to a render tree. The mental model becomes increasingly complex when JSX is passed as props between components. This is because directives become automatically applied to modules directly imported into the component.&lt;/p&gt;

&lt;p&gt;Consequently, in a render tree, we might encounter a scenario where a server component acts as a child to a client component. Yes, this scenario is indeed possible, which can lead to confusion in understanding the execution environment of each component.&lt;/p&gt;

&lt;p&gt;To better illustrate this, take for example the following component structure:&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;a href="https://codesandbox.io/p/devbox/github/Armadillidiid/render-and-module-tree-demo" rel="noopener noreferrer"&gt;
      codesandbox.io
    &lt;/a&gt;
&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--w-pc2Ixj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711494675438/1a9dc806-00ae-4860-88af-f1d9bf989b60.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--w-pc2Ixj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711494675438/1a9dc806-00ae-4860-88af-f1d9bf989b60.png" alt="" width="800" height="604"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In our render tree, we have three components: &lt;code&gt;Comp A&lt;/code&gt;, which is a conditionally rendered server component that accepts &lt;code&gt;Comp C&lt;/code&gt; as children; &lt;code&gt;Comp B,&lt;/code&gt; a client component; and &lt;code&gt;Comp C&lt;/code&gt;, which serves as both a client and server component.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HQYT4i_b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711494088867/fb29287a-0cd1-4ffc-9cd5-f9b15612f21f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HQYT4i_b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711494088867/fb29287a-0cd1-4ffc-9cd5-f9b15612f21f.png" alt="" width="800" height="604"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Comp C is a client and server component? How is that even possible?&lt;/p&gt;

&lt;p&gt;Well, when a component is defined in a module with a &lt;code&gt;'use client'&lt;/code&gt; directive, or the component is imported and called in a Client Component, then the component is a Client Component. Otherwise, the component is a Server Component.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sUcNpS3P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711737439650/78e21fa6-d9d5-4c20-abc0-6787e6a39288.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sUcNpS3P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711737439650/78e21fa6-d9d5-4c20-abc0-6787e6a39288.png" alt="" width="800" height="604"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this scenario, &lt;code&gt;Comp A&lt;/code&gt; receives &lt;code&gt;Comp C&lt;/code&gt; as a child component, but it neither directly imports the module nor calls the component itself. As a result, &lt;code&gt;Comp C&lt;/code&gt; doesn't appear as a node under &lt;code&gt;Comp A&lt;/code&gt;. According to the definition provided earlier, &lt;code&gt;Comp C&lt;/code&gt; becomes a server component by usage, as it's the parent &lt;code&gt;App&lt;/code&gt; component that executes it.&lt;/p&gt;

&lt;p&gt;On the other hand, under &lt;code&gt;Comp B&lt;/code&gt;, &lt;code&gt;Comp C&lt;/code&gt; is directly imported and rendered, making it a dependency of &lt;code&gt;Comp B&lt;/code&gt;. Therefore, &lt;code&gt;Comp C&lt;/code&gt; becomes a client component in this context.&lt;/p&gt;

&lt;p&gt;It's important to note that if &lt;code&gt;Comp C&lt;/code&gt; had interactivity or utilized unsupported Web APIs, React would raise an error because a server component can only be a child node to a client component in the module dependency tree if passed as children.&lt;/p&gt;

&lt;h3&gt;
  
  
  When Components Should be Rendered as Client Components?
&lt;/h3&gt;

&lt;p&gt;In general, if a component can be rendered on the server without any issues, it's best to keep it as a server component. This is beneficial due to the performance boosts provided by RSCs. However, since most applications require some level of interactivity in reality, not every component can be a server component.&lt;/p&gt;

&lt;p&gt;My advice would be to thrive on making Client Components primarily as leaves within the component tree. Ideally, they should be positioned as far down a branch as possible, ensuring that their children do not inherit the "&lt;code&gt;use client&lt;/code&gt;" directive.&lt;/p&gt;

&lt;h2&gt;
  
  
  RSC Under the Hood
&lt;/h2&gt;

&lt;p&gt;Have you taken a moment to inspect your network tab to view the response of a Server Component? It's noteworthy that RSCs aren't sent down as a JS script file.&lt;/p&gt;

&lt;p&gt;On the server, React renders your Server Components into a special data format known as an &lt;strong&gt;&lt;em&gt;RSC Payload&lt;/em&gt;&lt;/strong&gt;. Then on the client, React downloads and parses the payload to resolve where to render the elements. The output structure resembles JSON a lot, that's because it mostly is.&lt;/p&gt;

&lt;p&gt;Before inspecting the payload, there are a few things we need to first glance at.&lt;/p&gt;

&lt;p&gt;React serializes components rendered on the server, along with any props passed from a Server Component to a Client Component. If you're familiar with &lt;code&gt;JSON.stringify&lt;/code&gt;, then you're likely aware that not all types are serializable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;([[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;one&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;two&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;three&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]]);&lt;/span&gt; &lt;span class="err"&gt;❌&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="kd"&gt;set&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="err"&gt;❌&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="err"&gt;✅&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;


&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Output: "{"map":{},"set":{},"arr":[1,2,3]}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To combat this, React uses a &lt;a href="https://github.com/facebook/react/blob/a1c62b8a7635c0bc51e477ba5437df9be5a9e64f/packages/react-client/src/ReactFlightReplyClient.js#L154"&gt;custom mapper&lt;/a&gt;. This custom mapper under the hood uses &lt;code&gt;JSON.stringify&lt;/code&gt; but with a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#the_replacer_parameter"&gt;replacer function&lt;/a&gt; to support non-serializable types. Depending on the type of the value, it performs a specific serialization operation. For example, if the value is a promise, it waits for its resolution and serializes the resolved value by calling &lt;code&gt;serializePromiseID&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The serialize functions execute two purposes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;They take in the &lt;code&gt;id&lt;/code&gt; of the serialized type and converts it into a string representation.&lt;/li&gt;
&lt;li&gt;They prefix this resulting string with a dollar symbol and an identifier character to signify the unique type. For instance, 'W' for sets, 'Q' for maps, etc.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Thereafter, on the client side, React utilizes these unique prefixes to reference and deserialize the JSON string back to its original form.&lt;/p&gt;

&lt;p&gt;That's enough talk. Let's add a new route with some non-default serializable types to see what the payload actually looks like. We'll still be using the code from our &lt;a href="https://codesandbox.io/p/github/Armadillidiid/render-and-module-tree-demo/draft/throbbing-waterfall"&gt;previous CodeSandbox&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/app/new/page.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/link&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Prefetch&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Link&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Converted CompA from server component to client&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CompA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;CompA&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we visit the route &lt;code&gt;/new&lt;/code&gt; and renavigate back to the root page using the Link component, we should get this response in our network tab. Due to SSR, the &lt;strong&gt;&lt;em&gt;RSC payload&lt;/em&gt;&lt;/strong&gt; can only be seen on subsequent navigations. If you were to load &lt;code&gt;/new&lt;/code&gt; as your initial load, you'd only get an HTML response.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="err"&gt;:I&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"(app-pages-browser)/./app/CompA.js"&lt;/span&gt;&lt;span class="p"&gt;,[&lt;/span&gt;&lt;span class="s2"&gt;"app/page"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"static/chunks/app/page.js"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"$Sreact.suspense"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="err"&gt;:I&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"(app-pages-browser)/./node_modules/next/dist/shared/lib/lazy-dynamic/dynamic-bailout-to-csr.js"&lt;/span&gt;&lt;span class="p"&gt;,[&lt;/span&gt;&lt;span class="s2"&gt;"app/page"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"static/chunks/app/page.js"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="s2"&gt;"BailoutToCSR"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"one"&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"two"&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"three"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"development"&lt;/span&gt;&lt;span class="p"&gt;,[[&lt;/span&gt;&lt;span class="s2"&gt;"children"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"__PAGE__"&lt;/span&gt;&lt;span class="p"&gt;,[&lt;/span&gt;&lt;span class="s2"&gt;"__PAGE__"&lt;/span&gt;&lt;span class="p"&gt;,{}],[&lt;/span&gt;&lt;span class="s2"&gt;"__PAGE__"&lt;/span&gt;&lt;span class="p"&gt;,{},[&lt;/span&gt;&lt;span class="s2"&gt;"$L1"&lt;/span&gt;&lt;span class="p"&gt;,[[&lt;/span&gt;&lt;span class="s2"&gt;"$"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"$L2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,{&lt;/span&gt;&lt;span class="nl"&gt;"json"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"map"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"$Q3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"set"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"$W4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"arr"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt;&lt;span class="nl"&gt;"children"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="s2"&gt;"$"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"h2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,{&lt;/span&gt;&lt;span class="nl"&gt;"children"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Above 12:00 PM"&lt;/span&gt;&lt;span class="p"&gt;}]}],[&lt;/span&gt;&lt;span class="s2"&gt;"$"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"$5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,{&lt;/span&gt;&lt;span class="nl"&gt;"fallback"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"children"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="s2"&gt;"$"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"$L6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,{&lt;/span&gt;&lt;span class="nl"&gt;"reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"next/dynamic"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"children"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"$L7"&lt;/span&gt;&lt;span class="p"&gt;}]}]],&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;]],[&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"$L8"&lt;/span&gt;&lt;span class="p"&gt;]]]]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="err"&gt;:I&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"(app-pages-browser)/./app/CompB.js"&lt;/span&gt;&lt;span class="p"&gt;,[&lt;/span&gt;&lt;span class="s2"&gt;"app/page"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"static/chunks/app/page.js"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"$"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"$L9"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,{}]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="s2"&gt;"$"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"meta"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"0"&lt;/span&gt;&lt;span class="p"&gt;,{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"viewport"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"width=device-width, initial-scale=1"&lt;/span&gt;&lt;span class="p"&gt;}],[&lt;/span&gt;&lt;span class="s2"&gt;"$"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"meta"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,{&lt;/span&gt;&lt;span class="nl"&gt;"charSet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"utf-8"&lt;/span&gt;&lt;span class="p"&gt;}],[&lt;/span&gt;&lt;span class="s2"&gt;"$"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"2"&lt;/span&gt;&lt;span class="p"&gt;,{&lt;/span&gt;&lt;span class="nl"&gt;"children"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Create Next App"&lt;/span&gt;&lt;span class="p"&gt;}],[&lt;/span&gt;&lt;span class="s2"&gt;"$"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"meta"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"3"&lt;/span&gt;&lt;span class="p"&gt;,{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Generated by create next app"&lt;/span&gt;&lt;span class="p"&gt;}],[&lt;/span&gt;&lt;span class="s2"&gt;"$"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"link"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"4"&lt;/span&gt;&lt;span class="p"&gt;,{&lt;/span&gt;&lt;span class="nl"&gt;"rel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"icon"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"href"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"/favicon.ico"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"image/x-icon"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"sizes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"16x16"&lt;/span&gt;&lt;span class="p"&gt;}],[&lt;/span&gt;&lt;span class="s2"&gt;"$"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"meta"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"5"&lt;/span&gt;&lt;span class="p"&gt;,{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"next-size-adjust"&lt;/span&gt;&lt;span class="p"&gt;}]]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Right out of the gate, the first notable observation is each line begins with a number, followed by a colon, and sometimes proceeded by the character "&lt;strong&gt;I&lt;/strong&gt;". After that, the remaining data appears to be JSON.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"one"&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"two"&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"three"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;...,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="s2"&gt;"$"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="s2"&gt;"$L2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"json"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"map"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$Q3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"set"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$W4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"arr"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"children"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="s2"&gt;"$"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="s2"&gt;"h2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"children"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Above 12:00 PM"&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I went ahead and removed some lines of the payload to analyze the essential parts.&lt;/p&gt;

&lt;p&gt;There are a few key elements to decipher here. Notably, we can see our serialized set and map appear as the third element in the node array, each accompanied by their respective IDs. If further look down, you see where they are referenced by the id with theirs respective identifier prefix. The identifier prefix informs React about the data type for proper parsing.&lt;/p&gt;

&lt;p&gt;What about the second element in the node? It represents the current level node, which could be either an HTML tag or a component. In cases where the node is a client component, it points to the payload line referencing the JavaScript file. This explains why some lines have an "&lt;strong&gt;I&lt;/strong&gt;" prefix, as they reference a JavaScript file on the client.&lt;/p&gt;

&lt;p&gt;Everything beyond "&lt;code&gt;$L1&lt;/code&gt;" which represents the route segment component, constitutes a proper &lt;code&gt;node&lt;/code&gt; with an expression resembling this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"$"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"p"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"children"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"I'm a child node"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which gets interpreted to the below in the DOM:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OiQWJzFM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711666496843/ec34f668-c4fe-4773-81aa-0dab90c273dd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OiQWJzFM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711666496843/ec34f668-c4fe-4773-81aa-0dab90c273dd.png" alt="" width="297" height="124"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're curious to &lt;em&gt;play around with&lt;/em&gt; parsing of RSC payload, check out this &lt;a href="https://rsc-parser.vercel.app/"&gt;dev tool by Alvar Lagerlöf&lt;/a&gt;. It provides a visual representation of the payload with intuitive UI components.&lt;/p&gt;

&lt;p&gt;Additionally, there's a &lt;a href="https://github.com/reactjs/server-components-demo"&gt;minimal RSC demo&lt;/a&gt; without SSR built by the React team. It saves you the hassle of setting up a project to explore RSCs. Also, since it lacks SSR, you can access the RSC payload upon the initial page load without navigating.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The advent of React Server Components marks a milestone in the way we code in React today. By shifting the heavy lifting of rendering to the server, we can achieve faster load times and ship less JavaScript bundles to the browser. Consider the image below, depicting legacy SSR:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tdnwcSB8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711738629309/d8b47e81-f530-4a24-b008-6a612087c8be.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tdnwcSB8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711738629309/d8b47e81-f530-4a24-b008-6a612087c8be.png" alt="" width="800" height="506"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, by integrating Suspense and React Server Components, we can achieve results like the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ah7mNkkn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711718041599/a84c826e-72f2-4dda-9889-3295c04ef9b6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ah7mNkkn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1711718041599/a84c826e-72f2-4dda-9889-3295c04ef9b6.png" alt="" width="800" height="506"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And if we want to take things to the next level, there's a new feature released in Next.js 14 (albeit currently experimental) called &lt;a href="https://nextjs.org/docs/app/api-reference/next-config-js/partial-prerendering"&gt;Partial Prerendering&lt;/a&gt;. If we utilize it, we can essentially eliminate the initial pre-render block, ensuring that content is delivered instantly upon user request.&lt;/p&gt;

&lt;p&gt;These are exciting times to be a web developer as the ecosystem continues to push out new technologies each day. I'm filled with optimism for the future and hope that this blog post has successfully revealed the capabilities of React as it stands today.&lt;/p&gt;

</description>
      <category>react</category>
      <category>nextjs</category>
      <category>frontend</category>
    </item>
    <item>
      <title>What's New in TypeScript 5.4 Beta</title>
      <dc:creator>Emmanuel Isenah </dc:creator>
      <pubDate>Thu, 08 Feb 2024 08:28:06 +0000</pubDate>
      <link>https://dev.to/emmanuelisenah/whats-new-in-typescript-54-beta-1ndi</link>
      <guid>https://dev.to/emmanuelisenah/whats-new-in-typescript-54-beta-1ndi</guid>
      <description>&lt;p&gt;Greetings! &lt;a href="https://devblogs.microsoft.com/typescript/announcing-typescript-5-4-beta"&gt;TypeScript 5.4 Beta&lt;/a&gt; just dropped and it presents new exciting features with some bug fixes and QoL changes. Without further delay, let's quickly explore some of these game-changing improvements.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;Object.groupBy&lt;/code&gt; and &lt;code&gt;Map.groupBy&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;One of the new API changes added in &lt;a href="https://devblogs.microsoft.com/typescript/announcing-typescript-5-4-beta"&gt;TypeScript 5.4 Beta&lt;/a&gt; is the declarations for upcoming JavaScript methods: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/groupBy"&gt;&lt;code&gt;Object.groupBy&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/groupBy"&gt;&lt;code&gt;Map.groupBy&lt;/code&gt;&lt;/a&gt; . These static methods simplify the grouping of items in an array (and iterables such as objects or maps) far easier.&lt;/p&gt;

&lt;p&gt;It works by accepting an iterable and a function that classifies which group each element should be placed in. The result of this function is then used to create an object key for each distinct group and adds the original element to an array for every key. Here's an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;people&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bob&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Charlie&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;David&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// ... more people&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// Group people by age range&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ageGroups&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;groupBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;people&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;young&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;adult&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;senior&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result of the above is well equivalent to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;people&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;young&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;David&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="na"&gt;adult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bob&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="na"&gt;senior&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Charlie&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this can be done with other iterables such as arrays or maps.&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;Map.groupBy&lt;/code&gt;, it performs equivalently to &lt;code&gt;Object.groupBy&lt;/code&gt;, but instead produces a map as output rather than a plain object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fruits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;banana&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;orange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kiwi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// Group fruits by their first letter&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;letterGroups&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;groupBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fruits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fruit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;fruit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Resulting map:&lt;/span&gt;
&lt;span class="c1"&gt;// Map {&lt;/span&gt;
&lt;span class="c1"&gt;//   'a' =&amp;gt; ['apple'],&lt;/span&gt;
&lt;span class="c1"&gt;//   'b' =&amp;gt; ['banana'],&lt;/span&gt;
&lt;span class="c1"&gt;//   'o' =&amp;gt; ['orange'],&lt;/span&gt;
&lt;span class="c1"&gt;//   'k' =&amp;gt; ['kiwi']&lt;/span&gt;
&lt;span class="c1"&gt;// }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A good thing to note is the objects produced end up as a &lt;code&gt;Parital&lt;/code&gt; record as there's no concrete way for the compiler to ensure all keys were created. To access variables, you'll have to use an optional chaining operator or check for &lt;code&gt;undefined&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;AgeGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
  &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;young&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;adult&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;senior&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;}[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;ageGroups&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;young&lt;/span&gt; &lt;span class="c1"&gt;// OK&lt;/span&gt;
&lt;span class="nx"&gt;ageGroups&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;young&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;ageGroups&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;young&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// OK&lt;/span&gt;
&lt;span class="nx"&gt;ageGroups&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;young&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Error: Object is possibly 'undefined'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This static method is yet to be included in the standard as it's a pending &lt;a href="https://github.com/tc39/proposal-array-grouping"&gt;TC39 proposal&lt;/a&gt;. However, it's in stage 4, indicating that it will be included in the next stable release, &lt;code&gt;ES2024&lt;/code&gt;. To use these methods currently, you have to change your target and lib to &lt;code&gt;ESNext&lt;/code&gt; in your &lt;code&gt;tsconfig&lt;/code&gt; settings.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;NoInfer&lt;/code&gt; Utility Type
&lt;/h2&gt;

&lt;p&gt;For a long time, there have been situations where you have a generic function with multiple arguments or properties of the same type parameter, but don't want to infer all the types to the generic value. This utility type precisely addresses this issue, providing more control over which types get inferred.&lt;/p&gt;

&lt;p&gt;Let's consider a function that receives a list of values, such as fruits in this example, along with a default value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;defaultValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Example: Without NoInfer&amp;lt;T&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lemon&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// OK&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this example, TypeScript infers the type of result as &lt;code&gt;"apple" | "lemon"&lt;/code&gt; as it should be. But what if we changed our default value to something very different?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lemon&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bomb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Also OK&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Currently, the inferred result is &lt;code&gt;"apple" | "lemon" | "bomb."&lt;/code&gt; But you may wonder, why is that the case? Isn't our &lt;code&gt;"values"&lt;/code&gt; parameter intended to be our source of truth, allowing us to choose an initial value exclusively from there? Indeed, it should be, but a subtle nuance exists. As both share the same generic type, &lt;code&gt;"bomb"&lt;/code&gt; is regarded as a valid inference candidate, akin to the list of values. In simpler terms, TypeScript will infer the values of &lt;code&gt;defaultValue&lt;/code&gt; into the union of fruits &lt;code&gt;T&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One common approach that comes to mind to address this is to add a distinct type parameter that extends our intended type parameter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;defaultValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lemon&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bomb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Error: Argument of type "bomb" is not assignable to parameter of type ("apple" | "lemon")&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This also works but it's a bit more verbose and generic &lt;code&gt;D&lt;/code&gt; most likely won't be used anywhere else in the signature.&lt;/p&gt;

&lt;p&gt;This is where the new utility type &lt;code&gt;NoInfer&lt;/code&gt; comes in. By surrounding our type in &lt;code&gt;NoInfer&amp;lt;...&amp;gt;&lt;/code&gt; , TypeScript will skip to adding the type parameter as a candidate for type inference.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;defaultValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NoInfer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Example: With NoInfer&amp;lt;T&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lemon&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bomb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Error: Argument of type "bomb" is not assignable to parameter of type ("apple" | "lemon")&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By excluding the &lt;code&gt;defaultValue&lt;/code&gt; type, we ensure that whatever is inputted isn't included in the union of values returned or inferred by our function.&lt;/p&gt;

&lt;p&gt;Now previously before this utility type was officially introduced, the community had created a workaround type to combat this issue.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;NoInfer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Albeit it is less efficient in terms of performance compared to the built-in utility type we have today, mainly because of complex types that require deep exploration by TypeScript to find inference candidates. Here is a reference to the &lt;a href="https://github.com/microsoft/TypeScript/issues/14829"&gt;GitHub issue&lt;/a&gt; that prompted this change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap up
&lt;/h2&gt;

&lt;p&gt;To conclude, TypeScript 5.4 Beta introduces substantial improvements, one of which I forgot to mention; &lt;a href="https://devblogs.microsoft.com/typescript/announcing-typescript-5-4-beta/#preserved-narrowing-in-closures-following-last-assignments"&gt;preserved narrowing in closures&lt;/a&gt;. This allows for a more accurate narrowing of types within functions, addressing a common pain point in type-checking. This is just one among several noteworthy changes introduced. For a more comprehensive overview, refer to the &lt;a href="https://devblogs.microsoft.com/typescript/announcing-typescript-5-4-beta"&gt;official release notes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I hope you found this post useful. If you did, please give it a like. 🙂&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Setting up a Monorepo using PNPM workspaces with TypeScript and Tailwind</title>
      <dc:creator>Emmanuel Isenah </dc:creator>
      <pubDate>Fri, 02 Feb 2024 08:57:56 +0000</pubDate>
      <link>https://dev.to/emmanuelisenah/setting-up-a-monorepo-using-pnpm-workspaces-with-typescript-and-tailwind-5611</link>
      <guid>https://dev.to/emmanuelisenah/setting-up-a-monorepo-using-pnpm-workspaces-with-typescript-and-tailwind-5611</guid>
      <description>&lt;p&gt;In this article, We're going learn how to set up a monorepo and share multiple configs and dependencies between each package inside one repository. Before, we proceed, we have to understand what a monorepo is and what benefits it brings to the table.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Monorepo?
&lt;/h2&gt;

&lt;p&gt;A monorepo is a single repository containing multiple distinct projects, with well-defined relationships. It contains different applications or libraries which are somewhat dependent on each other but are logically independent&lt;/p&gt;

&lt;p&gt;At this moment in time, the de facto way of developing applications is having a separate repo for each distinct project, library, or team. It is customary for each repository to have a single build artifact and its dedicated build pipeline. Nevertheless, the industry has gradually gravitated away from this practice, primarily for two significant reasons: &lt;strong&gt;ease of code reuse and desire for team autonomy.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Typically, the common process we reuse code is we publish it as a package to a remote registry like npm. Then, the app dependent on it installs it from the registry as an external dependency and uses the package as it sees fit. However, this approach poses multiple problems.&lt;/p&gt;

&lt;p&gt;First, we have to set up package publishing and tooling with CI environment for the package being shared. But then, we introduce another problem: inconsistent tooling. The shared package will now require its own set of commands for running tests, building, serving, linting, deploying, and so forth. I could go on to provide numerous examples to illustrate how much maintenance overhead and work this will lead to in the long run.&lt;/p&gt;

&lt;p&gt;But this is where monorepo's shine. They can drastically enhance this workflow by eliminating the overhead of publishing versioned packages just so it can be used by other internal projects and eliminating the concept of a breaking change when everything is fixed in the same commit. Let's take a quick dive into how to set one up using PNPM workspaces.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup Root Level Project
&lt;/h2&gt;

&lt;p&gt;The first thing that we need to do is set up our root project which will encapsulate and manage all our applications. We can do so by initializing a pnpm project in our desired folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="s1"&gt;'pnpm-monorepo'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;pnpm-monorepo &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; pnpm init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now our root project has been initialized, we should be able to add necessary root-level dependencies and dotfile configs that we’ll use across our projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  TypeScript
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm add &lt;span class="nt"&gt;-D&lt;/span&gt; typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll start by setting up TypeScript as our initial root-level dependency. Installing it at this level ensures consistency in versioning across all projects. Let's populate our base configuration with the following code:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tsconfig.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ESNext"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lib"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"DOM"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DOM.Iterable"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ESNext"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ESNext"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"skipLibCheck"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"noImplicitAny"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"allowJs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"noErrorTruncation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="err"&gt;/*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Bundler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;mode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*/&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"moduleResolution"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bundler"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"allowImportingTsExtensions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"resolveJsonModule"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"isolatedModules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"noEmit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"jsx"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"react-jsx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="err"&gt;/*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Linting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*/&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"strict"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"noUncheckedIndexedAccess"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"noUnusedLocals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"noUnusedParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"noFallthroughCasesInSwitch"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nl"&gt;"declaration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"composite"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sourceMap"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"declarationMap"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will serve as the default &lt;code&gt;tsc&lt;/code&gt; compiler config shared throughout our project. While it might seem daunting due to the multitude of configurable options, &lt;a href="https://www.totaltypescript.com/tsconfig-cheat-sheet" rel="noopener noreferrer"&gt;Matt Pocock has written a comprehensive piece&lt;/a&gt; explaining the purpose of each property if you're interested.&lt;/p&gt;

&lt;p&gt;Following that, we'll create our &lt;code&gt;tsconfig.node.json&lt;/code&gt; file which will be extended by our base config. This file serves a &lt;a href="https://github.com/vitejs/vite/issues/11396#issuecomment-1474749697" rel="noopener noreferrer"&gt;unique purpose&lt;/a&gt;, acting as a workaround for Vite to omit bundling node types to the browser. If you're utilizing a different framework, you could skip creating this file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"composite"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"skipLibCheck"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ESNext"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"moduleResolution"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bundler"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"allowSyntheticDefaultImports"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's look to set up linting and formatting. For these, we'll be using ESLint and Prettier.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prettier
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm add &lt;span class="nt"&gt;-D&lt;/span&gt; prettier prettier-plugin-tailwindcss
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'{"printWidth": 80, "singleQuote": false}'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .prettierrc.json
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'dist
node_modules
*/*.yml'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .prettierignore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For quality-of-life purposes, let's add a package script to format every project in our codebase.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm pkg &lt;span class="nb"&gt;set &lt;/span&gt;scripts.format&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"prettier --write &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;./**/*.{js,jsx,ts,tsx,json}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ESLint
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm create @eslint/config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ESLint wizard will ask you a set of questions to set up the linter as per your needs. This is the configuration I've chosen for this project.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.eslint.cjs&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;es2021&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;extends&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eslint:recommended&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;plugin:@typescript-eslint/recommended&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;plugin:react/recommended&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;overrides&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.eslintrc.{js,cjs}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;parserOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sourceType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@typescript-eslint/parser&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;parserOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;ecmaVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;latest&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;sourceType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;module&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@typescript-eslint&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, ESLint will look for configuration files in all parent folders up to the root directory. We don't want such behavior so we'll set the &lt;code&gt;root&lt;/code&gt; property to true.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's configure PNPM to use &lt;a href="https://pnpm.io/workspaces" rel="noopener noreferrer"&gt;workspaces&lt;/a&gt; by adding a &lt;code&gt;pnpm-workspace.yaml&lt;/code&gt; file. It serves the purpose of including/excluding directories to be added to our workspace using &lt;a href="https://en.wikipedia.org/wiki/Glob_(programming)" rel="noopener noreferrer"&gt;glob patterns.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pnpm-workspace.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;packages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;apps/*"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;packages/*"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The glob pattern here adds all direct subdirs of our specified folders. To add extra projects, we can do so by simply adding the absolute path of the project to our workspace file.&lt;/p&gt;

&lt;p&gt;At this point, our repository has been set up to use workspaces. Now, let's proceed to create our individual projects.. Our applications will be housed under the &lt;code&gt;apps/&lt;/code&gt; folder and the shared projects will created under &lt;code&gt;packages/.&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a Project
&lt;/h2&gt;

&lt;p&gt;For our applications, I'll be using &lt;a href="https://vitejs.dev/" rel="noopener noreferrer"&gt;Vite&lt;/a&gt; to initialize the projects. Now this can be done using any other JS framework like Next.js, Vue.js, Svelte, etc., and will remain still applicable.&lt;/p&gt;

&lt;p&gt;First, let's create our &lt;code&gt;apps&lt;/code&gt; and &lt;code&gt;packages&lt;/code&gt; directory at the root.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;apps packages
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's init (for this article) our main application by changing our current directory and calling the bash script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;apps
pnpm create vite frontend &lt;span class="nt"&gt;--template&lt;/span&gt; react-ts
&lt;span class="nb"&gt;cd&lt;/span&gt; ../
pnpm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PNPM has a &lt;a href="https://pnpm.io/filtering" rel="noopener noreferrer"&gt;filtering feature&lt;/a&gt; that allows you to restrict commands to specific subsets of packages using a filter tag (&lt;code&gt;--filter&lt;/code&gt;). This will come in handy later on, so let's create one now.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; pnpm pkg &lt;span class="nb"&gt;set &lt;/span&gt;scripts.frontend&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"pnpm --filter @monorepo/frontend"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PNPM follows a workspace naming convention, assigning child projects the format "&lt;code&gt;@root-project-name/project-name&lt;/code&gt;". In our case, our root project name is "&lt;code&gt;monorepo&lt;/code&gt;" so our child project &lt;code&gt;package.json&lt;/code&gt; name would be "&lt;code&gt;@monorepo/frontend&lt;/code&gt;". Let's proceed to make this adjustment in our &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/packages/apps/frontend/package.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="s2"&gt;"name"&lt;/span&gt;: &lt;span class="s2"&gt;"@monorepo/frontend"&lt;/span&gt;
...
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's extend our base &lt;code&gt;tsconfig.json&lt;/code&gt; and &lt;code&gt;tsconfig.node.json&lt;/code&gt; from our root folder.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/apps/frontend/tsconfig.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extends"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"../../tsconfig.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"noEmit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"baseUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"include"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"src"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"references"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./tsconfig.node.json"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Typically, we would enable "&lt;code&gt;noEmit&lt;/code&gt;" in our config to prevent TypeScript compiler from generating transpiled code, as this task is managed by our bundler, Vite. However, this is not a concern thanks to our base config.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/apps/frontend/tsconfig.node.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extends"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"../../tsconfig.node.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"include"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"vite.config.ts"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're done setting up our main application at this point. If you have any extra dotfile configurations, feel free to extend them too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create Shared Package
&lt;/h2&gt;

&lt;p&gt;Let's create an extra project to share some code across our applications or even other shared packages. The project is going to be built as an external library with declaration files bundled together.&lt;/p&gt;

&lt;p&gt;Let's create the project by running these commands from our root directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;packages
pnpm create vite ui &lt;span class="nt"&gt;--template&lt;/span&gt; react-ts
&lt;span class="nb"&gt;cd &lt;/span&gt;ui/src
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; assets App.tsx App.css ../.eslintrc.&lt;span class="k"&gt;*&lt;/span&gt;
pnpm &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="nb"&gt;install
&lt;/span&gt;pnpm &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; pnpm pkg &lt;span class="nb"&gt;set &lt;/span&gt;scripts.ui&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"pnpm --filter @monorepo/ui"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;TIP: When executing commands for the root project while working within a child project, you can use the '--workspace-root' flag or its shorthand '-w' to prevent changing directories. For example, 'pnpm -w run frontend dev' will spin up the dev server for our frontend app while within the 'ui' working directory.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's change the name of our project to match naming previous naming convention and also extend our &lt;code&gt;tsconfig.json&lt;/code&gt; and &lt;code&gt;tsconfig.node.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/packages/apps/ui/package.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@monorepo/ui"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;/packages/apps/ui/tsconfig.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extends"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"../../tsconfig.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"include"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"src"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"references"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./tsconfig.node.json"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;/packages/apps/ui/tsconfig.node.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extends"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"../../tsconfig.node.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"include"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"vite.config.ts"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, Vite builds our assets in app mode using &lt;code&gt;index.html&lt;/code&gt; as the entry file. However, we intend to build our app in library mode and expose the &lt;code&gt;main.ts&lt;/code&gt; file as the entry point for our package. Let's proceed to modify the Vite configuration to accommodate this. Also while we're at it, we'll install a Vite plugin to auto-generate declaration files for our library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm ui add &lt;span class="nt"&gt;-D&lt;/span&gt; vite-plugin-dts @types/node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;/packages/ui/vite.config.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vite&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;dts&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vite-plugin-dts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// https://vitejs.dev/config/&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;lib&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;src/main.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;formats&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;es&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;dts&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With all this finally out of the way, let's create an example component.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/packages/ui/src/components/Button.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ButtonProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ComponentProps&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;ButtonProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's now export it out of our main entry file.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/packages/ui/main.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./components/Button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll be finished creating our library once we update the &lt;code&gt;package.json&lt;/code&gt; file with the entry file and type declarations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dist/ui.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"types"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dist/src/main.d.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;NOTE: The output name for 'main' property is based on your application, whereas the type declaration output name is derived from your entry filename.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We now have a basic functional component named &lt;code&gt;Button&lt;/code&gt; that accepts all possible props a button could have, in addition to a &lt;code&gt;children&lt;/code&gt; prop for displaying content.&lt;/p&gt;

&lt;p&gt;Let's head back to our main application and import our &lt;code&gt;ui&lt;/code&gt; package. First, we have to install the library under &lt;code&gt;monorepo/@frontend&lt;/code&gt; using the workspace filter command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm frontend add @monorepo/ui
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;NOTE: By default, when we try to install a package, pnpm will always try to link the package from our workspace based on the declared range. This wasn't always the case before; if the range wasn't matched, it would install the package from the npm registry. With the "&lt;code&gt;workspace:&lt;/code&gt;" protocol, pnpm will refuse to resolve to anything other than a local workspace package.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Inside the &lt;code&gt;@frontend&lt;/code&gt; application, our &lt;code&gt;package.json&lt;/code&gt; should look similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@monorepo/ui"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"workspace:^"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"react"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^18.2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"react-dom"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^18.2.0"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, let's build our &lt;code&gt;@ui&lt;/code&gt; library. We can't import anything if there's no output artifact to begin with.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm ui build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it, now we should be able to import our components or whatever is exported from the &lt;code&gt;ui&lt;/code&gt; package.&lt;/p&gt;

&lt;p&gt;If you remember, we created a button component in the &lt;code&gt;ui&lt;/code&gt; package. Let's render that button inside our &lt;code&gt;frontend&lt;/code&gt; application:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/apps/frontend/src/App.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@monorepo/ui&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt;
      &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
        &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;10px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;Hello&lt;/span&gt; &lt;span class="nx"&gt;World&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we spin up our dev server and visit our localhost in our browser, we'll see a blue button rendered, saying 'Hello World'."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1706803966940%2Fe379d406-f5e4-4a06-9f45-84a067a0ca44.png%2520align%3D" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1706803966940%2Fe379d406-f5e4-4a06-9f45-84a067a0ca44.png%2520align%3D"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Dev Mode
&lt;/h2&gt;

&lt;p&gt;Everything works with the current setup but it's highly inefficient. There are currently two problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;We have to manually rebuild our dependency packages each time a change is made to them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We have to restart our server each time when the former is performed.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To address the initial problem, we'll establish a development script to build our &lt;code&gt;ui&lt;/code&gt; package in watch mode.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/packages/ui/package.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vite build --watch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additionally, we'll create a root-level script to execute the "&lt;code&gt;dev&lt;/code&gt;" script across all packages in our workspace recursively, as specified in their package.json.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/package.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scripts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dev&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pnpm --recursive --parallel --stream run dev&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;TIP: To selectively run a script for a package and its dependencies only, suffix an ellipsis to the package name (&lt;code&gt;&amp;lt;package_name&amp;gt;...&lt;/code&gt;) with the &lt;code&gt;--filter&lt;/code&gt; flag. For instance, if building for production, use: &lt;code&gt;pnpm --filter @monorepo/frontend... build&lt;/code&gt;. This will build the specified package (&lt;code&gt;@monorepo/frontend&lt;/code&gt;) and also its dependencies in the workspace.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To fix the second issue, we're going to have to configure an alias in the &lt;code&gt;vite.config.ts&lt;/code&gt; of the &lt;code&gt;@frontend&lt;/code&gt; app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="p"&gt;...,&lt;/span&gt;
  &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@monorepo/ui&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../packages/ui/src/main.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By adding our &lt;code&gt;ui&lt;/code&gt; package as an alias, it forces Vite to hot reload whenever the build artifact changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: Add Tailwind Support
&lt;/h2&gt;

&lt;p&gt;To establish a single source of truth for all Tailwind configurations, we'll create an additional project for this purpose under the "&lt;code&gt;/packages&lt;/code&gt;" directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cd&lt;/span&gt; &lt;span class="nx"&gt;packages&lt;/span&gt;
&lt;span class="nx"&gt;mkdir&lt;/span&gt; &lt;span class="nx"&gt;tailwind&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;cd&lt;/span&gt; &lt;span class="nx"&gt;tailwind&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;pnpm&lt;/span&gt; &lt;span class="nx"&gt;init&lt;/span&gt;
&lt;span class="nx"&gt;touch&lt;/span&gt; &lt;span class="nx"&gt;tailwind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt; &lt;span class="nx"&gt;postcss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt;
&lt;span class="nx"&gt;pnpm&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;D&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="nx"&gt;tailwindcss&lt;/span&gt; &lt;span class="nx"&gt;postcss&lt;/span&gt; &lt;span class="nx"&gt;autoprefixer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update the project name to match previously used naming convention.&lt;br&gt;&lt;br&gt;
&lt;code&gt;/packages/tailwind/package.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@monorepo/tailwind"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the paths to all of our HTML templates, JS components, and any other files that contains Tailwind class names in the &lt;code&gt;tailwind.config.js&lt;/code&gt; file. In order for Tailwind to generate all of the CSS we need, it needs to know about every single file in our project that contains any Tailwind class names.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/packages/tailwind/tailwind.config.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/** @type {import('tailwindcss').Config} */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./index.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../packages/**/src/**/*.{html,js,ts,jsx,tsx}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./src/**/*.{html,js,ts,jsx,tsx}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add &lt;code&gt;tailwindcss&lt;/code&gt; and &lt;code&gt;autoprefixer&lt;/code&gt; property to our &lt;code&gt;postcss.config.js&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/packages/tailwind/postcss.config.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;tailwindcss&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
    &lt;span class="na"&gt;autoprefixer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add &lt;code&gt;@monorepo/tailwind&lt;/code&gt; package to the &lt;code&gt;frontend&lt;/code&gt; application&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm &lt;span class="nt"&gt;-w&lt;/span&gt; frontend add &lt;span class="nt"&gt;-D&lt;/span&gt; @monorepo/tailwind
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Re-export default Tailwind config from &lt;code&gt;tailwind&lt;/code&gt; package&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/apps/frontend/tailwind.config.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@monorepo/tailwind/tailwind.config.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Re-export default PostCSS config from &lt;code&gt;tailwind&lt;/code&gt; package&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/apps/frontend/postcss.config.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@monorepo/tailwind/postcss.config.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the Tailwind directives to our CSS&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/apps/frontend/src/index.css&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;tailwind&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;tailwind&lt;/span&gt; &lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;tailwind&lt;/span&gt; &lt;span class="nx"&gt;utilities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's update our button component to use Tailwind class&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/apps/frontend/src/App.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bg-yellow-500&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Hello&lt;/span&gt; &lt;span class="nx"&gt;World&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Button&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without restarting our server, we should see our button background should now be yellow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1706811607344%2Fa2aeaf49-1a7b-43ec-ba97-ee3ada97033a.png%2520align%3D" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1706811607344%2Fa2aeaf49-1a7b-43ec-ba97-ee3ada97033a.png%2520align%3D"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;And there you have it! We've covered the basics of setting up a monorepo using PNPM workspaces. Additionally, we've explored configuring a project in library mode using Vite and adding Tailwind support. Embracing a monorepo approach changes our perspective on how we organize code, reducing barriers to creating new projects and promoting efficient code sharing.&lt;/p&gt;

&lt;p&gt;If you're interested in exploring the finalized code from the blog, here is the &lt;a href="https://github.com/Armadillidiid/pnpm-monorepo-demo" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thank you for reading! If you got up to this point, please consider following for more upcoming blogs.&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
