<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dušan Perković</title>
    <description>The latest articles on DEV Community by Dušan Perković (@noblica).</description>
    <link>https://dev.to/noblica</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%2F1135352%2F19ac0894-b8a3-4867-88b8-2694f9a01ed9.jpeg</url>
      <title>DEV Community: Dušan Perković</title>
      <link>https://dev.to/noblica</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/noblica"/>
    <language>en</language>
    <item>
      <title>What does StyleX solve?</title>
      <dc:creator>Dušan Perković</dc:creator>
      <pubDate>Mon, 18 Dec 2023 00:30:40 +0000</pubDate>
      <link>https://dev.to/noblica/what-does-stylex-solve-10c</link>
      <guid>https://dev.to/noblica/what-does-stylex-solve-10c</guid>
      <description>&lt;p&gt;Facebook/Meta recently released the &lt;a href="https://github.com/facebook/stylex" rel="noopener noreferrer"&gt;StyleX&lt;/a&gt; library, and already there are many articles and youtube videos explaining how it's &lt;strong&gt;THE TAILWIND KILLER&lt;/strong&gt; (ooh, spooky).&lt;/p&gt;

&lt;p&gt;I'm going to go through some of the main points from &lt;a href="https://www.youtube.com/watch?v=dphmbB77W_4" rel="noopener noreferrer"&gt;this video&lt;/a&gt; by &lt;a href="https://www.youtube.com/@WebDevSimplified" rel="noopener noreferrer"&gt;Web Dev Simplified&lt;/a&gt; to try and explain why I'm not convinced of the StyleX hype. If you're not familiar with the StyleX library, it's a nice way to get introduced to it. This channel has a lot of great videos, even though I don't agree with his take here.&lt;/p&gt;

&lt;p&gt;So let's start with the first big StyleX feature:&lt;/p&gt;

&lt;h2&gt;
  
  
  Co-location
&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%2Fsm8j6cnx19xu02wkt79h.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%2Fsm8j6cnx19xu02wkt79h.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Co-location is the practice of closely grouping things that belong together. So why not keep styles in the same place where you define your component code?&lt;/p&gt;

&lt;p&gt;I have nothing against this approach. In fact, I'm glad that we are embracing this principle more and more. But this implementation honestly seems like a step back from what Tailwind is doing. If we take a look at the example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./Button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;stylex&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@stylexjs/stylex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stylex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;heading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;stylex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;props&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;heading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Heading&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Button&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compared to how we would write it in Tailwind:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-blue"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Heading&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Button&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seems like the Tailwind implementation is actually better with co-location. The classes that impact the element are written &lt;strong&gt;directly&lt;/strong&gt; on the element, instead of somewhere above or below.&lt;/p&gt;

&lt;p&gt;The difference in the example is small, but imagine defining styles for a more complex component. With StyleX, you would have a big chunk of CSS-like code at the beginning of your file (as is visible later in the video), in which case you would have to keep scrolling up-and-down to find and change the styling for a given element. With Tailwind this is never the case, because you only change the classes on the element you want to change itself.&lt;/p&gt;

&lt;p&gt;At that point, it might actually be helpful to move the StyleX code to another file, so you can keep the styling code open side by side with the component code. And if you're doing that, you're basically just doing CSS Modules, so I'm not really sure how this is better?&lt;/p&gt;

&lt;h2&gt;
  
  
  Deterministic resolution
&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%2Fmj01vs854c1abctp7xm3.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%2Fmj01vs854c1abctp7xm3.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The last style applied always wins."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Conflicting CSS selectors can be a pain, especially if you don't use a convention like &lt;a href="https://getbem.com/" rel="noopener noreferrer"&gt;BEM&lt;/a&gt; or something similar.&lt;br&gt;
If you use Tailwind however, you never have these specificity selector issues, because the classes are atomic, and applied directly on the element in the HTML.&lt;/p&gt;

&lt;p&gt;So unless you are just randomly creating selectors, without any convention or structure, and without scoping things with CSS Modules, I'm not really sure what this solves? &lt;br&gt;
If you are, then I don't think StyleX is gonna help you much. You have an organizational problem, not a tooling one.&lt;/p&gt;
&lt;h2&gt;
  
  
  Bigger projects are easier to maintain with StyleX.
&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%2Fplzvbf3m88ro19bngzce.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%2Fplzvbf3m88ro19bngzce.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I don't really think this is the case. Actually I think on larger projects, StyleX will suffer from almost the same issues that CSS does.&lt;br&gt;
One of the biggest issues with CSS on bigger projects, is knowing if a defined selector is still necessary, or if it can be removed from the stylesheet. Bigger projects tend to have a lot of selectors which get applied in multiple places, so knowing if a selector should or shouldn't be removed can be tricky.&lt;/p&gt;

&lt;p&gt;Since "The last style applied always wins." (just like the selector with the most specificity wins in plain CSS), all the styles that are applied until the last one may or may not be partially needed. So on larger projects you will still have the issue described above, just with a different tool. It definitely helps a bit that these useless styles are stripped in production, but they still remain in the codebase and make maintenance harder.&lt;/p&gt;
&lt;h2&gt;
  
  
  Reusability
&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%2Fzp68cefr8wihziu2d35g.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%2Fzp68cefr8wihziu2d35g.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I really don't think styles should be shared between components, expect maybe in &lt;strong&gt;very&lt;/strong&gt; specific cases. A components style is an integral and identifiable part of it. Trying to reuse it, or a part of it just creates extra dependencies which makes things weird, and long term project maintenance difficult. &lt;/p&gt;

