<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Junsu Park</title>
    <description>The latest articles on Forem by Junsu Park (@junsupark).</description>
    <link>https://forem.com/junsupark</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%2F813150%2Fdf790b83-ec45-430b-8fb4-fa1bd6b92050.jpeg</url>
      <title>Forem: Junsu Park</title>
      <link>https://forem.com/junsupark</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/junsupark"/>
    <language>en</language>
    <item>
      <title>My 2023 Web Development Highlights</title>
      <dc:creator>Junsu Park</dc:creator>
      <pubDate>Wed, 27 Dec 2023 21:53:35 +0000</pubDate>
      <link>https://forem.com/junsupark/my-2023-web-development-highlights-4n0e</link>
      <guid>https://forem.com/junsupark/my-2023-web-development-highlights-4n0e</guid>
      <description>&lt;p&gt;Web technology is constantly evolving and new front end libraries and frameworks are constantly being released. New primitives, improved developer experience, and so many headless UI libraries. It’s hard to keep up sometimes. Let me make that easier for you by sharing my highlights from this year.&lt;/p&gt;

&lt;h3&gt;
  
  
  CSS - :has selector
&lt;/h3&gt;

&lt;p&gt;The Chrome Team has written a &lt;a href="https://developer.chrome.com/blog/css-wrapped-2023"&gt;beautiful blog post&lt;/a&gt; that lists all the changes that CSS had this year. Go check it out and skim through it at least.&lt;/p&gt;

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

&lt;p&gt;What I (and everyone else) loved and would probably use the most is the new :has selector. You can now style the parent element based on some condition present in its child elements without JavaScript. For example, give it a background color if a child element is an input and has the :checked state.&lt;/p&gt;

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

&lt;p&gt;From &lt;a href="https://www.youtube.com/watch?v=CLkxRnRQtDE&amp;amp;t=1209s"&gt;Tailwind Connect 2023 Keynote&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or as &lt;a href="https://twitter.com/WebIsBae"&gt;Web Bae&lt;/a&gt; has demonstrated, create a &lt;a href="https://twitter.com/WebIsBae/status/1737897643458597341"&gt;CSS-only dark mode toggle&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fggcld1tx0uk22w2kmuxi.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fggcld1tx0uk22w2kmuxi.gif" alt="CSS-only dark mode toggle" width="1232" height="720"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I love when CSS adds features that usually required workarounds in JavaScript. Speaking of which…&lt;/p&gt;

&lt;h3&gt;
  
  
  HTML - Exclusive Accordion
&lt;/h3&gt;

&lt;p&gt;Sadly there’s no pretty blog post detailing all the changes to HTML like the CSS one had. In fact, I had a hard time figuring out when certain things were released. There is this &lt;a href="https://survey.devographics.com/en-US/survey/state-of-html/2023/outline/1"&gt;State of HTML 2023 Survey&lt;/a&gt; that asks people about their familiarity with the newer features and changes. The survey is over and I recommend perusing it because I learned a lot.&lt;/p&gt;

&lt;p&gt;For example, I did not know you make an accordion element by wrapping the  element around  elements.&lt;/p&gt;

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

&lt;p&gt;The survey has not been updated because it says no browser has implemented the exclusive accordion yet. But as of &lt;a href="https://developer.chrome.com/docs/css-ui/exclusive-accordion"&gt;Chrome 120, it is&lt;/a&gt;! Just give the  the same name, and voila! The behavior that required JavaScript is now native to HTML.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  JavaScript - new array methods
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://tc39.es/ecma262/2023/"&gt;new ECMAScript 14&lt;/a&gt; came out this year and I would love to check it out but it kills my browser every time I try to load it. So instead I relied on reading blog posts about it. Please check them out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.infoworld.com/article/3703571/all-the-new-features-in-ecmascript-2023-es14.html"&gt;Info World&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thenewstack.io/the-new-javascript-features-coming-in-ecmascript-2023/"&gt;The New Stack&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main highlight are new array methods. These include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;findLast&lt;/li&gt;
&lt;li&gt;findLastIndex&lt;/li&gt;
&lt;li&gt;toReversed&lt;/li&gt;
&lt;li&gt;toSorted&lt;/li&gt;
&lt;li&gt;toSpliced&lt;/li&gt;
&lt;li&gt;with&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last 4 allow you to change array by copy, which follows the same behavior as .map and .filter, resulting in less confusion and also following functional programming patterns. And according to MDN, all these methods have already been implemented by browsers!&lt;/p&gt;

&lt;h3&gt;
  
  
  Web APIs - View Transitions API
&lt;/h3&gt;

&lt;p&gt;I’d describe Web APIs as a set of standardized features and behaviors that are implemented through a combination of HTML, CSS, JavaScript, and browser APIs. And &lt;a href="https://developer.chrome.com/docs/web-platform/view-transitions"&gt;View Transitions API&lt;/a&gt; is a great example of that.&lt;/p&gt;

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

&lt;p&gt;This API allows you to seamlessly transition between &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API"&gt;“different DOM states while also updating the DOM contents in a single step”&lt;/a&gt;. Such behavior that would have required complicated and verbose CSS and JavaScript is now available in the DOM. Furthermore, the transitions can be controlled by JavaScript and CSS.&lt;/p&gt;

&lt;p&gt;This API has been implemented by Chrome but is still being worked on by the W3C. Still, its current state is quite exciting already.&lt;/p&gt;

&lt;h3&gt;
  
  
  UI Component Libraries - ShadCN
&lt;/h3&gt;

&lt;p&gt;I wrote an &lt;a href="https://www.linkedin.com/pulse/accessibility-headless-ui-libraries-adobe-radix-tailwind-junsu-park/?trackingId=6Zg3KTLQSzmYcE5Dw4V2wA%3D%3D"&gt;article about headless UI libraries&lt;/a&gt; so feel free to skim that to get up to date.&lt;/p&gt;

&lt;p&gt;On Dec. 20th, React Aria has updated their &lt;a href="https://react-spectrum.adobe.com/react-aria/"&gt;landing page&lt;/a&gt; for the &lt;a href="https://react-spectrum.adobe.com/releases/2023-12-20.html"&gt;GA release of React Aria Components&lt;/a&gt;, which is built on top of React Aria hooks. &lt;/p&gt;

&lt;p&gt;Also on Dec 20th, Lemon Squeezy released &lt;a href="https://www.lemonsqueezy.com/wedges"&gt;Wedges&lt;/a&gt;, which is built on &lt;a href="https://www.radix-ui.com/primitives"&gt;Radix UI&lt;/a&gt; and &lt;a href="https://tailwindcss.com/"&gt;Tailwind&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Then on Dec 22nd, shadcn also updated &lt;a href="https://ui.shadcn.com/"&gt;shadcn/ui&lt;/a&gt;, adding the following &lt;a href="https://ui.shadcn.com/docs/changelog"&gt;new components&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drawer&lt;/li&gt;
&lt;li&gt;Carousel&lt;/li&gt;
&lt;li&gt;Pagination&lt;/li&gt;
&lt;li&gt;Toast&lt;/li&gt;
&lt;li&gt;Resizable&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Before, I was team React Aria. But as time went on, I have to say shadcn has outdone everyone. It has more components than the others and are very easy to use. The copy-paste approach that allows your codebase to own the component code instead of relying on an external package and have full control over it is really what won me over. And since copy-pasting manually is tiring, the CLI does all that work for you. And it works amazingly well. There’s a reason he was hired at Vercel.&lt;/p&gt;

&lt;p&gt;I still have to try out Wedges, but for 2023, shadcn/ui was the clear winner. &lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;So these were the highlights of 2023 for me. I need to take some time and tinker around with all these new features and updates to really solidify them in my head. &lt;/p&gt;

&lt;p&gt;I thought about writing about my highlight for UI framework (React, Svelte, Vue, Solid, etc) and metaframework (Next.js, SvelteKit, Nuxt, SolidStart, etc) but I need more time with all of them. Though two things stood out to me as they gained more adoption by these frameworks: &lt;strong&gt;signals&lt;/strong&gt; and &lt;strong&gt;server actions&lt;/strong&gt;. Once I have enough experience and wisdom (ie. read the opinions of people way smarter than me), I'll share mine.&lt;/p&gt;