&lt;p&gt;Let me try to explain what I mean through this example: Let's say we have a simple button with a little bit of styling on our project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;stylex&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@stylexjs/stylex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stylex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;white&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;borderRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.25em&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
        &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;stylex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;props&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And let's say that at some point we need to define another button, which should be the same as the original button, but a little bit different. &lt;br&gt;
So we might do something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;stylex&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@stylexjs/stylex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./Button.jsx

const newStyles = stylex.create({
  base: {
    backgroundColor: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="nx"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;,
  },
})

export default function DeleteButton(props) {
  return (
      &amp;lt;button
        onClick={() =&amp;gt; {
          if (confirm(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="nx"&gt;Are&lt;/span&gt; &lt;span class="nx"&gt;you&lt;/span&gt; &lt;span class="nx"&gt;sure&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;) {
            props.onClick()
          }
        }}
        {...stylex.props(styles.base, newStyles.base)}
      &amp;gt; 
         {props.children}
      &amp;lt;/button&amp;gt;
  )
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works, but puts the &lt;code&gt;DeleteButton&lt;/code&gt; component in a weird spot. Co-location is effectively broken, because the styling for &lt;code&gt;DeleteButton&lt;/code&gt; depends on the styling from the &lt;code&gt;Button&lt;/code&gt; component. A dependency is also introduced, which means that any future style changes to the &lt;code&gt;Button&lt;/code&gt; will also impact the &lt;code&gt;DeleteButton&lt;/code&gt;. So your boss and QA are gonna love you, for making their job twice as difficult.&lt;/p&gt;

&lt;p&gt;We could also extract the styling to a separate file like a &lt;code&gt;button-styles.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./Button.jsx

export const styles = stylex.create({
  base: {
    backgroundColor: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="nx"&gt;blue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;,
    color: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="nx"&gt;white&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;,
    borderRadius: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="nx"&gt;em&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;,
  },
  delete: {
    backgroundColor: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="nx"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;,
  },
})

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

&lt;/div&gt;



&lt;p&gt;But at this point we are just writing CSS with extra steps, so I don't really see the benefit?&lt;/p&gt;

&lt;p&gt;A simpler approach would be to just keep the styles unique to each component, but at that point we have no need to share the styles, so reusability becomes a moot point. And since Tailwind is better with co-location as discussed above, it could look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
        &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"bg-blue text-white rounded"&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;DeleteButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
        &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;confirm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Are you sure?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"bg-red text-white rounded"&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 
         &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is my preferred approach, as it keeps things simple, and components contained and independent of each other. And your boss and QA not hating you is a nice bonus.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conditionally applying styles
&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%2Fhn7zkbu529r5ahr27jdv.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%2Fhn7zkbu529r5ahr27jdv.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This feature is nice, but libraries like &lt;a href="https://www.npmjs.com/package/classnames" rel="noopener noreferrer"&gt;classnames&lt;/a&gt;, and &lt;a href="https://www.npmjs.com/package/clsx" rel="noopener noreferrer"&gt;clsx&lt;/a&gt; already solved this a long time ago.&lt;br&gt;
If you are using Tailwind, you might be worried that your code won't look as nice if you have a bunch of classes on your element tags.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We are not&lt;/strong&gt; in the business of making code look pretty, and satisfying your aesthetic wants for numbers of characters on screen per file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We are&lt;/strong&gt; in the business of building maintainable solutions that are as simple as possible, and easy to maintain.&lt;/p&gt;

&lt;p&gt;Stop trying to "make code pretty". It doesn't have to be pretty, but &lt;a href="https://dev.to/noblica/expressive-code-clean-code-59o7"&gt;it should always be expressive&lt;/a&gt;. &lt;/p&gt;
&lt;h2&gt;
  
  
  Overriding styles from parent components.
&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%2Fi8maorkq4n5bi20pznm5.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%2Fi8maorkq4n5bi20pznm5.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not do this. Do not pass random styles around to components.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not even once.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Unless you are making a component library akin to &lt;a href="https://headlessui.com/" rel="noopener noreferrer"&gt;headlessui&lt;/a&gt; you should never just pass random styles to components.&lt;/p&gt;

&lt;p&gt;A better solution is to create an interface from the child component via props, where you can specify which version of the child component you want. If we use the button example from above, and the classnames library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;classnames&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;classnames&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
        &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;confirm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Are you sure?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;classnames&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bg-blue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;variant&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bg-red&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;variant&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;delete&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-white rounded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
       &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 
         &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way the styling stays internal to the child component, consistent across the application, but still flexible based on the &lt;code&gt;variant&lt;/code&gt; property.&lt;/p&gt;

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

&lt;p&gt;As the title says, I am not sure what StyleX is supposed to solve, since most of the things that it solves have better solutions in other places. &lt;/p&gt;

&lt;p&gt;If you're starting a new project, just use Tailwind, and you're already winning.&lt;/p&gt;

&lt;p&gt;If you already have a codebase in CSS, I don't see the need to switch to StyleX, or how it would "evolve" your styling. If you have some of the issues described above, try adopting a methodology like BEM, and using CSS Modules for scope isolation. It's easier then rewriting everything in StyleX, and you'll have more maintainable code.&lt;/p&gt;

&lt;p&gt;If you have an existing large codebase using CSS-in-JS:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You are suffering more than any of us.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;StyleX might actually make sense for you&lt;/strong&gt;, but I still wouldn't recommend it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You would definitely see some perf improvements, and the syntax seems quite similar so transition should be easy. But StyleX is quite young, so you will probably experience some issues with the transition.&lt;/p&gt;

&lt;p&gt;Even though I crapped on StyleX throught this article, I always think it's cool when people are trying something new. And I think it's great that people behind StyleX are trying to make something to make our professional lives easier. &lt;/p&gt;

&lt;p&gt;I'm keeping an open mind about this topic, so feel free to try to change it in the comments!&lt;/p&gt;

</description>
      <category>stylex</category>
      <category>tailwindcss</category>
      <category>frontend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>You're not missing out</title>
      <dc:creator>Dušan Perković</dc:creator>
      <pubDate>Wed, 13 Sep 2023 14:28:59 +0000</pubDate>
      <link>https://dev.to/noblica/youre-not-missing-out-175e</link>
      <guid>https://dev.to/noblica/youre-not-missing-out-175e</guid>
      <description>&lt;p&gt;Recently &lt;a href="https://bun.sh/blog/bun-v1.0"&gt;Bun 1.0&lt;/a&gt; came out to much fanfare. And rightly so! It is a very ambitious project that aims to be a drop-in replacement for your JavaScript package manager, transpiler, bundler, testing library, and even NodeJS itself. While this is all indeed very exciting, and I am really interested to see how Bun grows and evolves, this is not the first time I've noticed everyone rush to try out the &lt;strong&gt;new thing&lt;/strong&gt; in web development. I'm here to tell you that you don't need to do that. In fact, it can be a big determent to your project.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Temptation of FOMO
&lt;/h2&gt;

&lt;p&gt;Whenever a new JS tool comes out, and I see all the bombastic articles being written about it, I start getting feeling the FOMO (Fear Of Missing Out). It seems like everyone else is jumping on this new cool bandwagon, and since I am not doing it &lt;strong&gt;right away&lt;/strong&gt;, I might get left behind. But the truth is that this never happens, because all the early adopters usually end up being beta testers, breaking their apps/build systems by trying to fit the new shiny thing in their codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Experiment with New Tools
&lt;/h2&gt;

&lt;p&gt;I'm not saying that you should never try anything new. But there is a time and a place for testing new tools out. Like hobby projects, or smaller/"younger" projects that have less dependencies to manage. Anything where you &lt;strong&gt;can&lt;/strong&gt; move fast and break things, or where the impact of things breaking is low, should be fine to play around with and give new things a shot. However, if you have an enterprise level app with a bunch of people working on it, &lt;strong&gt;please&lt;/strong&gt; do not rush to adopt the newest JavaScript thing that reached version x.0. &lt;/p&gt;

&lt;h2&gt;
  
  
  Prioritizing Stability in Enterprise Projects
&lt;/h2&gt;

&lt;p&gt;Any major version jumps (like from 2.x to 3.0), usually contain a lot of breaking changes. Migrations like this can be a pain to do, but are usually necessary for security/compatibility reasons. I recommend setting up and using something like &lt;a href="https://github.blog/2020-06-01-keep-all-your-packages-up-to-date-with-dependabot/"&gt;dependabot&lt;/a&gt;, since it's very helpful in keeping things up to date.&lt;/p&gt;

&lt;p&gt;In addition to that, in case of it being a new library (like finally reaching 1.0), it means that not many people are using it, and you probably won't find answers online to the issues you encounter specific to your project. &lt;strong&gt;You will have a bad time, and your co-workers will dislike you when things inevitably break.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  You're not missing out
&lt;/h2&gt;

&lt;p&gt;In the ever-evolving world of web development, it's easy to get swept up in the excitement of new tools and frameworks. However, it's essential to remember that the race to adopt the latest and greatest doesn't always lead to success. Whether you're working on a hobby project or a massive enterprise application, take your time, carefully evaluate the impact of new tools, and prioritize the stability of your projects over the allure of the 'next big thing.' After all, &lt;strong&gt;you're not missing out&lt;/strong&gt; – you're ensuring that your work stands the test of time.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>bunjs</category>
      <category>node</category>
    </item>
    <item>
      <title>Creating the project in Google Console</title>
      <dc:creator>Dušan Perković</dc:creator>
      <pubDate>Thu, 07 Sep 2023 11:15:52 +0000</pubDate>
      <link>https://dev.to/noblica/creating-the-project-in-google-console-1k0e</link>
      <guid>https://dev.to/noblica/creating-the-project-in-google-console-1k0e</guid>
      <description>&lt;p&gt;In the &lt;a href="https://dev.to/noblica/setup-your-nextjs-app-35io"&gt;first article&lt;/a&gt; of the series, we have set up our frontend project, created some basic components, and added some base styling.&lt;/p&gt;

&lt;p&gt;If we want that &lt;strong&gt;Sign In With Google&lt;/strong&gt; button to actually do &lt;strong&gt;something&lt;/strong&gt;, we have to connect it to Google services. This means we need to tell Google some details about our project, like the project name, who's going to be using it and what information from the Google profile we want to use.&lt;/p&gt;

&lt;p&gt;So we have to set up a project in Google Console, and this is what we'll be doing in this article!&lt;/p&gt;

&lt;p&gt;First, we need to create and setup the project. To do that, we simply go to &lt;a href="https://console.cloud.google.com/"&gt;https://console.cloud.google.com/&lt;/a&gt; click the &lt;strong&gt;Select Project&lt;/strong&gt; dropdown at the top of the screen, and create a new project. For the &lt;strong&gt;Project Name&lt;/strong&gt; we will pick &lt;strong&gt;Next Google Auth&lt;/strong&gt;, and in the &lt;strong&gt;Organization&lt;/strong&gt; field pick &lt;strong&gt;No Organization&lt;/strong&gt;*.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j_ShYg4c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3i9o3c7typetkzrgfaa3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j_ShYg4c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3i9o3c7typetkzrgfaa3.png" alt="Creating the project" width="800" height="681"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the project is created, we need to configure it, starting with the OAuth Consent Screen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up the OAuth Consent Screen
&lt;/h2&gt;

&lt;p&gt;After your project is created, select it, and navigate to the &lt;strong&gt;APIs &amp;amp; Services -&amp;gt; OAuth Consent Screen&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7aM0Nquu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2bk2zyzc1trh61vd6twg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7aM0Nquu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2bk2zyzc1trh61vd6twg.png" alt="Navigate to the OAuth consent screen" width="800" height="735"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We need to define certain OAuth consent parameters, like if the app will be for internal or external use, what the app name will be, etc.&lt;/p&gt;

&lt;p&gt;We will select certain options for the purposes of this demo, but feel free to change your selection to however you see fit depending on your needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A note on Google Cloud project configuration&lt;/strong&gt;: Initially, when the Google Cloud project is created, it is put in &lt;strong&gt;TESTING&lt;/strong&gt; mode, and you can change the settings as much as you want until you decide to publish your project. However, please note that after you &lt;strong&gt;PUBLISH&lt;/strong&gt; the project, you will need to submit your app for verification, before you can change the project settings again!&lt;/p&gt;

&lt;p&gt;In the &lt;strong&gt;OAuth consent screen&lt;/strong&gt; step we just need to provide some basic info about the app, and who is going to support it. So choose the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Our &lt;strong&gt;User Type&lt;/strong&gt; will be &lt;strong&gt;External&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Our &lt;strong&gt;App name&lt;/strong&gt; will be &lt;strong&gt;Next Google Auth&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Our &lt;strong&gt;User support email&lt;/strong&gt; and &lt;strong&gt;Developer contact information email&lt;/strong&gt; will be the same (you can use your own google email address here).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sn3B9H6d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o1wtd6b06t0vvtjfdwah.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sn3B9H6d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o1wtd6b06t0vvtjfdwah.png" alt="Configuring the OAuth consent screen" width="800" height="1019"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tk2Kx2Qc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nclkz1ytv9emdrs0vflr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tk2Kx2Qc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nclkz1ytv9emdrs0vflr.png" alt="Configuring the OAuth consent screen" width="800" height="1002"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the next step &lt;strong&gt;Scopes&lt;/strong&gt;, we define what user info we want to grab from google services. There's a lot of info we can get, but we are only interested in the users email and some profile info for this specific app, so:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select &lt;strong&gt;ADD OR REMOVE SCOPES&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Select &lt;code&gt;../auth/userinfo.email&lt;/code&gt; and &lt;code&gt;../auth/userinfo.profile&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Hit &lt;strong&gt;UPDATE&lt;/strong&gt; and continue to the next step.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xNMTo0zo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1rstu1dno6ww9xky6ewc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xNMTo0zo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1rstu1dno6ww9xky6ewc.png" alt="Initial add/remove scopes screen" width="800" height="653"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--awgNJPSY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mi2illedrcqs7oom53ap.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--awgNJPSY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mi2illedrcqs7oom53ap.png" alt="Dialog to add scopes" width="800" height="747"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cGiKn6s5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0qciggjb5a1q6v7qwejo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cGiKn6s5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0qciggjb5a1q6v7qwejo.png" alt="Final screen with scopes added" width="800" height="796"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, go ahead and add your email as a &lt;strong&gt;Test Users&lt;/strong&gt; for now.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0NEG95a3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sucinko2vcchulfjleg2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0NEG95a3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sucinko2vcchulfjleg2.png" alt="Adding a test user" width="800" height="665"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's it! We've finished with the consent screen configuration. The final screen is just an overview of the things we selected/entered, so make sure everything is correct.&lt;/p&gt;

&lt;p&gt;After we're done with our consent screen configuration, we can continue and create our &lt;strong&gt;Credentials&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up our OAuth Credentials:
&lt;/h2&gt;

&lt;p&gt;We need to setup our OAuth Client ID and Client Secret, so we can connect our frontend app with our newly created Google Cloud Project.&lt;br&gt;
To create these credentials, go to &lt;strong&gt;Credentials&lt;/strong&gt; -&amp;gt; &lt;strong&gt;CREATE CREDENTIALS&lt;/strong&gt; -&amp;gt; &lt;strong&gt;OAuth client ID&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Under &lt;strong&gt;Application Type&lt;/strong&gt; make sure you select &lt;strong&gt;Web Application&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Make sure to define an entry under &lt;strong&gt;Authorised redirect URIs&lt;/strong&gt; as &lt;code&gt;http://localhost:3000/api/auth/callback/google&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XisNAgpM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uvzowsezi4uek047wdo1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XisNAgpM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uvzowsezi4uek047wdo1.png" alt="Create credentials selection" width="800" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--94cmgczZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3yoktsizxw6jffu0h0i0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--94cmgczZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3yoktsizxw6jffu0h0i0.png" alt="Credentials configuration" width="800" height="1252"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why do we have to specify a redirect URI?
&lt;/h3&gt;

&lt;p&gt;After Google has verified that the user signing into your app is in fact a Google user, it needs to know where it can safely send the information we requested in the &lt;strong&gt;Selected Scopes&lt;/strong&gt; (in our case we only requested the user email and profile information). &lt;br&gt;
This token can contain &lt;strong&gt;sensitive&lt;/strong&gt; data, so we have to make sure that we are redirecting to a safe URI.&lt;/p&gt;

&lt;p&gt;We now have our &lt;strong&gt;Client ID&lt;/strong&gt; and &lt;strong&gt;Client Secret&lt;/strong&gt;! With these 2 strings, we can finally connect our frontend app with our freshly created Google Cloud Project, and put those Sign in/Sign out buttons to good use!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>googlecloud</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Setup your NextJS app</title>
      <dc:creator>Dušan Perković</dc:creator>
      <pubDate>Thu, 31 Aug 2023 14:08:57 +0000</pubDate>
      <link>https://dev.to/noblica/setup-your-nextjs-app-35io</link>
      <guid>https://dev.to/noblica/setup-your-nextjs-app-35io</guid>
      <description>&lt;p&gt;If you're looking to setup easy authentication for your users in NextJS, you're in the right place!&lt;/p&gt;

&lt;p&gt;In this guide, I will show you all the steps necessary to setup your NextJS app, add google authentication to it (the &lt;code&gt;Sign In With Google&lt;/code&gt; button), and deploy the application to production (using &lt;a href="https://vercel.com/noblica" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt;). &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is the first part of the guide&lt;/strong&gt;, which will focus on just setting up your NextJS environment.&lt;/p&gt;

&lt;h1&gt;
  
  
  Generating the boilerplate
&lt;/h1&gt;

&lt;p&gt;To setup our app, we're gonna use the tried and true method from &lt;a href="https://nextjs.org/docs/getting-started/installation" rel="noopener noreferrer"&gt;the official documentation&lt;/a&gt;. NextJS has a great CLI tool, which you don't even need to install separately. &lt;br&gt;
If you already have &lt;code&gt;node&lt;/code&gt; installed, simply run &lt;code&gt;npx create-next-app@latest&lt;/code&gt; in your projects directory, and answer the following questions as you please. Since I'm a big fan of &lt;strong&gt;Tailwind&lt;/strong&gt; and &lt;strong&gt;TypeScript&lt;/strong&gt;, this is the setup I used:&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%2Fvjueu6p5om4h08k57ghc.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%2Fvjueu6p5om4h08k57ghc.png" alt="Next project setup"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Creating the pages
&lt;/h1&gt;

&lt;p&gt;Let's personalize our app a bit. We can start by adding our sign in, and sign out buttons.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app/components/SignInButton.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useRouter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/navigation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SignInButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;push&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRouter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; 
    &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-white w-full bg-[#4285F4] hover:bg-[#4285F4]/90 focus:ring-4 focus:outline-none focus:ring-[#4285F4]/50 font-medium rounded-lg text-sm px-5 py-2.5 text-center inline-flex items-center justify-center dark:focus:ring-[#4285F4]/55"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GoogleIcon&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    Sign in with Google
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GoogleIcon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;svg&lt;/span&gt;
    &lt;span class="na"&gt;xmlns&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2000/svg"&lt;/span&gt;
    &lt;span class="na"&gt;aria-hidden&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
    &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"mr-2 -ml-1 w-4 h-4"&lt;/span&gt;
    &lt;span class="na"&gt;data-icon&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"google"&lt;/span&gt;
    &lt;span class="na"&gt;data-prefix&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"fab"&lt;/span&gt;
    &lt;span class="na"&gt;viewBox&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"0 0 488 512"&lt;/span&gt;
  &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;path&lt;/span&gt;
      &lt;span class="na"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"currentColor"&lt;/span&gt;
      &lt;span class="na"&gt;d&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"M488 261.8C488 403.3 391.1 504 248 504 110.8 504 0 393.2 0 256S110.8 8 248 8c66.8 0 123 24.5 166.3 64.9l-67.5 64.9C258.5 52.6 94.3 116.6 94.3 256c0 86.5 69.1 156.6 153.7 156.6 98.2 0 135-70.4 140.8-106.9H248v-85.3h236.1c2.3 12.7 3.9 24.9 3.9 41.4z"&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;svg&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;app/components/SignOutButton.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useRouter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/navigation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SignOutButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;push&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRouter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-black hover:text-sky-600"&lt;/span&gt;
      &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/signin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Sign out&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For now, the only thing that should happen when clicking on these buttons is a redirect to the home page (&lt;code&gt;/&lt;/code&gt;), or to the sign in page (&lt;code&gt;/signin&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A note on "use client"&lt;/strong&gt;: This is a new syntax specific to using NextJS with the App router. It marks the component as a &lt;strong&gt;client component&lt;/strong&gt;, which means it needs to load JavaScript on the client side.&lt;br&gt;
Client components are different from &lt;strong&gt;server components&lt;/strong&gt;, which render only on the server. If you would like a deeper explanation of server vs client components, you can check out the official documentation on &lt;a href="https://nextjs.org/docs/app/building-your-application/rendering/server-components" rel="noopener noreferrer"&gt;server components&lt;/a&gt; and &lt;a href="https://nextjs.org/docs/app/building-your-application/rendering/client-components" rel="noopener noreferrer"&gt;client components&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next, let's &lt;strong&gt;create our Sign in page&lt;/strong&gt;, so we can use our signin button!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app/signin/page.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;redirect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/navigation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SignInButton&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/SignInButton&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Signin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Please sign in &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;SignInPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex min-h-full flex-1 flex-col justify-center px-6 py-12 lg:px-8"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"sm:mx-auto sm:w-full sm:max-w-sm"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"mt-10 text-center text-2xl font-bold leading-9 tracking-tight text-gray-900"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            Sign in to your account
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"mt-10 sm:mx-auto sm:w-full sm:max-w-sm"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SignInButton&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Regarding the global styling, we can remove almost everything from the &lt;code&gt;global.css&lt;/code&gt; file, and leave only the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app/global.css&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;utilities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will just apply the Tailwind CSS reset, and make it possible to use Tailwind classes inside our components. &lt;/p&gt;

&lt;p&gt;For the home page itself, let's just make it as simple as possible and just leave some text indicating we're on the homepage, and also add our &lt;code&gt;SignOutButton&lt;/code&gt; so we can navigate back to the sign in page:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app/page.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SignOutButton&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./components/SignOutButton&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;header&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"border-b border-gray-200 bg-white"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"mx-auto max-w-7xl px-4"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex gap-10 items-center w-full justify-between lg:justify-end my-2 px-4"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SignOutButton&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;header&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex min-h-screen flex-col items-center justify-between p-24"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello from the homepage!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Running our app now using &lt;code&gt;npm run dev&lt;/code&gt;, and visiting &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt; in the browser should show the following:&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%2Fp34w694jeiu36oc3nhd8.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%2Fp34w694jeiu36oc3nhd8.png" alt="Home page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And clicking on &lt;code&gt;Sign Out&lt;/code&gt;, should take you to the &lt;code&gt;/signin&lt;/code&gt; page, which should look like this:&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%2Fg7uu3k2x9286rwmqe0xh.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%2Fg7uu3k2x9286rwmqe0xh.png" alt="Sign In page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's a link to the acompanying &lt;a href="https://github.com/noblica/next-google-auth" rel="noopener noreferrer"&gt;github repo&lt;/a&gt;, which contains all the code from this blogpost.&lt;br&gt;
I have also deployed this code snippet on Vercel, &lt;a href="https://next-google-auth-lac.vercel.app/signin" rel="noopener noreferrer"&gt;available here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But what good are all these sign in and sign out buttons without some actual authentication logic behind them?&lt;/p&gt;

&lt;p&gt;We will expand on that topic in the following chapter!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>nextjs</category>
      <category>googlecloud</category>
    </item>
    <item>
      <title>The best way to integrate in a new team</title>
      <dc:creator>Dušan Perković</dc:creator>
      <pubDate>Mon, 21 Aug 2023 21:49:46 +0000</pubDate>
      <link>https://dev.to/noblica/the-best-way-to-integrate-in-a-new-team-4k29</link>
      <guid>https://dev.to/noblica/the-best-way-to-integrate-in-a-new-team-4k29</guid>
      <description>&lt;p&gt;As someone who has either worked in distributed teams, or as a remote contractor, I know it can be difficult to integrate in a new team.&lt;/p&gt;

&lt;p&gt;There are many challenges you have to face. Whether it's poor onboarding, lack of clear communication or direction, or a difference in time zones, it's hard to escape the feeling that you're not really part of the team. If not handled properly, this can lead to impostor syndrome, or a "us vs them mentality".&lt;/p&gt;

&lt;p&gt;So what can you do to avoid this if you've just joined a team?&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Avoid communicating through text only
&lt;/h2&gt;

&lt;p&gt;This is especially important in the beginning.&lt;br&gt;
&lt;strong&gt;Text is the worst form of communication&lt;/strong&gt;, by far.&lt;/p&gt;

&lt;p&gt;I know, I know, we all hate being stuck in meetings that seem to go nowhere, or have no value to us. But try to get as much face time with everyone as possible. Have a one-on-one introduction with everyone in the team, from the client(if possible) to the intern. Try and get to know the people you're working with, where they see the project going, what issues they are dealing with right now, or what problems they think might be coming in the future.&lt;/p&gt;

&lt;p&gt;If you communicate only through text, there is a lack of context, tone, and body language. There are only words on the screen, and if the person you're talking to doesn't know you well enough, they can take things the wrong way.&lt;/p&gt;

&lt;p&gt;I'm not saying that you should jump on a video call every time someone asks you to change a border color in CSS. But if requirements are unclear, or you need to explain something to another team member, you should use every tool at your disposal to make it easier to understand each other and push the project forward. Your team members will thank you for reaching out, and feel more connected to you.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Use screen recordings
&lt;/h2&gt;

&lt;p&gt;I promise you, your clients love it when you keep them up to date on what you did. Creating a screen recording and walking them through a feature you just implemented is going to make everyone feel more included in the development process, give you quicker feedback, and make you more visible to the rest of the team.&lt;/p&gt;

&lt;p&gt;As a bonus, you will also catch a lot more bugs before creating PR's, because you will basically be doing QA on yourself.&lt;/p&gt;

&lt;p&gt;Your colleagues will also love it if they ask you to explain something, and instead of writing paragraphs of text, you just send them a screen recording, and all they have to do is press play. &lt;/p&gt;

&lt;p&gt;This is especially useful if you are in separate timezones. I have actually gotten more higher quality feedback on screen recordings like this, then on live demos. Probably because people can watch and comment on it multiple times, at their own pace.&lt;/p&gt;

&lt;p&gt;I use the &lt;a href="https://scre.io/"&gt;scre.io&lt;/a&gt; chrome plugin, since it's the easiest to use, and convert the recording to &lt;code&gt;.mp4&lt;/code&gt; if necessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Take control of your tickets.
&lt;/h2&gt;

&lt;p&gt;I know developers dislike managing tickets (almost as much as they dislike meetings that could've been emails). But if you can help your team organize the work better, they will be forever grateful to you, and you will be able to impact the project on a higher level.&lt;/p&gt;

&lt;p&gt;If you can break features down into small tickets that are easy to implement, you can avoid merge queues, PR's being stuck in review hell for weeks because of unclear requirements, or implementing the same thing multiple times. Your project manager will like you because you'll be helping them out, and your QA team will love you even more if a clear Acceptance Criteria is provided with every ticket. &lt;br&gt;
You are making everyone's life easier, and as a result everyone wins.&lt;/p&gt;

&lt;h2&gt;
  
  
  In conclusion
&lt;/h2&gt;

&lt;p&gt;Remember, you are working with people. If you help make their lives easier, or if you at least try, they will appreciate it and help you out. Building trust may take some time, but a team that trusts and helps each other, is a great team to work in.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>career</category>
      <category>remote</category>
    </item>
    <item>
      <title>How to optimize your Storyblok app</title>
      <dc:creator>Dušan Perković</dc:creator>
      <pubDate>Tue, 15 Aug 2023 15:56:42 +0000</pubDate>
      <link>https://dev.to/noblica/how-to-optimize-your-storyblok-app-55aa</link>
      <guid>https://dev.to/noblica/how-to-optimize-your-storyblok-app-55aa</guid>
      <description>&lt;p&gt;If you are using &lt;a class="mentioned-user" href="https://dev.to/storyblokcom"&gt;@storyblokcom&lt;/a&gt; with NextJS, and following &lt;a href="https://www.storyblok.com/tp/add-a-headless-cms-to-next-js-in-5-minutes"&gt;the official guides from Storyblok&lt;/a&gt;, you know that the usual way to start the project is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a NextJS project using &lt;code&gt;create-next-app&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Install the necessary dependencies to integrate with Storyblok.&lt;/li&gt;
&lt;li&gt;Create your Storyblok components.&lt;/li&gt;
&lt;li&gt;Initialize the NextJS - Storyblok connection by adding the following code to your &lt;code&gt;_app.jsx&lt;/code&gt;.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;storyblokInit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;apiPlugin&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@storyblok/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Feature&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/Feature&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Grid&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/Grid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/Page&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Teaser&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/Teaser&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;components&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Feature&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Grid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;teaser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Teaser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;storyblokInit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your-preview-token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;use&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;apiPlugin&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The problem:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;You are loading all of your components on each page load!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is because the contents of &lt;code&gt;_app.jsx&lt;/code&gt; get executed on every page. So all the JavaScript that is imported in the &lt;code&gt;_app.jsx&lt;/code&gt; file, gets bundled and sent to the client on every page load.&lt;/p&gt;

&lt;p&gt;Since the official guide recommends importing &lt;strong&gt;all&lt;/strong&gt; of your components in the &lt;code&gt;_app.jsx&lt;/code&gt; file, this means that &lt;strong&gt;all&lt;/strong&gt; your component code get loaded on every page. Even if that page is completely static and doesn't use any StoryBlok components at all!&lt;/p&gt;

&lt;p&gt;I ended up creating &lt;a href="https://github.com/storyblok/storyblok-react/issues/595"&gt;a Github issue&lt;/a&gt;, and &lt;a href="https://github.com/storyblok/storyblok-react/pull/598"&gt;implementing this feature via a PR&lt;/a&gt;, on the official &lt;a href="https://github.com/storyblok/storyblok-react"&gt;@storyblok/react&lt;/a&gt; Github repo. I was a bit hesitent about contributing, but the good folks at the &lt;code&gt;@storyblok/react&lt;/code&gt; repo were very kind and accepting of it, so a big thanks to them!&lt;/p&gt;

&lt;h2&gt;
  
  
  How to load only the stuff you need
&lt;/h2&gt;

&lt;p&gt;Instead of loading all your components in the &lt;code&gt;_app.jsx&lt;/code&gt; file, just initialize the connection, and remove any component imports you have, so it looks more like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;storyblokInit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;apiPlugin&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@storyblok/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;storyblokInit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your-preview-token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;use&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;apiPlugin&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, in your page components, use the new &lt;code&gt;setComponents&lt;/code&gt; method, to set only the components you need on that page. So it would look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getStoryblokApi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;StoryblokComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setComponents&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@storyblok/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Feature&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/Feature&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Grid&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/Grid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/Page&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Teaser&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/Teaser&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;story&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;story&lt;/span&gt;
    &lt;span class="nx"&gt;setComponents&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Feature&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Grid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;teaser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Teaser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Head&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Create&lt;/span&gt; &lt;span class="nx"&gt;Next&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/title&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt; &lt;span class="nx"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;icon&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/favicon.ico&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Head&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;story&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;story&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;My Site&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/header&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
         &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;StoryblokComponent&lt;/span&gt; &lt;span class="nx"&gt;blok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;story&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it!&lt;/p&gt;

&lt;p&gt;Now, when NextJS builds your page, it will only include the components imported directly on that page and reduce your JS bundle size per page, improving your SEO and speeding up your page load times.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>storyblok</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Expressive code &gt; Clean code</title>
      <dc:creator>Dušan Perković</dc:creator>
      <pubDate>Wed, 09 Aug 2023 13:02:30 +0000</pubDate>
      <link>https://dev.to/noblica/expressive-code-clean-code-59o7</link>
      <guid>https://dev.to/noblica/expressive-code-clean-code-59o7</guid>
      <description>&lt;p&gt;When people say "clean code", they usually mean "code that's easy to read." I know that the full definition is closer to "code that's easy to read, maintain, understand and change", but people usually get stuck at that first part.&lt;/p&gt;

&lt;p&gt;As a result, "easy to read" usually ends up meaning "small files with only a few lines of code", since developers associate big files with a lot of complexity (and rightfully so). Getting away from this complexity is not as easy as it seems, and is not always the right thing to do.&lt;/p&gt;

&lt;h1&gt;
  
  
  Reducing complexity vs hiding complexity
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kb4QKxgm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/emcc471x2rjhwkky9knk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kb4QKxgm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/emcc471x2rjhwkky9knk.jpg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reducing complexity&lt;/strong&gt; is a good thing. It means you are actually scaling down the complexity of your app. This can include removing some tech debt, or relying on a third-party library to solve your problem, instead of having a bunch of custom code you have to maintain yourself. Reducing complexity basically means you and your co-workers have less of your own code to worry about.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hiding complexity&lt;/strong&gt; is what usually happens. Big files do not look aesthetically pleasing to us, so we come up with excuses and abstractions based on personal feelings. We start moving things away from each other, that logically belong together, and as a result make the code less expressive, harder to understand and more difficult to maintain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not be afraid of big files.&lt;/strong&gt; If the feature you are building is a complex one, the code should reflect that.&lt;/p&gt;

&lt;h1&gt;
  
  
  Abstraction always increases complexity
&lt;/h1&gt;

&lt;p&gt;Even though it might make the codebase "look" smaller, it is actually more complex. Think about what you are doing when you abstract things: you are moving a piece of code away from where it is needed. So now, to understand the full picture of what's going on inside your component, you need to jump back-and-forth between the abstracted piece of code, and the rest of your component, to understand how they work together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To be clear:&lt;/strong&gt; I am not saying that abstraction is always bad, and that you should inline everything. I am saying that you should be very careful with it, when you do it, and for what reason.&lt;/p&gt;

&lt;h1&gt;
  
  
  Expressive code is easier to maintain
&lt;/h1&gt;

&lt;p&gt;Here's an example using &lt;a href="https://tailwindcss.com/"&gt;Tailwind&lt;/a&gt;, taken from &lt;a href="https://levelup.gitconnected.com/how-to-use-tailwind-css-the-clean-way-4bfd46e3113"&gt;this blog post&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;figure&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"md:flex bg-gray-100 rounded-xl p-8 md:p-0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"w-32 h-32 md:w-48 md:h-auto md:rounded-none rounded-full mx-auto"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/sarah-dayan.jpg"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"384"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"512"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"pt-6 md:p-8 text-center md:text-left space-y-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;blockquote&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-lg font-semibold"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        “Tailwind CSS is the only framework that I've seen scale
        on large teams. It’s easy to customize, adapts to any design,
        and the build size is tiny.”
      &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/blockquote&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;figcaption&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"font-medium"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-indigo-600"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        Sarah Dayan
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-gray-500"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        Staff Engineer, Algolia
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/figcaption&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/figure&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Look at all those classes! That's too much, man.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But you only need to understand how tailwind works, to understand what's happening with this component.&lt;/p&gt;

&lt;p&gt;If we want to change how this component looks, we just need to add/remove the corresponding class, and everything is done. Even though there's a lot of it, the code is easy to understand, maintain and extend, even for someone new to the codebase.&lt;/p&gt;

&lt;p&gt;We can also try to abstract these classes to individual CSS selectors, and make the HTML "look pretty", and move all the classes to a separate &lt;code&gt;scss&lt;/code&gt; file that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nt"&gt;figure&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.bg-gray-100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.rounded-xl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.p-8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.md&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nd"&gt;:flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.md&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nd"&gt;:p-0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.w-32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.h-32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.rounded-full&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.mx-auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.md&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nd"&gt;:w-48&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.md&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nd"&gt;:h-auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.md&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nd"&gt;:rounded-none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.pt-6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.text-center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.space-y-4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.md&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nd"&gt;:p-8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.md&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nd"&gt;:text-left&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nt"&gt;blockquote&lt;/span&gt; &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.text-lg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.font-semibold&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nt"&gt;figcaption&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.font-medium&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="nc"&gt;.name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.text-indigo-600&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="nc"&gt;.work-role&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.text-gray-500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And change the HTML to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;figure&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"img/175062.png"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"384"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"512"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;blockquote&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
        “Tailwind CSS is the only framework that I've seen scale
        on large teams. It’s easy to customize, adapts to any design,
        and the build size is tiny.”
      &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/blockquote&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;figcaption&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        Sarah Dayan
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"work-role"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        Staff Engineer, Algolia
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/figcaption&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/figure&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But this makes it harder to understand the component:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The styling of each tag has been moved away from it, so you have to look through the &lt;code&gt;scss&lt;/code&gt; selector to understand what affects what.&lt;/li&gt;
&lt;li&gt;Extending this code is more difficult, because it has to be done in multiple places. And you have to be careful of styles from other selectors impacting each other.&lt;/li&gt;
&lt;li&gt;Maintaining the code is more difficult as well, because you need to make sure you're not deleting/changing the wrong thing in each of the files.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Maintainable &amp;gt; Aesthetic
&lt;/h1&gt;

&lt;p&gt;At the end of the day, we are building products, not competing for the worlds most visually pleasing component. Coding is not the end goal - it's a means to an end. The code that you write has to be maintained and extended by you &lt;strong&gt;and your colleagues&lt;/strong&gt;. Be expressive with what you write, and don't make things more complicated then they have to be.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/gHzSpx_9Eww"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Further reading:&lt;br&gt;
&lt;a href="https://grugbrain.dev/"&gt;The Grug Brained Developer&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>tailwindcss</category>
    </item>
  </channel>
</rss>