&lt;p&gt;All in all, I’m excited for what 2024 has to offer. Let me know what your highlights were!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>css</category>
    </item>
    <item>
      <title>4 Things I Have Read That Are Good for Web Devs</title>
      <dc:creator>Junsu Park</dc:creator>
      <pubDate>Thu, 16 Nov 2023 00:32:42 +0000</pubDate>
      <link>https://forem.com/junsupark/4-things-i-have-read-that-are-good-for-web-devs-lke</link>
      <guid>https://forem.com/junsupark/4-things-i-have-read-that-are-good-for-web-devs-lke</guid>
      <description>&lt;p&gt;I usually write about what I made and learned, but this time, I wanted to share knowledge I gained from other people. I think these 3 articles and 1 documentary will help you become a better web developer.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.joshwcomeau.com/css/rules-of-margin-collapse/"&gt;Rules of Margin Collapse&lt;/a&gt; by &lt;a href="https://twitter.com/JoshWComeau"&gt;Josh Comeau&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;CSS rules are &lt;del&gt;frustrating&lt;/del&gt; are a nightmare. What is even more frustrating are behaviors that are not well documented. One of these are CSS margins. Here’s an example: did you know margins only collapse vertically?&lt;/p&gt;

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

&lt;p&gt;Thankfully, Josh Comeau has written all the weird arbitrary rules that margins have. I personally won’t be using margin unless it’s for one-off spacing that Flexbox gap wouldn’t work for.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;a href="https://tkdodo.eu/blog/the-uphill-battle-of-memoization"&gt;The Uphill Battle of Memoization&lt;/a&gt; by &lt;a href="https://twitter.com/tkdodo"&gt;TkDodo&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;React re-renders are hard to tame. Any state change in a component will propagate re-renders to all its children components. You may already know some ways to isolate re-renders:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Move state down

&lt;ol&gt;
&lt;li&gt;If state can’t be moved down, use a global state management with atomic picks to isolate re-renders&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;Pass the component as a prop or children&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There’s also React.memo but TkDodo warns against using it for very good reasons. For example, using inline props can easily break it since inline functions and objects are recreated when the component re-renders.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;a href="https://planetscale.com/docs/learn/operating-without-foreign-key-constraints#how-does-your-schema-look-without-foreign-key-constraints"&gt;Operating without Foreign Key Constraints&lt;/a&gt; by Planetscale
&lt;/h3&gt;

&lt;p&gt;This article is from the Planetscale’s documentation, which is a MySQL serverless database service. Planetscale explains it doesn’t support foreign key constraints because it interferes with Online DDL operations and it becomes harder to maintain over multiple database servers. By enforcing referential integrity at the application level instead of at the database level, Planetscale can benefit from online DDL and unlimited scaling through sharding.&lt;/p&gt;

&lt;p&gt;Initially I thought this was a weird approach but I agreed with it after reading through the page. I love it when developers rethink best practices.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;a href="https://www.youtube.com/watch?v=8pDqJVdNa44"&gt;How a Small Team of Developers Created React at Facebook | React.js: The Documentary&lt;/a&gt; by Honeypot
&lt;/h3&gt;

&lt;p&gt;Speaking of rethinking best practices, this 76 minute documentary goes into the origin and early public reception to React when it was released as open source. &lt;a href="https://youtu.be/8pDqJVdNa44?t=2208"&gt;The initial reception was extremely negative&lt;/a&gt;; people hated JSX and thought React broke separation of concerns.&lt;/p&gt;

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

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

&lt;p&gt;Thankfully, early adopters started using React, few in production, and an open source community quickly grew around React, which the React team cultivated by fixing bugs, releasing new features, and organizing meetups. I found this documentary inspiring for two reasons. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I’m now a full stack engineer with a year of professional experience under my belt and I have spent almost all of my time deferring to other people’s opinions on how things should be built. And I should since I don’t know much. But now as I gain more experience, I am starting to become more opinionated. And the fact that traditional best practices have been broken and innovated upon gives me confidence to experiment and try out new approaches.&lt;/li&gt;
&lt;li&gt;The strength of the open source community makes me want to contribute to open source projects. I think it’s beautiful to see really smart people passionately work together for no compensation just because they love building cool things. And I want to be part of that.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>frontend</category>
      <category>fullstack</category>
    </item>
    <item>
      <title>Next.js 14</title>
      <dc:creator>Junsu Park</dc:creator>
      <pubDate>Tue, 07 Nov 2023 04:11:17 +0000</pubDate>
      <link>https://forem.com/junsupark/nextjs-14-cca</link>
      <guid>https://forem.com/junsupark/nextjs-14-cca</guid>
      <description>&lt;p&gt;I attended the Next.js Conference 2023 in person and I had a great time listening to the talks, talking to people way smarter than me, and getting free food and swag. The main theme of the conference seemed to be about getting people to transition from the Pages Router to the App Router. I already use and love the App Router so I did not learn much from those kinds of talks.&lt;/p&gt;

&lt;p&gt;If you are still on the fence about App Router and React Server Components, then I recommended watching &lt;a href="https://www.youtube.com/watch?v=9CN9RCzznZc"&gt;this talk&lt;/a&gt; by &lt;a href="https://twitter.com/samselikoff"&gt;Sam Selikoff&lt;/a&gt;, who gives great talk that explains how these features execute React’s goal of composable UI.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.youtube.com/watch?v=gfU1iZnjRZM"&gt;keynote about Next.js 14&lt;/a&gt; by &lt;a href="https://twitter.com/rauchg"&gt;Guillermo Rauch&lt;/a&gt; was great. This major release is focused on improving current features and aiming for stability. You can read the &lt;a href="https://nextjs.org/blog/next-14"&gt;official blog post here&lt;/a&gt; for more in-depth read. I am excited that &lt;strong&gt;&lt;a href="https://nextjs.org/docs/app/building-your-application/data-fetching/forms-and-mutations"&gt;Server Actions&lt;/a&gt;&lt;/strong&gt; are now stable and am looking forward &lt;strong&gt;Partial Prerendering&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Server Actions
&lt;/h3&gt;

&lt;p&gt;First off, if you don’t know what &lt;a href="https://nextjs.org/docs/app/building-your-application/rendering/server-components"&gt;React Server Components&lt;/a&gt; are, I suggest reading up on it before continuing. I also wrote an &lt;a href="https://www.linkedin.com/pulse/learning-nextjs-react-full-stack-features-junsu-park/"&gt;article about it and NextJS features&lt;/a&gt;, including Server Actions, with lot of simple examples and pictures.&lt;/p&gt;

&lt;p&gt;Server Actions allows you to invoke server functions from the client without needing to explicitly define an API endpoint and write a request to that endpoint. NextJS will handle all of that for you.  You can also send data from the client to the server function.Simply mark a function with “use server” at the top and everything inside will only live and execute on the server.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm87663qfgsq9qqeo9ao2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm87663qfgsq9qqeo9ao2.png" alt="Converting API endpoint and client-side request into Server Action" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There were people pushing back on Server Actions with the usual worry about separation of concerns, which is expected whenever &lt;a href="https://youtu.be/8pDqJVdNa44?t=2439"&gt;React does anything&lt;/a&gt;. I agree with what React and NextJS is doing - concerns should be component based. I personally believe this improves DX through easier mental models and improved code maintainability. All the code required to render some piece of UI will all be in one file (especially if you use CSS utility libraries like Tailwind). &lt;/p&gt;

&lt;p&gt;Other frameworks also have ways of defining server-only code, such as &lt;a href="https://start.solidjs.com/api/server"&gt;Solid&lt;/a&gt; and &lt;a href="https://qwik.builder.io/docs/server$/"&gt;Qwik&lt;/a&gt;. And I’m excited to see how this new paradigm grows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Partial Prerendering
&lt;/h3&gt;

&lt;p&gt;I recently wrote a &lt;a href="https://www.linkedin.com/pulse/server-side-rendering-whats-ssr-ssg-isr-build-time-request-junsu-park"&gt;basic summary of server side rendering&lt;/a&gt;, and in it, I talk about the difference between build time - more accurately, ahead of time - and request time. There was one thing I did not mention for sake of conciseness which is that it’s all or nothing. If your page was static but had just one tiny part that needed to be dynamically rendered, you either had to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pre-render it all at request time&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpi4bjgv5t5lb4y0320xe.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpi4bjgv5t5lb4y0320xe.jpg" alt="Visual of traditional server-side rendering" width="800" height="602"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6mn68ok6of96lh1jjrob.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6mn68ok6of96lh1jjrob.jpg" alt="Rating traditional server-side-rendering with slow initial visual" width="800" height="602"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Or pre-render everything else ahead of time and make the client fetch the dynamic data and render it themselves.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fytmn4s7ws6ridisb2p0k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fytmn4s7ws6ridisb2p0k.png" alt="Rating static + client fetch with slow dynamic visual" width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What if there was a way to render all the static content, such as the navbar and footer, ahead of time? All the static content will be served immediately when the client makes a request. Then the dynamic content, such as product information, can be rendered and streamed in later. Partial prerendering is exactly that.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5dsdc0o4nkj6rhn73e3s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5dsdc0o4nkj6rhn73e3s.png" alt="Rating partial prerendering with fast initial visual and fast dynamic visual" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No waterfalls. No new API - this is all done through React Suspense.&lt;/p&gt;

&lt;p&gt;This feature is not released yet but I’m very excited to try it out.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Next.js is an already amazing production-grade framework with great developer experience and it keeps outdoing itself with every release. They fully enable React to be used to its fullest extent in the easier manner possible. And I can’t wait to see what comes next.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>frontend</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Highlights from ViteConf 2023</title>
      <dc:creator>Junsu Park</dc:creator>
      <pubDate>Sun, 22 Oct 2023 16:40:53 +0000</pubDate>
      <link>https://forem.com/junsupark/highlights-from-viteconf-2023-35j4</link>
      <guid>https://forem.com/junsupark/highlights-from-viteconf-2023-35j4</guid>
      <description>&lt;p&gt;I spent 12 hours watching &lt;a href="https://viteconf.org/23/"&gt;ViteConf 2023&lt;/a&gt; talks to learn lot of cool new things about web dev, open source softwares, and front end technology. You can find the &lt;a href="https://viteconf.org/23/schedule"&gt;list of talks here&lt;/a&gt;. I became aware of so many amazing web dev tools and frameworks to improve developer experience. I’m going to highlight the talks I personally found most interesting.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.youtube.com/watch?v=jcpkVJr-rUw"&gt;Stop Writing Docs; Start Helping&lt;/a&gt; by &lt;a href="https://twitter.com/sarah11918"&gt;Sarah Rainsberger&lt;/a&gt; - Docs Lead at Astro
&lt;/h3&gt;

&lt;p&gt;Sarah talks about how to write great docs with many concrete examples and advices. I think this talk is beneficial to everyone because great docs is how you get people to use your software. “Write less, help more” is the central idea of the talk. I screenshotted some slides with great advice.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa26mbrdkw8ow92z7wap0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa26mbrdkw8ow92z7wap0.png" alt="Delete outdated, misleading, incorrect info from your doc" width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc5e1buiicm79l1kcnr1q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc5e1buiicm79l1kcnr1q.png" alt="Your job is not to excite the user or make jokes" width="800" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.youtube.com/watch?v=NJbCfAKtxUI"&gt;Road to Open Source: The Set Theory&lt;/a&gt; by &lt;a href="https://twitter.com/antfu7"&gt;Anthony Fu&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Anthony Fu talks about converting OOS that work universally instead of one specific use case or software.&lt;/p&gt;

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

&lt;p&gt;Anthony and his collaborators talks about building tools in Nuxt that allow server functions of apps - server side rendering and server APIs -  to to work with specific features of cloud providers, such as edge rendering and serverless functions. The tool auto detects each platform and allows apps to be written isomorphically.&lt;/p&gt;

&lt;p&gt;They realized this is a problem every metaframework has to deal with and is not specific to Nuxt. So they extracted those tools into a standard tool called Nitro - a universal server builder. With Nitro taking care of the details of dealing with servers, it actually allows Nuxt to have more clear architecture for handling server side rendering, APIs, etc.&lt;/p&gt;

&lt;p&gt;Now Nitro has been adopted by other metaframeworks such as Analog and Stacks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3a3apgo0e3lg9rlrnou7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3a3apgo0e3lg9rlrnou7.png" alt="Unplugin is a universal plugin interface for bundlers such as Webpack and Vite" width="800" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Similarly, they built first-party integrations to allow Nuxt to be compatible with Webpack and Vite for bundling. However, the architecture and plugin ecosystem are quite different. For example, if you want to add some transformation to some modules in the pipeline, that would require implementing the logic twice for each-plugin. That doubles the work as well as the effort for community modules to support it.&lt;/p&gt;

&lt;p&gt;Thus they created unplugin, a universal plugin interface, that now has its own community and expanded the scope to support Rollup, Esbuild, and potentially more in the future.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  &lt;a href="https://www.youtube.com/watch?v=bvSlEweRyjE"&gt;Qwik: Performance is a Human Design Issue&lt;/a&gt; by &lt;a href="https://twitter.com/manucorporat"&gt;Manu Martinez-Almeida&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Manuel explains performance differences between frameworks thoroughly and concisely with great visuals. He shows how Qwik is the first O(1) framework with regards to hydration. I highly recommend watching the whole thing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1p6cchn2fz2puvibvceu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1p6cchn2fz2puvibvceu.png" alt="Qwik is the first O(1) framework" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

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

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

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

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

&lt;p&gt;Qwik does not ship any JavaScript initially. Everything is static. When you click on an interactive component, then the browser will download the JavaScript. This is called &lt;a href="https://qwik.builder.io/docs/concepts/resumable/"&gt;Resumability&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft2x01pi4w8vi7depz1h1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft2x01pi4w8vi7depz1h1.png" alt="Chrome Dev Tools Network tab shows no Javascript downloaded" width="800" height="546"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv1zkd8x8o2bzz84lhift.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv1zkd8x8o2bzz84lhift.png" alt="Clicking a button triggers the download allowing for interactivity" width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;I’m definitely going to try out Qwik for its unique hydration approach. Also it’s re-rendering approach is interesting as well, somewhere between React and Solid - solving for performance and mental overhead. I recommend reading this &lt;a href="https://medium.com/@mprasanthk27/signals-in-solidjs-vs-qwik-js-df81872af3e4"&gt;article about Qwik’s Signals&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I’m also going to NextJS conference on 10.26.2023 and I’ll share what I learned from that as well. Follow me on &lt;a href="https://www.linkedin.com/in/junsupark-swe/"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://dev.to/junsupark94"&gt;DEV&lt;/a&gt; for more updates about web dev and full stack engineering!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Server Side Rendering: what’s SSR, SSG, ISR, build time, request time, hydration mismatch?</title>
      <dc:creator>Junsu Park</dc:creator>
      <pubDate>Fri, 20 Oct 2023 20:40:45 +0000</pubDate>
      <link>https://forem.com/junsupark/server-side-rendering-whats-ssr-ssg-isr-build-time-request-time-hydration-mismatch-3gh9</link>
      <guid>https://forem.com/junsupark/server-side-rendering-whats-ssr-ssg-isr-build-time-request-time-hydration-mismatch-3gh9</guid>
      <description>&lt;p&gt;You may have heard about server side rendering and may be bit confused by all these terms being thrown around. And is this related to React server components? (No, kind of, but not really).&lt;/p&gt;

&lt;p&gt;Here’s a brief and maybe bit oversimplified explainer on what all these concepts mean.&lt;/p&gt;

&lt;h3&gt;
  
  
  Server Side Rendering
&lt;/h3&gt;

&lt;p&gt;Client side rendering sucks 👎 Why?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Poor initial page load - big bundle and rendering takes time&lt;/li&gt;
&lt;li&gt;Poor SEO - web crawlers only get blank HTML&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Solution? Make server do most or all of the work. 👍&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fast initial page load&lt;/li&gt;
&lt;li&gt;Great SEO - web crawlers get HTML with content&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I will refer to server side rendering as ****&lt;strong&gt;&lt;em&gt;pre-rendering&lt;/em&gt;&lt;/strong&gt;**** also. The terms are synonymous; the pre-rendering generates HTML before the client, and the computer this happens in is the server. Pre-rendering is also a less ambiguous term since SSR can have a different meaning (explained below).&lt;/p&gt;

&lt;p&gt;Question: when should the server do the rendering work? Initially when the server starts or when the client makes a request?&lt;/p&gt;

&lt;h3&gt;
  
  
  Build Time or Static Site Generation (SSG)
&lt;/h3&gt;

&lt;p&gt;(Also called static rendering)&lt;/p&gt;

&lt;p&gt;This is when the server starts up and pre-renders all the pages by creating all the HTML files and Javascript bundles - the content - beforehand.&lt;/p&gt;

&lt;p&gt;This is great for content that will not change:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Portfolios&lt;/li&gt;
&lt;li&gt;Marketing pages&lt;/li&gt;
&lt;li&gt;Documentations&lt;/li&gt;
&lt;li&gt;E-commerce product listings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fijd2npb3myt37yzm7evy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fijd2npb3myt37yzm7evy.png" alt="Apple homepage" width="800" height="504"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Sites like Apple changes every few months or so, which is perfect for SSG&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If a page requires dynamic data, such as updating the stock of a product, that can be done through client-side data fetching. The stock count will not be in the pre-rendered HTML but information like this can be excluded without impacting SEO or performance.&lt;/p&gt;

&lt;p&gt;If the page can be pre-rendered ahead of the user’s request, then this approach works.&lt;/p&gt;
&lt;h3&gt;
  
  
  Request Time or Server Side Rendering (SSR)
&lt;/h3&gt;

&lt;p&gt;What if the page ***&lt;strong&gt;&lt;em&gt;can’t&lt;/em&gt;&lt;/strong&gt;*** be pre-rendered ahead of client’s request? For example, take the home page of news sites such as New York Times, Los Angeles Times, etc. There will be new stories to display throughout the day. And if the user has an account and selected their preferences for topics, then the home page will have to be modified in regards to that as well.&lt;/p&gt;

&lt;p&gt;Thus any pre-rendered content will likely be outdated by the time the client makes a request. &lt;/p&gt;

&lt;p&gt;Hence, pre-rendering at request time. Also called dynamic rendering or server side rendering (Yes, it’s a bit confusing how developers reuse the same term to mean different things. Looking at you, NextJS docs 😠). &lt;strong&gt;Note&lt;/strong&gt;: I don’t know what those sites do, this is just an example of where request time pre-rendering can apply.&lt;/p&gt;
&lt;h3&gt;
  
  
  Incremental Static Regeneration (ISR)
&lt;/h3&gt;

&lt;p&gt;Well, pre-rendering every time the user makes a request can be costly. The news probably has not changed significantly within a minute. And if it did, they can wait and go touch grass.&lt;/p&gt;

&lt;p&gt;Thus the concept of ISR: pre-render the page again at intervals.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Let’s say interval is X seconds&lt;/li&gt;
&lt;li&gt;Client makes a request&lt;/li&gt;
&lt;li&gt;Server pre-renders the content, caches it, and sends the content to the client&lt;/li&gt;
&lt;li&gt;Client makes a request within X seconds&lt;/li&gt;
&lt;li&gt;Server sends cached content&lt;/li&gt;
&lt;li&gt;Client makes a request after X seconds&lt;/li&gt;
&lt;li&gt;Server invalidates cached content, pre-renders, caches, and sends content&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw6gr743398hrlhy8tsw6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw6gr743398hrlhy8tsw6.png" alt="Wired homepage" width="800" height="405"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Check back in a few hours later and the home page will be different&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  On-Demand Revalidation
&lt;/h3&gt;

&lt;p&gt;What if you have very static sites that still needs to be updated from time to time but not:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every time the client makes a request?&lt;/li&gt;
&lt;li&gt;At time intervals?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, you need to change the metadata of a product on your e-commerce site - the price, description, category. If your database or headless CMS updates, this will make your server pre-render the relevant pages again and cache the new content.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvh2u3j092lbrlr9iaaix.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvh2u3j092lbrlr9iaaix.png" alt="Amazon product page" width="800" height="507"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;This product page won’t change often and is perfect for on-demand revalidation.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Hydration Mismatch
&lt;/h3&gt;

&lt;p&gt;This occurs when the pre-rendered HTML has a mismatch with the rendered content DOM in the server. This can occur for variety of reasons such as outdated cached Javascript or time differences. Here’s a very simple example to understand how this happens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default function Component = () =&amp;gt; {
  return &amp;lt;div&amp;gt;{Math.random()}&amp;lt;/div&amp;gt;;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a simple server component in NextJS that is pre-rendered (server components are separate but related to pre-rendering). It outputs a random number.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx4c5vg08s6uv9m3obuqz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx4c5vg08s6uv9m3obuqz.png" alt="Showing output in browser and the HTML file received in Network tab of Chrome Dev Tools" width="800" height="682"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now I convert the server component into a client component by marking it with ‘use client’.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'use client'
export default function Component = () =&amp;gt; {
  return &amp;lt;div&amp;gt;{Math.random()}&amp;lt;/div&amp;gt;;
};

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

&lt;/div&gt;



&lt;p&gt;This means that this component will still be pre-rendered by NextJS but this code will also be sent to the client.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1c0twq2eb5g0bizdo5zt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1c0twq2eb5g0bizdo5zt.png" alt="Different text output in browser and HTML file received" width="800" height="787"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Uh oh, there’s a mismatch. Math.random() executed again in the client and obviously output a completely different number. NextJS’s dev build displays errors for us as well.&lt;/p&gt;

&lt;p&gt;Why does this matter? The client creates an internal representation of the page and maps the internal representation to the DOM elements of the pre-rendered HTML. This allows it to attach event handlers to the correct DOM elements. If there is a mismatch, interactivity can be broken or UI components can be duplicated. The example was a text mismatch but there can be element mismatch as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Client side rendering is still required for adding interactivity and displaying dynamic data. But it should no longer be used to render entire pages. Hopefully I explained these concepts well and if I didn’t and you have questions, please ask!&lt;/p&gt;

&lt;p&gt;You can follow me on &lt;a href="https://www.linkedin.com/in/junsupark-swe/"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://dev.to/junsupark94"&gt;DEV&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>softwareengineering</category>
      <category>webdev</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>3 great Typescript libraries to speed up your full stack development</title>
      <dc:creator>Junsu Park</dc:creator>
      <pubDate>Fri, 13 Oct 2023 10:22:26 +0000</pubDate>
      <link>https://forem.com/junsupark/3-great-typescript-libraries-to-speed-up-your-full-stack-development-3pm3</link>
      <guid>https://forem.com/junsupark/3-great-typescript-libraries-to-speed-up-your-full-stack-development-3pm3</guid>
      <description>&lt;p&gt;I have been hard at work turning my &lt;a href="https://www.linkedin.com/feed/update/urn:li:activity:7104512314267095042/" rel="noopener noreferrer"&gt;Instagram clone project&lt;/a&gt; from a front-end mock to a full stack application. It’s still a ways off but I wanted to share new libraries I picked up: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React Hook Form&lt;/li&gt;
&lt;li&gt;Zod&lt;/li&gt;
&lt;li&gt;Prisma&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They’re very popular and I must say their popularity is well deserved. They provide amazing developer experience and type-safety, which reduces my mental overhead and enforces good code structure. I will always have these libraries in my tech stack from now on until better ones come along.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://react-hook-form.com/" rel="noopener noreferrer"&gt;React Hook Form&lt;/a&gt; - client-side validation that reduces boilerplate code
&lt;/h2&gt;

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

&lt;p&gt;Forms require lot of boilerplate - validation, error state, submitting state, default values. This makes writing forms very error-prone, especially as the number of inputs increases. This library handles all of it for you. It can validate the input values without causing un-necessary re-renders. If an input value is invalid or missing, trying to submit the form will put focus on to the input.&lt;/p&gt;

&lt;p&gt;Additionally, you can extract form state from the useForm hook to render error messages or disable the submission button when the form is executing its onSubmit function.&lt;/p&gt;

&lt;p&gt;If you’re interested in trying it out, here’s a &lt;a href="https://www.youtube.com/watch?v=u6PQ5xZAv7Q" rel="noopener noreferrer"&gt;great tutorial by ByteGrad&lt;/a&gt;, who demonstrates the reduction in boilerplate thanks to React Hook Form.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://zod.dev/" rel="noopener noreferrer"&gt;Zod&lt;/a&gt; - schema validation for client and server
&lt;/h2&gt;

&lt;p&gt;However, what if you need more complex validation than just checking if a value is string or number? Zod is a schema declaration and validation library.  Here’s a code I’ve written for a sign up form for new users.&lt;/p&gt;

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

&lt;p&gt;All the required inputs here are strings, which could have been reinforced with regular TypeScript types.  But Zod can also reinforce regex pattern matching, minimum and maximum character requirement. An error message can be provided for each requirement as well. And a TypeScript type can be generated with the z.infer method.&lt;/p&gt;

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

&lt;p&gt;Now all you need to do is change the schema and the type will change automatically.&lt;/p&gt;

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

&lt;p&gt;Define the generic type and pass in the schema with a zodResolver - a package that integrated Zod and React Hook Form. Now &lt;em&gt;errors&lt;/em&gt; will update with the error messages I provided. Also, Intellisense provides autocompletion!&lt;/p&gt;

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

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

&lt;p&gt;Update the input and the form will only re-render when input is valid (or invalid again), not on every input change. It does this with &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy" rel="noopener noreferrer"&gt;Proxies&lt;/a&gt;, which allows subscribing to value changes.&lt;/p&gt;

&lt;p&gt;Here’s what’s really great about Zod: you can use the same schema on the server. Which is great because you should &lt;strong&gt;always validate on both the client and the server&lt;/strong&gt;! Who knows what malicious actor will bypass your client-side validation. Use the &lt;a href="https://zod.dev/?id=parse" rel="noopener noreferrer"&gt;parse or safeParse method&lt;/a&gt; in your API endpoint.&lt;/p&gt;

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

&lt;p&gt;One source of truth. Less error-prone, type safe, elegant.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.prisma.io/" rel="noopener noreferrer"&gt;Prisma&lt;/a&gt; - TypeScript ORM
&lt;/h2&gt;

&lt;p&gt;Unlike RHF and Zod, Prisma is a very big library and it’s hard to go over everything in detail. To be concise, I’ll tell you what I used Prisma for.&lt;/p&gt;

&lt;p&gt;I created a database schema with Prisma’s own syntax. I installed their official VS Code extension to enable Intellisense, which provided errors for constraints and relationships. It also warned me to add an index for a foreign key field to improve performance.&lt;/p&gt;

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

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

&lt;p&gt;Then I generated Prisma client and TypeScript types for all the models with npx prisma generate. In the example below, I queried the Post table to return 100 posts and join it with other tables. Autocomplete prevents me from making mistakes with my query.&lt;/p&gt;

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

&lt;p&gt;TypeScript knows the shape of the query object. I don’t need to validate the query response anymore.&lt;/p&gt;

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

&lt;p&gt;I connected Prisma to a database of my choosing and pushed the schema to the database, which is Supabase. With Prisma’s CLI command npx prisma db push, it generated all the tables for me.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkfoou3plnyx8qybr3evs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkfoou3plnyx8qybr3evs.png" alt="Created database with Supabase and Prisma"&gt;&lt;/a&gt;&lt;br&gt;
I realized I neglected to add certain fields required for an entity. No worry, I just update the Prisma schema file, re-run &lt;code&gt;npx prisma generate&lt;/code&gt; and &lt;code&gt;npx prisma db push&lt;/code&gt;. Supabase is updated for me. If any table must be cleared of its data, Prisma will warn me and ask if I want to proceed.&lt;/p&gt;

&lt;p&gt;Supabase has a visual database but if it didn’t like most CLI apps, I would run &lt;code&gt;npx prisma studio&lt;/code&gt; and it would provide one for me on a &lt;a href="http://localhost" rel="noopener noreferrer"&gt;localhost&lt;/a&gt; port.&lt;/p&gt;

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

&lt;p&gt;Prisma has accelerated my backend development. I don’t have to write complex and long SQL strings that are error prone. I have autocompletion and type-safety to prevent me from making mistakes.&lt;/p&gt;

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

&lt;p&gt;I hope I convinced you to add these 3 libraries to your stack. These libraries work at any scale and helps you write clean code that is self-documenting.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>fullstack</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Accessibility and Headless UI Libraries - Adobe, Radix, Tailwind, MUI</title>
      <dc:creator>Junsu Park</dc:creator>
      <pubDate>Sun, 24 Sep 2023 12:31:11 +0000</pubDate>
      <link>https://forem.com/junsupark/accessibility-and-headless-ui-libraries-adobe-radix-tailwind-mui-584n</link>
      <guid>https://forem.com/junsupark/accessibility-and-headless-ui-libraries-adobe-radix-tailwind-mui-584n</guid>
      <description>&lt;p&gt;There are lot of UI libraries out there. Their goal is to speed up development by providing a design system and accessibility right out of the box. The design system comes with a tradeoff: it helps speed up development since the developers don’t need to create their own design system from scratch but it can be very restrictive with customization, which makes sites built with that library look similar to each other. It’s easy to identify which sites were built using Bootstraps, for example. This tradeoff is acceptable for developers who are not good at frontend and their sites’ features rely more on the backend.&lt;/p&gt;

&lt;p&gt;Lately there has been more headless (i.e. ‘unstyled’) UI libraries that provides the accessibility with very minimal or no styling so devs can style it however they want. They provide features such as keyboard navigation, labels and attributes for screen readers, and focus management I have been perusing through some of them to incorporate into my own tech stack. Here are 4 libraries I looked at and my thoughts on them.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;Tailwind&lt;/a&gt; - &lt;a href="https://headlessui.com/" rel="noopener noreferrer"&gt;Headless UI&lt;/a&gt;
&lt;/h3&gt;

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

&lt;ul&gt;
&lt;li&gt;Component based - must be assembled in a certain way&lt;/li&gt;
&lt;li&gt;Incremental installation - can install install individual components instead of whole library&lt;/li&gt;
&lt;li&gt;Minimal - only 10 components at time of writing&lt;/li&gt;
&lt;li&gt;Tailwind has &lt;a href="https://tailwindui.com/" rel="noopener noreferrer"&gt;Tailwind UI&lt;/a&gt;, which is styled and fully customizable components but with no behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.radix-ui.com/" rel="noopener noreferrer"&gt;Radix UI&lt;/a&gt; - &lt;a href="https://www.radix-ui.com/primitives" rel="noopener noreferrer"&gt;Primitives&lt;/a&gt;
&lt;/h3&gt;

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

&lt;ul&gt;
&lt;li&gt;Component based&lt;/li&gt;
&lt;li&gt;Incremental installation&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.radix-ui.com/themes/docs/overview/getting-started" rel="noopener noreferrer"&gt;Radix UI Themes&lt;/a&gt; - minimally styled component library that is more of a superset of Primitives&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ui.shadcn.com/" rel="noopener noreferrer"&gt;ShadCN UI&lt;/a&gt; - 3rd party minimally styled component library built with Radix Primitives&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://react-spectrum.adobe.com/" rel="noopener noreferrer"&gt;Adobe&lt;/a&gt; - &lt;a href="https://react-spectrum.adobe.com/react-aria/index.html" rel="noopener noreferrer"&gt;React ARIA&lt;/a&gt;
&lt;/h3&gt;

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

&lt;ul&gt;
&lt;li&gt;Provides hooks that returns props to be assigned to corresponding elements&lt;/li&gt;
&lt;li&gt;Documentation explains thoroughly how to use the hooks and the problems they solve&lt;/li&gt;
&lt;li&gt;Complete visibility and control over DOM structure&lt;/li&gt;
&lt;li&gt;State management decoupled from accessibility behavior - provided by &lt;a href="https://react-spectrum.adobe.com/react-stately/index.html" rel="noopener noreferrer"&gt;React Stately&lt;/a&gt; hooks&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://react-spectrum.adobe.com/react-spectrum/index.html" rel="noopener noreferrer"&gt;React Spectrum&lt;/a&gt; - component library built with React Aria and React Stately - documentation is confusing since there is a component section in React Aria that is nearly identical to React Spectrum&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nextui.org/" rel="noopener noreferrer"&gt;NextUI&lt;/a&gt; - 3rd party minimally styled component library built with React ARIA&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://mui.com/" rel="noopener noreferrer"&gt;Material&lt;/a&gt; - &lt;a href="https://mui.com/base-ui/" rel="noopener noreferrer"&gt;Base UI&lt;/a&gt;
&lt;/h3&gt;

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

&lt;ul&gt;
&lt;li&gt;Behavior and accessibility logic decoupled from Material UI

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://mui.com/material-ui/" rel="noopener noreferrer"&gt;Material UI&lt;/a&gt; - completely styled component library and follows &lt;a href="https://m3.material.io/" rel="noopener noreferrer"&gt;Google’s Material Design&lt;/a&gt; design system&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Provides components like Tailwind and Radix&lt;/li&gt;

&lt;li&gt;Provides hooks like React Aria&lt;/li&gt;

&lt;li&gt;In beta - certain components are not complete or are experimental. Documentation is lacking, especially for hooks.&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  My winner is React ARIA
&lt;/h3&gt;

&lt;p&gt;My main problem with the other libraries is that I have to learn and think in their design system whereas with React ARIA, I’m thinking in native HTML.&lt;/p&gt;

&lt;p&gt;For example, Radix’s Dialog component has 8 pieces: Root, Trigger, Portal, Overlay, Content, Title, Description, Close. It abstracts away the state management, logic and behavior, and HTML elements with these pieces that I have to assemble in a specific way. &lt;/p&gt;

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

&lt;p&gt;And tweaking their behavior is exposed through certain props, not DOMAttribtues.&lt;/p&gt;

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

&lt;p&gt;With React ARIA, it’s a lot more code I have to write but working with semantic HTML and attributes makes me a better frontend engineer overall. With Radix, Tailwind, and Material, I only get better at using their library - knowing Dialog.Content must wrap around Dialog.Title and Dialog.Description does not transfer to anything else.  Additionally, I can intuit what the hooks do and see what their return values do. It reminds me of &lt;a href="https://react-hook-form.com/" rel="noopener noreferrer"&gt;React Hook Form&lt;/a&gt; in this way.&lt;/p&gt;

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

&lt;p&gt;This is a lot more boilerplate than other libraries but it makes more natural sense to me.&lt;/p&gt;

&lt;p&gt;As Tailwind makes you think in native CSS, I want to think in native HTML elements as much as possible.&lt;/p&gt;

&lt;p&gt;Also, React ARIA documentation is superb - it lists all the features of the hooks and provides an anatomy diagram for each UI component.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Thinking about accessibility is hard. Implementing them is harder. Keeping up with guidelines and thinking of different devices take up lot of time and research. It requires lot of boilerplate code and is very easy to get wrong. That’s why I highly recommend using one of these libraries so people that require on assistive technology to browse the internet can do so easily on your site. If React ARIA seems too daunting, I recommend Radix Primitives since it has more features and documentation than Headless UI and Base UI.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>a11y</category>
      <category>webdev</category>
      <category>react</category>
    </item>
    <item>
      <title>Instagram Clone Project Part 1</title>
      <dc:creator>Junsu Park</dc:creator>
      <pubDate>Mon, 04 Sep 2023 17:16:19 +0000</pubDate>
      <link>https://forem.com/junsupark/instagram-clone-project-part-1-3eeb</link>
      <guid>https://forem.com/junsupark/instagram-clone-project-part-1-3eeb</guid>
      <description>&lt;p&gt;&lt;a href="https://next-instagram-p3flcc4pj-junsupark94.vercel.app/"&gt;Link to Instagram clone project&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tech Stack: NextJS + React, TypeScript, Tailwind, Zustand, Radix UI + ShadCN UI, html-react-parser&lt;/p&gt;

&lt;p&gt;I spent the past 4 weeks working on an Instagram clone to develop my front end skills. I challenged myself to build more features than my Twitter clone project. The features I focused on were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modal routing&lt;/li&gt;
&lt;li&gt;Virtual List&lt;/li&gt;
&lt;li&gt;Dark mode&lt;/li&gt;
&lt;li&gt;Carousel&lt;/li&gt;
&lt;li&gt;Custom video player (shoutout to Web Dev Simplified for his tutorial!)&lt;/li&gt;
&lt;li&gt;Autoplay behavior&lt;/li&gt;
&lt;li&gt;Text parsing for hashtags and @ links&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please check out the project and let me know what you think. I tried to mimic Instagram as closely as possible. I also share my thoughts about implementing the features above in the post descriptions. If you have any questions, feel free to ask me in the comments of this article!&lt;/p&gt;

&lt;p&gt;This is only part 1 of the project. I will turn it into a full stack app with the following features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User Authentication&lt;/li&gt;
&lt;li&gt;Reels&lt;/li&gt;
&lt;li&gt;Messenger&lt;/li&gt;
&lt;li&gt;Stories&lt;/li&gt;
&lt;li&gt;Notifications&lt;/li&gt;
&lt;li&gt;And many more&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ll also implement end-to-end testing and fix some bugs (NextJS modal routing has a known issue I need to work around). I would have fixed these issues before deployment but I spent too long on this project and I needed to ship it for my own sanity 😭.&lt;/p&gt;

&lt;p&gt;I’ll also implement the following optimizations and compare the differences in speed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;useMemo&lt;/li&gt;
&lt;li&gt;useCallback&lt;/li&gt;
&lt;li&gt;React.memo&lt;/li&gt;
&lt;li&gt;React.lazy + Suspense&lt;/li&gt;
&lt;li&gt;React Hook Form&lt;/li&gt;
&lt;li&gt;Loading UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Follow me here on &lt;a href="https://www.linkedin.com/in/junsupark-swe/"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://dev.to/junsupark94"&gt;DEV&lt;/a&gt; to follow me on my journey to building robust web apps!&lt;/p&gt;

</description>
      <category>react</category>
      <category>typescript</category>
      <category>nextjs</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Learning NextJS and React Full Stack Features</title>
      <dc:creator>Junsu Park</dc:creator>
      <pubDate>Thu, 10 Aug 2023 01:05:34 +0000</pubDate>
      <link>https://forem.com/junsupark/learning-nextjs-and-react-full-stack-features-432l</link>
      <guid>https://forem.com/junsupark/learning-nextjs-and-react-full-stack-features-432l</guid>
      <description>&lt;p&gt;Currently there are many full stack frameworks or &lt;em&gt;metaframeworks&lt;/em&gt; that build on top of a UI library. &lt;a href="https://nextjs.org/"&gt;NextJS&lt;/a&gt; and &lt;a href="https://remix.run/"&gt;Remix&lt;/a&gt; for &lt;a href="https://react.dev/"&gt;React&lt;/a&gt;, &lt;a href="https://kit.svelte.dev/"&gt;SvelteKit&lt;/a&gt; for &lt;a href="https://svelte.dev/"&gt;Svelte&lt;/a&gt;, &lt;a href="https://nuxt.com/"&gt;Nuxt&lt;/a&gt; for &lt;a href="https://vuejs.org/"&gt;Vue&lt;/a&gt;, and &lt;a href="https://start.solidjs.com/getting-started/what-is-solidstart"&gt;SolidStart&lt;/a&gt; for &lt;a href="https://www.solidjs.com/"&gt;Solid&lt;/a&gt;. There's even a framework called &lt;a href="https://create.t3.gg/"&gt;T3&lt;/a&gt; that builds on top of NextJS - just frameworks on top of frameworks 🤯, but I'm getting ahead of myself. These frameworks vary in terms of opinionated they are and usually provide the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;💻 Enhanced developer experience via default tooling and configurations (Eslint, TypeScript, compiler, optimizations, etc)&lt;/li&gt;
&lt;li&gt;🚏 File-based routing and nested layouts&lt;/li&gt;
&lt;li&gt;💪 Backend server that provides server-side rendering, API endpoints&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;NextJS is extremely popular due to how robust it is and is the &lt;a href="https://react.dev/learn/start-a-new-react-project"&gt;recommended way to build React apps by the React devs&lt;/a&gt;. The NextJS team and React team work closely together to bring the next evolution of web technology. The current aim is to reduce the amount of client side Javascript and pre-render as much as possible in order to improve SEO and speed for users. This also helps reduce risk of exposing private APIs and improves developer experience. I spent the past week tinkering with NextJS to learn about these features and here's some of what I learned. I'll try to be concise and bring up only salient points.&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;No more installing 3rd party libraries and losing hours trying to configure them all together to make them work. Batteries are included here!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Brief background about me&lt;/strong&gt;: I'm became a full stack engineer last year and have been working at Wells Fargo since January 2023. I love learning about new web technologies, design patterns, and building things.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Server Side Rendering
&lt;/h2&gt;

&lt;p&gt;All components by default are pre-rendered on the server. This means the HTML sent to the client will have contents of the app. Previously, client side rendering was the default, in which a barebones HTML and JS is sent to the client after which JS takes over and renders the app. This was not good for two reason:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bad for SEO - web crawlers 🤖 would not see the actual content since the HTML is empty&lt;/li&gt;
&lt;li&gt;Slow for users if JS bundle is big 🐌 - users would see a blank site until the JS code was downloaded. Worse if data fetching then needed to be done afterwards to update UI - resulting in big waterfall and blocked UI. And slow initial load speed can lose customers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With SSR, both of these problems are solved. Static content and data are present in the HTML. Only dynamic data (ie. requires hydration) is not present.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'use client'
import { useEffect, useState } from "react"

export default function Page() {
  const [text, setText] = useState("This will also be in source page")

  useEffect(() =&amp;gt; {
    setText("But this won't since it can't be pre-rendered")
  }, [])

  return &amp;lt;div&amp;gt;
    &amp;lt;div&amp;gt;This will be in source page&amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;{text}&amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;blockquote&gt;
&lt;p&gt;Turned throttling on to show the initial HTML sent to client&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;blockquote&gt;
&lt;p&gt;After JS is downloaded and takes over (hydration), the UI is updated.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;blockquote&gt;
&lt;p&gt;Source page shows static and initial state are pre-rendered and present in the HTML.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;However, server-side fetched data IS pre-rendered.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function getData() 
  const res = await fetch("https://swapi.dev/api/people/1");
  const data = await res.json();
  return data;
}

async function Luke() {
  const data = await getData();

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;div&amp;gt;Name: {data.name}&amp;lt;/div&amp;gt;
      &amp;lt;div&amp;gt;Gender: {data.gender}&amp;lt;/div&amp;gt;
      &amp;lt;div&amp;gt;Height: {data.height}&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default async function Page() {
  return &amp;lt;Luke /&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;blockquote&gt;
&lt;p&gt;It's at the bottom of the source page because it was streamed in later.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  2. Server and Client Components
&lt;/h2&gt;

&lt;p&gt;So how do you do server-side data fetching? 🤔 By default, all components are server components, ie. their code is executed on the server. So just fetch the data, simple. This also has the added benefit of not sending private API endpoints and secrets to the client.&lt;br&gt;
However, code that require interactivity such as event handlers and useState can't be executed on the server since they're meant for the browser, ie. the client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function Luke() 
  const data = await getData();

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;div&amp;gt;Name: {data.name}&amp;lt;/div&amp;gt;
      &amp;lt;div&amp;gt;Gender: {data.gender}&amp;lt;/div&amp;gt;
      &amp;lt;div&amp;gt;Height: {data.height}&amp;lt;/div&amp;gt;
      {/* error: interactivity cannot be added to server components */}
      &amp;lt;button onClick={() =&amp;gt; console.log("Something")}&amp;gt;Console log something&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Therefore the 'use client' directive must be written at top of the file to declare a boundary between server code and client code. All other modules imported into a client file is now part of the client bundle.&lt;br&gt;
In order to reduce client-side JS and keep its size cacheable and predictable, client components should be smallest as possible and at the leaves of the component tree. Note though client components are still pre-rendered as shown above.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Data Fetching
&lt;/h2&gt;

&lt;p&gt;By default, all data fetching done with the fetch() API are cached. Thus if identical fetch requests are made (same URL, methods, body, headers), then it will only be executed once and the data will be shared.&lt;/p&gt;

&lt;p&gt;In order to avoid stale data, revalidation or no-caching can be set. Revalidation can be time-based or on-demand (imperatively). Revalidation will cause the server to pre-render a new HTML.&lt;/p&gt;
&lt;h2&gt;
  
  
  4. Server Actions
&lt;/h2&gt;

&lt;p&gt;This is an ⚠️ experimental feature ⚠️ that allows interactivity in server components. It allows to send requests to server and update the UI with revalidation. The &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; element has an action prop which takes an async function with the 'use server' directive at the top of the function definition. Wrap it around a text or element. Here I wrapped it around a button.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let likes = 0
let dislikes = 0;

async function incrementLikes() {
  "use server";
  likes++;
  revalidatePath("/");
}
async function incrementDislikes() {
  "use server";
  dislikes++;
  revalidatePath("/");
}

async function Count() {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;div&amp;gt;Likes: {likes}&amp;lt;/div&amp;gt;
      &amp;lt;form action={incrementLikes}&amp;gt;
        &amp;lt;button className="bg-blue-300 p-1 rounded-md"&amp;gt;Increment Likes&amp;lt;/button&amp;gt;
      &amp;lt;/form&amp;gt;
      &amp;lt;div&amp;gt;Dislikes: {dislikes}&amp;lt;/div&amp;gt;
      &amp;lt;form action={incrementDislikes}&amp;gt;
        &amp;lt;button className="bg-blue-300 p-1 rounded-md"&amp;gt;
          Increment Dislikes
        &amp;lt;/button&amp;gt;
      &amp;lt;/form&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdhvr6kqp8tua4rgr6yc1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdhvr6kqp8tua4rgr6yc1.png" alt="Image description" width="165" height="121"&gt;&lt;/a&gt;&lt;br&gt;
Clicking on these buttons will mutate the server data. The revalidatePath function will cause the server to re-render the page and send the HTML to the client.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnq7kw5w1e09iagd8s04c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnq7kw5w1e09iagd8s04c.png" alt="Image description" width="750" height="114"&gt;&lt;/a&gt;&lt;br&gt;
I think the most practical application of this would be to send some form data to the server since form data can be accessed without state or refs. This feature is still experimental and will likely change in the future but it's a cool way to run server-side code on the client without exposing the code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let email = ""

async function submitEmail(formData: FormData) {
  'use server'
  email = formData.get('email')?.toString()!;
  revalidatePath('/')
}

async function EmailForm() {
  return &amp;lt;div&amp;gt;
    &amp;lt;div&amp;gt;Submit your email&amp;lt;/div&amp;gt;
    &amp;lt;form action={submitEmail}&amp;gt;
      &amp;lt;input className="bg-gray-300 p-2 rounded-md" name="email" type="email" /&amp;gt;
    &amp;lt;/form&amp;gt;
    &amp;lt;div&amp;gt;Your email: {email}&amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;blockquote&gt;
&lt;p&gt;Before submitting&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;blockquote&gt;
&lt;p&gt;After submitting and revalidation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  5. &lt;a href="https://react.dev/reference/react/Suspense"&gt;Suspense&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;What happens if a server component is fetching data but it takes a long time? It'll block the UI. I mentioned streaming HTML earlier and this is something we can do with React Suspense so the UI isn't blocked by a slow server component.&lt;/p&gt;

&lt;p&gt;The code here has a DelayedComponent that takes 3 seconds to render. By wrapping it React Suspense and providing the fallback prop with a JSX content to be rendered while it waits for DelayedComponent to be rendered, our UI is no longer blocked and is progressively loaded.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function DelayedComponent() 
  await new Promise((resolve) =&amp;gt; setTimeout(resolve, 3000));
  return &amp;lt;div&amp;gt;Delayed Component&amp;lt;/div&amp;gt;;
}

export default async function Page() {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;div&amp;gt;This is visible immediately&amp;lt;/div&amp;gt;
      &amp;lt;Suspense fallback={&amp;lt;div&amp;gt;Loading Delayed Component...&amp;lt;/div&amp;gt;}&amp;gt;
        &amp;lt;DelayedComponent /&amp;gt;
      &amp;lt;/Suspense&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;blockquote&gt;
&lt;p&gt;Without React Suspense, I'd see a blank page for 3 seconds&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;blockquote&gt;
&lt;p&gt;You can see the fallback content in the source page at the top then the actual content streamed in at the bottom.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  6. &lt;a href="https://react.dev/reference/react/lazy"&gt;lazy&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;If there is a client component or library that takes a long time to load and is not critical to your UI, you can defer it from the initial client bundle with React lazy, aka code splitting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"use client"
import { lazy, useState } from "react";

const LazyComponent = lazy(() =&amp;gt; import("@/components/LazyComponent"));

export default function Page() {
  const [isVisible, setIsVisible] = useState(false);
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setIsVisible(true)} className="p-2 bg-blue-300 rounded-md"&amp;gt;Load Lazy Component&amp;lt;/button&amp;gt;
      {isVisible &amp;amp;&amp;amp; &amp;lt;LazyComponent /&amp;gt;}
    &amp;lt;/div&amp;gt;
  );
};

// separate file
export default function LazyComponent()
  return &amp;lt;div&amp;gt;Lazy Component&amp;lt;/div&amp;gt;
} 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;blockquote&gt;
&lt;p&gt;Before clicking the button&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;blockquote&gt;
&lt;p&gt;Click the button downloads the bundle for LazyComponent on demand and renders it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If the bundle takes a long time to download, it can block the UI. To prevent this, wrap it in Suspense. All lazily loaded components are pre-rendered by default (though in this example it's not since the initial state is not to show the component).&lt;/p&gt;

&lt;h2&gt;
  
  
  7. &lt;a href="https://nextjs.org/docs/app/building-your-application/optimizing/lazy-loading#nextdynamic"&gt;NextJS Dynamic&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I highly recommend reading the doc linked since it gives a very good explanation. Dynamic is composite of Suspense and lazy. There is no need to wrap the lazy component in Suspense, and to give it a fallback UI, it's passed in as an option parameter. Pre-rendering can also de disabled by setting ssr to false..&lt;/p&gt;

&lt;p&gt;ComponentA below will be loaded in a separate client bundle but will not be streamed in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import dynamic from "next/dynamic";

const ComponentA = dynamic(() =&amp;gt; import("../components/A"), 
  loading: () =&amp;gt; &amp;lt;div&amp;gt;Loading A...&amp;lt;/div&amp;gt;,
  ssr: false,
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;All these features help create a more robust front-end by reducing client bundle sizes, improving initial page load, reducing waterfall and blocking of UI. By leveraging the server more, less burden is placed on the client.&lt;/p&gt;

&lt;p&gt;If you liked what you read, follow me on &lt;a href="https://www.linkedin.com/in/junsupark-swe/"&gt;LinkedIn&lt;/a&gt; or DEV as I continue along my journey towards building more robust web applications. My next article will be comparing the full stack frameworks I mentioned at the start of this article. I want to understand the different approaches and mental models these frameworks have developed.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>webdev</category>
      <category>frontend</category>
    </item>
    <item>
      <title>What I learned from building a high fidelity Twitter UI clone</title>
      <dc:creator>Junsu Park</dc:creator>
      <pubDate>Mon, 31 Jul 2023 21:19:39 +0000</pubDate>
      <link>https://forem.com/junsupark/what-i-learned-from-building-a-high-fidelity-twitter-ui-clone-a1e</link>
      <guid>https://forem.com/junsupark/what-i-learned-from-building-a-high-fidelity-twitter-ui-clone-a1e</guid>
      <description>&lt;p&gt;To deepen my frontend skills, I decided to build a &lt;a href="https://twitter-clone-nextjs-brown.vercel.app/home"&gt;high-fidelity Twitter clone&lt;/a&gt;. I was bored of the very &lt;em&gt;basic&lt;/em&gt; CRUD app tutorials on Youtube that barely mimicked Twitter’s UI. Replicating Twitter’s UI was very challenging for a relatively new developer like me and I learned a lot, especially how to dissect UIs in Chrome Dev Tools.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tech Stack&lt;/strong&gt;: NextJS, TypeScript, Tailwind, Zustand.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Brief introduction about me&lt;/strong&gt;: I became a full stack engineer last year and have been enjoying working at Wells Fargo helping to build their new security that enables more sophisticated logins for customers. I love building interfaces and systems and reading about thoughtful design.&lt;/p&gt;

&lt;p&gt;Please check out &lt;a href="https://twitter-clone-nextjs-brown.vercel.app/home"&gt;my Twitter clone&lt;/a&gt; - I explain my thoughts about the tech stack I used and challenges I had in replicating Twitter’s UI behavior. Here are a few key points I learned:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;This project took me about 3 weeks. I initially projected a week but soon learned just how complex each component is. One thing that surprised me initially was that almost every element in Twitter is a div and all the divs are flex containers with accessibility added via ARIA labels. Then I quickly learned that the inconsistent CSS properties of semantic tags are extremely frustrating.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffhjg01tw5treaglymqrr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffhjg01tw5treaglymqrr.png" alt="It's flex divs all the way down" width="440" height="510"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;NextJS's default optimizations and server-side rendering gave me great Google Lighthouse scores right out of the box. I tried to make interactive parts of the app as small as possible and sectioned them off as client components at edges of the component tree to improve FCP. When I build a full stack app, I'll implement data fetching with React Server Components and Suspense.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7us4ytdbhu6h93xmpkyd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7us4ytdbhu6h93xmpkyd.png" alt="I didn't even have to configure gzip compression!" width="719" height="865"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I got really good at finding where height and width of an element comes from. In Chrome Dev Tools, I would analyze from the leaf all the way to the parent to check for padding, margins, borders, and hard-coded width and height. Twitter has lot of redundant divs that do apply one or two styles at a time. I assume this is due to the complexity of working in a extremely big team. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhhbebmxnp2mlfseydhl4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhhbebmxnp2mlfseydhl4.png" alt="Inspecting an element on Twitter's site - width and height are greyed out which means it gets it dimensions from its ancestors or descendants." width="725" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I feel extremely confident about my ability to create high-quality production-grade UIs now. Follow me here on &lt;a href="https://www.linkedin.com/in/junsupark-swe/"&gt;LinkedIn&lt;/a&gt; or on DEV as I continue along my journey towards building robust web applications! My goals are to build more high-fidelity clone projects with other frameworks, such as Remix, SvelteKit, SolidStart, and WASM.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>nextjs</category>
      <category>tailwindcss</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
