<?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: iskurbanov</title>
    <description>The latest articles on DEV Community by iskurbanov (@iskurbanov).</description>
    <link>https://dev.to/iskurbanov</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%2F697052%2Ffb9688c6-24e5-4939-80e5-74a483097b36.jpeg</url>
      <title>DEV Community: iskurbanov</title>
      <link>https://dev.to/iskurbanov</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/iskurbanov"/>
    <language>en</language>
    <item>
      <title>Shopify App - Theme Extension with React + Tailwind CSS</title>
      <dc:creator>iskurbanov</dc:creator>
      <pubDate>Thu, 03 Aug 2023 00:07:23 +0000</pubDate>
      <link>https://dev.to/iskurbanov/shopify-app-theme-extension-with-react-tailwind-css-3n9e</link>
      <guid>https://dev.to/iskurbanov/shopify-app-theme-extension-with-react-tailwind-css-3n9e</guid>
      <description>&lt;p&gt;&lt;em&gt;Full course available now! 👉 &lt;a href="https://www.buildnextshop.com/shopify-theme-extension-app" rel="noopener noreferrer"&gt;Shopify App Development Crash Course&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the last few years Shopify has been revamping their App CLI and all the tooling.&lt;/p&gt;

&lt;p&gt;We now have the App Theme Extensions here to replace the Script Tag API and make it an improved experience for merchants and their customers. &lt;/p&gt;

&lt;p&gt;Since these upgrades are so new, there is hardly any tutorials on it! &lt;/p&gt;

&lt;p&gt;I am currently building a theme extension app for Shopify. I initially started with Vanilla JS and regular CSS but soon realized that I wouldn't be able to build the customer experience that I wanted to with those tools. Plus it would be a bad developer experience for me also. &lt;/p&gt;

&lt;p&gt;So about 25% way through the project I decided to switch to React and Tailwind CSS for the Theme Extension. However, this wasn't so easy to setup. So I want to share the process with you in this walkthrough!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Full Tech Stack&lt;/em&gt;:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Shopify App CLI&lt;/li&gt;
&lt;li&gt;Vite&lt;/li&gt;
&lt;li&gt;Theme Extension&lt;/li&gt;
&lt;li&gt;React + Tailwind CSS&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 1: Clone Template Extension App
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/iskurbanov/theme-app-extension-react" rel="noopener noreferrer"&gt;Extension Template Github Repo&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Create a test store
&lt;/h3&gt;

&lt;p&gt;In your Shopify Partner Account (it's free), create a test store. &lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Run the app and install it
&lt;/h3&gt;

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

cd your-app-name &amp;amp;&amp;amp; npm install


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

&lt;/div&gt;

&lt;p&gt;Go through all the installation instructions &lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Deploy the extension
&lt;/h3&gt;

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

npm run deploy


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Step 5: Check the Deployment
&lt;/h3&gt;

&lt;p&gt;Go to the Shopify Partner Dashboard -&amp;gt; Apps -&amp;gt; Versions&lt;/p&gt;

&lt;p&gt;And check that the Shopify app was deployed with the extension.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 6: Enable Extension on Store
&lt;/h3&gt;

&lt;p&gt;Run&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

npm run dev


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

&lt;/div&gt;

&lt;p&gt;Install the app by clicking on the link in #1. Then go to link in #2 and navigate to the contact page in the theme. Then select the app from the &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%2Fd1z8jesyoo4ne06u9dca.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%2Fd1z8jesyoo4ne06u9dca.png" alt="Install the App"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add the Extension in the Sections&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fedvxf2db9w4j60av93nn.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%2Fedvxf2db9w4j60av93nn.png" alt="Add Extension Section"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;See the text "Hello From React!" on your page!&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnq40t8mfuh8wo76rj7xg.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%2Fnq40t8mfuh8wo76rj7xg.png" alt="See the text "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Great! You now should have a working Shopify App Theme Extension that you can work on! 🎉 🎉 🎉&lt;/p&gt;

</description>
      <category>shopify</category>
      <category>react</category>
      <category>vite</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>Building OpenWorldAI.com</title>
      <dc:creator>iskurbanov</dc:creator>
      <pubDate>Wed, 03 May 2023 10:34:54 +0000</pubDate>
      <link>https://dev.to/iskurbanov/building-openworldaicom-3i14</link>
      <guid>https://dev.to/iskurbanov/building-openworldaicom-3i14</guid>
      <description>&lt;p&gt;I just have finishing putting together the beta version of &lt;a href="https://openworldai.com"&gt;openworldai.com&lt;/a&gt; which right now is just a directory for AI projects. &lt;/p&gt;

&lt;p&gt;My goal with the website is to build it out to be a hub for all things AI. That includes interesting projects, community, news, and aggregating newsletters. &lt;/p&gt;

&lt;p&gt;This post is to share my process of building it and the tech stack that I used. I want to eventually open source the frontend. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Stack
&lt;/h2&gt;

&lt;p&gt;To build out the MVP of this project I went with the following stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Next.js for the React Framework&lt;/li&gt;
&lt;li&gt;Next-Auth for authentication&lt;/li&gt;
&lt;li&gt;Prisma for the ORM for my database&lt;/li&gt;
&lt;li&gt;PlanetScale for my database &lt;/li&gt;
&lt;li&gt;Tailwind CSS for styling&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://preline.co"&gt;Preline.co&lt;/a&gt; for Tailwind components&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://screenshotone.com/"&gt;ScreenshotOne&lt;/a&gt; for taking bulk screenshots&lt;/li&gt;
&lt;li&gt;ChatGPT for debugging and prototyping&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Future additions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Algolia for semantic search (this is a huge addition that I believe will be seen on all websites in the near future)&lt;/li&gt;
&lt;li&gt;Better project adding flow (the flow is too manual at the moment)&lt;/li&gt;
&lt;li&gt;Blog (to improve SEO)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Deeper dive on how it works
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Next.js&lt;/strong&gt;&lt;br&gt;
The project is currently all serverless, built with the Next.js API routes whenever they are needed. &lt;/p&gt;

&lt;p&gt;To add projects I currently just seed the database using Prisma. Which is working quite well. I also have a seed file where I call the OpenAI API to generate the description for each project and categorize it. Doing this at scale would take way too much time so I decided to automate that process from the beginning. It is working quite well!&lt;/p&gt;

&lt;p&gt;I also use a puppeteer scrapper to get the website text and feed it into OpenAI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Puppeteer Scrapper + OpenAI&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;puppeteer&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OpenAIApi&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;openai&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;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&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;configuration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sk-******&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;openai&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OpenAIApi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;);&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;generateSEOContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createChatCompletion&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gpt-3.5-turbo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;prompt&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="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;message&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="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error generating SEO content:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generateProjectName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createChatCompletion&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gpt-3.5-turbo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;prompt&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="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;message&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="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error generating project name:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generateCategoriesAndSubcategories&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createChatCompletion&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gpt-3.5-turbo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;prompt&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;categoriesAndSubcategories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;message&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="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;categoriesAndSubcategories:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;categoriesAndSubcategories&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;categoryMatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;categoriesAndSubcategories&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/categories: &lt;/span&gt;&lt;span class="se"&gt;(\[[^\]]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;\])&lt;/span&gt;&lt;span class="sr"&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;subcategoryMatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;categoriesAndSubcategories&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/subcategories: &lt;/span&gt;&lt;span class="se"&gt;(\[[^\]]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;\])&lt;/span&gt;&lt;span class="sr"&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;categories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;categoryMatch&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;categoryMatch&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="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;subcategories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;subcategoryMatch&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subcategoryMatch&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="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="nx"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;subcategories&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error generating categories and subcategories:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&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="na"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="na"&gt;subcategories&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;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getTextFromURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&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;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;headless&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;new&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;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newPage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;waitUntil&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;networkidle2&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;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Error fetching text from URL: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&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;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getTextFromURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&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;projectNamePrompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Get the project name for the following website content, only output the name:\n\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n\n`&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;projectName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;generateProjectName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;projectNamePrompt&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;seoTitlePrompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Generate an SEO optimized title for the following website content:\n\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n\n`&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;seoTitle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;generateSEOContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;seoTitlePrompt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SEO Title:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;seoTitle&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;seoShortDescPrompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Generate an SEO optimized short description for the following website content:\n\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n\n`&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;seoShortDesc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;generateSEOContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;seoShortDescPrompt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SEO Short Description:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;seoShortDesc&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;seoLongDescPrompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Generate an SEO optimized long description between 1000-1500 characters for the following website content:\n\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n\n`&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;seoLongDesc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;generateSEOContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;seoLongDescPrompt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SEO Long Description:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;seoLongDesc&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;categoryPrompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Here is a list of categories and their subcategories, only use these options: 
  text:[copywriting,email assistant,general writing,prompts,seo,social media assistant,summarizer]
  image:[art,avatars,design assistant,image editing,image generation,logo generation]
  code:[code assistant,low-code,no-code]
  audio:[audio editing,music,text to speech,transcriber]
  video:[personalized videos,video editing,video generation]
  business:[customer support,e-commerce,education assistant,finance,human resources,legal,presentations,productivity,real estate,sales,marketing]
  other:[dating,experimental,fitness,gaming,healthcare,life assistant,research,resources,search engine,travel]

  Analyze the following website content and assign it to categories and subcategories: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;seoLongDesc&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
  Return output in this format:
  categories: ["categories", "categories"]
  subcategories: ["subcategories", "subcategories","subcategories"]`&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;categoriesAndSubcategories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;generateCategoriesAndSubcategories&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;categoryPrompt&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;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;removeOuterQuotes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;removeOuterQuotes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;seoTitle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;removeOuterQuotes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;seoTitle&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;seoShortDesc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;removeOuterQuotes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;seoShortDesc&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;seoLongDesc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;removeOuterQuotes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;seoLongDesc&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;categoriesAndSubcategories&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;subcategories&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;categoriesAndSubcategories&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subcategories&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;output&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;output.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&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;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error reading output.json:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&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;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Parse the content of the file as a JSON array&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;projects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Add the new output to the array&lt;/span&gt;
    &lt;span class="nx"&gt;projects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Write the updated array back to the file&lt;/span&gt;
    &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;output.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;projects&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&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;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error writing to output.json:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Project output added to output.json.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&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;processURLs&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;outputArray&lt;/span&gt; &lt;span class="o"&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;urls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;readURLsFromFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;urls2.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;for &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;url&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;urls&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;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;outputArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// You can also write the outputArray to a JSON file if needed.&lt;/span&gt;
  &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;output2.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outputArray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;processURLs&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;removeOuterQuotes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;"&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;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;"&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;return&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;readURLsFromFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filename&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;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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 allows me to feed it an array of URLs and it returns an json object with all the data I need for the website. I then run another seed that takes a screenshot for all the websites. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tailwind CSS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'm not a huge fan of styling and css so I use Tailwind and component libraries where I can. I have recently stumbled upon Preline.co and loved it so I used some of their components and modified them to fit my style. &lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Prisma + PlanetScale&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;These 2 go really well together and I haven't done much configuration to it since I have set up initially. Which is what I expect from a good ORM and a database. Less time managing it and more time building. &lt;/p&gt;

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

&lt;p&gt;That is pretty much it for the MVP. I will try to add updates as I add more features to the site. I'm really looking forward to growing it and open sourcing the frontend when it's ready. &lt;/p&gt;

&lt;p&gt;You can checkout the website in its current form at &lt;a href="https://openworldai.com"&gt;OpenWorldAI.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let me know your thoughts and what you would like to see on the project!&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>prisma</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>What is the internet again?</title>
      <dc:creator>iskurbanov</dc:creator>
      <pubDate>Tue, 28 Mar 2023 22:17:40 +0000</pubDate>
      <link>https://dev.to/iskurbanov/what-is-the-internet-again-36d0</link>
      <guid>https://dev.to/iskurbanov/what-is-the-internet-again-36d0</guid>
      <description>&lt;p&gt;I have been in the tech scene since about 2017. Since then I have had the pleasure of learning programming, using social media, dabbling in crypto and AI, and all the other aspects of the internet that we all love and cherish. But what really is the internet? And why has it consumed our lives on such a massive level?&lt;/p&gt;

&lt;p&gt;It is easy to get consumed by the internet and forget what it really is. When I asked myself what is the internet on the first principles level, it came down to 'information'.&lt;/p&gt;

&lt;p&gt;There is a reason why, afterall, it is called Information Technology (IT). At the end of the day, the internet is simply a way for information to travel from one person to another. &lt;/p&gt;

&lt;h2&gt;
  
  
  So what does that mean?
&lt;/h2&gt;

&lt;p&gt;Well it means that the underlying purpose of the this thing we call the internet is to get and send (exchange) information. &lt;/p&gt;

&lt;p&gt;For example, you want to buy a toothbrush from a company. What are you options to communicate with them? &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Walk to their store for an in-person purchase. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Call them on the telephone to place your order. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Send them a letter with your order. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go online!&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Going Online
&lt;/h2&gt;

&lt;p&gt;So what is 'Going Online'? Well, it's kind of like a really advanced newspaper. Like the one from Harry Potter with the moving images. Or as we call them on the internet, GIFs. Except it doesn't just contain GIFs, but all kinds of content. AND we can interact with the content. &lt;/p&gt;

&lt;p&gt;The internet is simply a way for us to communicate information in a convenient way to make our physical lives easier and better for each other. &lt;/p&gt;

&lt;h2&gt;
  
  
  Internet 1.0
&lt;/h2&gt;

&lt;p&gt;Internet 1.0 was exactly that. It was a newspaper ONLINE. Companies were using the internet to replicate what they were already doing in the physical world onto the internet and allow for their information to be more easily distributed. Because the main purpose of the newspaper was to convey information. There is no other purpose for the newspaper. No, not even to start your backyard fire. &lt;/p&gt;

&lt;h2&gt;
  
  
  Internet 2.0
&lt;/h2&gt;

&lt;p&gt;I am not sure about the exact version definitions but the next version of the internet was something like Amazon. Where the next phase of the information entered the internet. This was the purchase phase. &lt;strong&gt;None of this factually correct, by the way.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;The purchase phase contained much more complicated information that needed to be conveyed from our person to another and involved additional technological advancements. Things like security, complicated databases, and payment processing entered the scene. &lt;/p&gt;

&lt;p&gt;Companies started to hire more talent to be able to facilitate all of this information. And the convenience of buying books and other things online started to draw in more people. &lt;/p&gt;

&lt;p&gt;Let's take the example of buying a book online. This simple process involved multiple exchanges of information from multiple people. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Amazon creates a website that is able to host information and process payments. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Businesses list the information about their books on Amazon.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Person logs onto Amazon and inputs their information and sends their order details to Amazon.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Amazon then digests that information and sends the relevant details to the book merchant. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All of this information exchange would be nearly impossible to facilitate within seconds without the use of the internet.  &lt;/p&gt;

&lt;p&gt;That. That is the value proposition of the internet. &lt;/p&gt;

&lt;h2&gt;
  
  
  Internet 3.0 (again I could be wrong with the version here)
&lt;/h2&gt;

&lt;p&gt;Social. More and more information started to migrate online. People started spending more time online and consuming more information. There goes that word again, 'information'. &lt;/p&gt;

&lt;p&gt;Now the structure of the information is incredibly complex. Hundreds of layers of technology is lubricating the exchange of information. Dozens of new industries are born and billions of lives are impacted by this new way of sending and receiving information. &lt;/p&gt;

&lt;h3&gt;
  
  
  Internet 4.0 and Beyond: The Future of the Internet:
&lt;/h3&gt;

&lt;p&gt;As we look towards the future of the internet, we can expect a continued evolution of the ways in which we exchange information. The next phase, often referred to as Internet 4.0, will likely be characterized by the integration of advanced technologies, such as Artificial Intelligence (AI), the Internet of Things (IoT), and blockchain, among others. These technologies have the potential to further revolutionize the ways we interact, both with each other and with the devices that surround us.&lt;/p&gt;

&lt;p&gt;Furthermore, AI will become increasingly integrated into the fabric of the internet, offering personalized experiences and streamlining our interactions with technology. While virtual assistants will become more advanced and capable of handling a wider range of tasks.&lt;/p&gt;

&lt;p&gt;The way we use the internet might change into something we don't recognize at all. Will we need search engines if AI can answer any question we have? Or teach us anything that we might want to learn?&lt;/p&gt;

&lt;p&gt;How will social media change if the majority of the content is AI generated? &lt;/p&gt;

&lt;p&gt;Will the transfer of data be so seamless that it will require less of our input?&lt;/p&gt;

&lt;p&gt;Will all of this allow us to spend more time of our days doing what we enjoy most? Or will we all be even more caught up in the pursuit of money, productivity, and happiness?&lt;/p&gt;

</description>
      <category>watercooler</category>
    </item>
    <item>
      <title>10 Free Next.js Templates and Hidden Gems 2023</title>
      <dc:creator>iskurbanov</dc:creator>
      <pubDate>Tue, 28 Mar 2023 22:05:57 +0000</pubDate>
      <link>https://dev.to/iskurbanov/free-nextjs-templates-and-hidden-gems-2023-22m8</link>
      <guid>https://dev.to/iskurbanov/free-nextjs-templates-and-hidden-gems-2023-22m8</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;em&gt;Bookmark it ;)&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I often find myself spending a lot of time searching for free Next.js resources whenever I start a new project and they seem to be very difficult to find at times!&lt;/p&gt;

&lt;p&gt;I ended up spending a good few days picking out the best free templates (and UI kits) from across the Google and Github and adding them all to this list. &lt;/p&gt;

&lt;p&gt;The criteria for my list was that the resource has to be high quality, use latest versions of packages, and open source/MIT license or free. &lt;/p&gt;

&lt;p&gt;This is an unorganized list in no particular order. I just wanted to have this for myself next time I start a new project and wanted to share it with all of you so you can bookmark this and save some time!&lt;/p&gt;

&lt;p&gt;Let's go!&lt;/p&gt;




&lt;h4&gt;
  
  
  1. &lt;strong&gt;Beautifully designed components built with Radix UI and Tailwind CSS.&lt;/strong&gt;
&lt;/h4&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%2Fodrw4jurif4zg3dslx7h.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%2Fodrw4jurif4zg3dslx7h.png" alt="components built with Radix UI and Tailwind CSS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ui.shadcn.com/" rel="noopener noreferrer"&gt;Live Demo&lt;/a&gt; | &lt;a href="https://github.com/shadcn/ui" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Radix UI Primitives&lt;/li&gt;
&lt;li&gt;Tailwind CSS&lt;/li&gt;
&lt;li&gt;Fonts with @next/font&lt;/li&gt;
&lt;li&gt;Icons from Lucide&lt;/li&gt;
&lt;li&gt;Dark mode with next-themes&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  2. &lt;strong&gt;Ultimate Front-end Template&lt;/strong&gt;
&lt;/h4&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%2Fikhie8cglz6wbu3zvcpx.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%2Fikhie8cglz6wbu3zvcpx.png" alt="Ultimate Front-end Template"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://template.cretu.dev/" rel="noopener noreferrer"&gt;Live Demo&lt;/a&gt; | &lt;a href="https://github.com/cristicretu/ts-next-tailwind-template" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modern Stack (Next.js + TailwindCSS)&lt;/li&gt;
&lt;li&gt;TypeScript support&lt;/li&gt;
&lt;li&gt;Minimal Design&lt;/li&gt;
&lt;li&gt;Dark Mode&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  3. &lt;strong&gt;Personal Site with Next.js 13, TailwindCSS, Framer Motion, Upstash&lt;/strong&gt;
&lt;/h4&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%2Fsmk7xffer6gr4jzrjvqf.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%2Fsmk7xffer6gr4jzrjvqf.png" alt="Personal Site"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://chronark.com/" rel="noopener noreferrer"&gt;Live Demo&lt;/a&gt; | &lt;a href="https://github.com/chronark/chronark.com" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modern Stack (Next.js 13 + app-router)&lt;/li&gt;
&lt;li&gt;TailwindCSS&lt;/li&gt;
&lt;li&gt;Framer Motion&lt;/li&gt;
&lt;li&gt;Tracking page views by Upstash serverless redis&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  4. &lt;strong&gt;A React Portfolio Template using Next.js and Tailwind CSS&lt;/strong&gt;
&lt;/h4&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%2F9l35xwfbo6sf94y9mv39.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%2F9l35xwfbo6sf94y9mv39.png" alt="React Portfolio Template"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://react-portfolio-template.netlify.app/" rel="noopener noreferrer"&gt;Live Demo&lt;/a&gt; | &lt;a href="https://github.com/LionStrate/react-portfolio-template?ref=reactjsexample.com" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modern Stack (Next.js + TailwindCSS)&lt;/li&gt;
&lt;li&gt;Minimal Design&lt;/li&gt;
&lt;li&gt;Dark Mode&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  5. &lt;strong&gt;DaisyUI - Use Tailwind CSS but write fewer classnames&lt;/strong&gt;
&lt;/h4&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%2F5jop3jtpbc7vw7cr2x3o.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%2F5jop3jtpbc7vw7cr2x3o.png" alt="DaisyUI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://daisyui.com/" rel="noopener noreferrer"&gt;Live Demo&lt;/a&gt; | &lt;a href="https://github.com/saadeghi/daisyui" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A plugin for Tailwind CSS&lt;/li&gt;
&lt;li&gt;Faster development&lt;/li&gt;
&lt;li&gt;Cleaner HTML&lt;/li&gt;
&lt;li&gt;Customizable and themeable&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  6. &lt;strong&gt;The T3 Stack - Full-stack, typesafe Next.js starter&lt;/strong&gt;
&lt;/h4&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%2F9z57qrrdk2m868cfb44t.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%2F9z57qrrdk2m868cfb44t.png" alt="The T3 Stack"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://create.t3.gg/" rel="noopener noreferrer"&gt;Live Demo&lt;/a&gt; | &lt;a href="https://github.com/t3-oss/create-t3-app" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Full Stack (Next.js, Prisma, Tailwind CSS)&lt;/li&gt;
&lt;li&gt;TypeScript support&lt;/li&gt;
&lt;li&gt;Authentication using NextAuth.js&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  7. &lt;strong&gt;Tremor - React library to build dashboards fast&lt;/strong&gt;
&lt;/h4&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%2Fr4p8e51230mfpqoqmslg.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%2Fr4p8e51230mfpqoqmslg.png" alt="Tremor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.tremor.so/" rel="noopener noreferrer"&gt;Live Demo&lt;/a&gt; | &lt;a href="https://github.com/tremorlabs/tremor" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Built on top of Tailwind CSS&lt;/li&gt;
&lt;li&gt;Full Next.js support&lt;/li&gt;
&lt;li&gt;TypeScript support&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  8. &lt;strong&gt;Precedent - collection of components, hooks, and utilities for your Next.js project&lt;/strong&gt;
&lt;/h4&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%2F93btx1zjz4p8nzrxiqey.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%2F93btx1zjz4p8nzrxiqey.png" alt="Precedent"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://precedent.dev/" rel="noopener noreferrer"&gt;Live Demo&lt;/a&gt; | &lt;a href="https://github.com/steven-tey/precedent" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Full Stack (Next.js 13, Prisma)&lt;/li&gt;
&lt;li&gt;Tailwind CSS&lt;/li&gt;
&lt;li&gt;Radix UI&lt;/li&gt;
&lt;li&gt;Framer Motion&lt;/li&gt;
&lt;li&gt;TypeScript support&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  9. &lt;strong&gt;Platforms - template for site builders and low-code tools.&lt;/strong&gt;
&lt;/h4&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%2F0xuwdu04n81pxw2qn4v3.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%2F0xuwdu04n81pxw2qn4v3.png" alt="Platforms"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://demo.vercel.pub/" rel="noopener noreferrer"&gt;Live Demo&lt;/a&gt; | &lt;a href="https://github.com/vercel/platforms" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Full Stack (Next.js 13, Prisma)&lt;/li&gt;
&lt;li&gt;Tailwind CSS&lt;/li&gt;
&lt;li&gt;PlanetScale database&lt;/li&gt;
&lt;li&gt;Authentication using NextAuth.js&lt;/li&gt;
&lt;li&gt;TypeScript support&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  10. &lt;strong&gt;Full Stack Personal Website by Brian Lovin&lt;/strong&gt;
&lt;/h4&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%2Fntfocylr3e8ue0we5ew4.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%2Fntfocylr3e8ue0we5ew4.png" alt="Personal Website by Brian Lovin"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://brianlovin.com/" rel="noopener noreferrer"&gt;Live Demo&lt;/a&gt; | &lt;a href="https://github.com/brianlovin/briOS" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Full Stack (Next.js 13, Prisma)&lt;/li&gt;
&lt;li&gt;Tailwind CSS&lt;/li&gt;
&lt;li&gt;TypeScript support&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;That's it! There are dozens of other templates I could have included but I wanted to keep this list short and sweet so that it can be a quick reference for your future projects. &lt;/p&gt;

&lt;p&gt;Article is presented by &lt;a href="https://openworldai.com" rel="noopener noreferrer"&gt;OpenWorldAI.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>nextjs</category>
      <category>javascript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Next.js 13 Image Cheatsheet</title>
      <dc:creator>iskurbanov</dc:creator>
      <pubDate>Thu, 16 Mar 2023 23:33:08 +0000</pubDate>
      <link>https://dev.to/iskurbanov/nextjs-13-image-cheatsheet-55fd</link>
      <guid>https://dev.to/iskurbanov/nextjs-13-image-cheatsheet-55fd</guid>
      <description>&lt;p&gt;This cheat sheet is meant to provide an overview of the important features and usage of the Next.js Image Component, which helps to optimize and enhance your images.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic Usage
&lt;/h2&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="nx"&gt;Image&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;next/image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Image&lt;/span&gt;
      &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/profile.png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Picture of the author&lt;/span&gt;&lt;span class="dl"&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;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Required Props
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;src&lt;/code&gt;: The image source, can be an internal path or an external URL.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;width&lt;/code&gt;: The rendered width in pixels.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;height&lt;/code&gt;: The rendered height in pixels.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;alt&lt;/code&gt;: Description of the image for screen readers and search engines.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Optional Props
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;loader&lt;/code&gt;: A custom function used to resolve image URLs.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fill&lt;/code&gt;: Boolean that causes the image to fill the parent element.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sizes&lt;/code&gt;: A string that provides information about how wide the image will be at different breakpoints.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;quality&lt;/code&gt;: The quality of the optimized image, an integer between 1 and 100.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;priority&lt;/code&gt;: When true, the image will be considered high priority and preload.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;placeholder&lt;/code&gt;: A placeholder to use while the image is loading.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;style&lt;/code&gt;: Allows passing CSS styles to the underlying image element.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;onLoadingComplete&lt;/code&gt;: A callback function that is invoked once the image is completely loaded and the placeholder has been removed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;onLoad&lt;/code&gt;: A callback function that is invoked when the image is loaded.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;onError&lt;/code&gt;: A callback function that is invoked if the image fails to load.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;loading&lt;/code&gt;: The loading behavior of the image. Defaults to lazy.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;blurDataURL&lt;/code&gt;: A Data URL to be used as a placeholder image before the src image successfully loads.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;unoptimized&lt;/code&gt;: When true, the source image will be served as-is instead of changing quality, size, or format.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configuration Options
&lt;/h2&gt;

&lt;p&gt;Configure the Image Component in &lt;code&gt;next.config.js&lt;/code&gt;. The following options are available:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;remotePatterns&lt;/code&gt;: Configuration required for using external images.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;domains&lt;/code&gt;: A list of allowed hostnames for external images.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Recommended way&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: '**.example.com',
      },
    ],
  },
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
  images: {
    domains: ['assets.acme.com'],
  },
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example usages of the Image component can be found at this repo: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/vercel/next.js/tree/canary/examples/image-component/pages"&gt;Image Examples&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>image</category>
    </item>
    <item>
      <title>Step by step: Multi-Tenant App with Next.js</title>
      <dc:creator>iskurbanov</dc:creator>
      <pubDate>Wed, 01 Mar 2023 23:23:35 +0000</pubDate>
      <link>https://dev.to/iskurbanov/step-by-step-multi-tenant-app-with-nextjs-2mbc</link>
      <guid>https://dev.to/iskurbanov/step-by-step-multi-tenant-app-with-nextjs-2mbc</guid>
      <description>&lt;p&gt;Next.js now allows you to easily create a multi-tenant application using subdomains. This enables you to create web apps like Linktree, Super.so, and other apps where a user gets their own webpage for example. &lt;/p&gt;

&lt;p&gt;Before we start, here are some additional resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://vercel.com/guides/nextjs-multi-tenant-application" rel="noopener noreferrer"&gt;Platforms Starter Kit Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://demo.vercel.pub/platforms-starter-kit" rel="noopener noreferrer"&gt;Platforms Starter Kit Demo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/vercel/static-fun" rel="noopener noreferrer"&gt;Example of a webpage builder&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/vercel/examples/tree/main/edge-middleware/hostname-rewrites" rel="noopener noreferrer"&gt;Hostname rewrites example&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Create a blank Next.js app
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;npx create-next-app&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You will be asked if you want Typescript, ESLint and other options. Hit yes for everything. &lt;/p&gt;

&lt;p&gt;Once the app is created, open it in your code editor (VSCode).&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Deploy app to Vercel
&lt;/h2&gt;

&lt;p&gt;You can do inside VSCode by opening the terminal (Command + J on Mac). &lt;/p&gt;

&lt;p&gt;Install the Vercel CLI:&lt;br&gt;
&lt;code&gt;npm i -g vercel&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once that is done, go ahead and run:&lt;br&gt;
&lt;code&gt;vercel --prod&lt;/code&gt; to deploy it to production&lt;/p&gt;

&lt;p&gt;Click on the deployment link to end up in the Vercel dashboard. &lt;/p&gt;
&lt;h2&gt;
  
  
  Step 3: Setup your domain
&lt;/h2&gt;

&lt;p&gt;In order to use the subdomain feature in Vercel, you will need to setup your own wildcard domain. If you are a developer, you should have plenty of unused domains ;) &lt;/p&gt;

&lt;p&gt;Mine is called buildwithnext.com&lt;/p&gt;

&lt;p&gt;I am using Namecheap so here is how you do it:&lt;/p&gt;

&lt;p&gt;In the Vercel dashboard add your wildcard domain&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flhmzs7zasqscu2twm1b6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flhmzs7zasqscu2twm1b6.png" alt="Adding a wildcard domain in Vercel" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then log into your Namecheap account and add the following Nameserver DNS urls&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frfacj2822saebkyqb4ok.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frfacj2822saebkyqb4ok.png" alt="Set up custom Nameserver DNS in Namecheap" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;When you add a wildcard domain, Vercel will automatically populate all the other ones for you.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 4: Setting up routing in Next.js
&lt;/h2&gt;

&lt;p&gt;Add a new folder in the pages folder called &lt;code&gt;_sites&lt;/code&gt; and then another one in there called &lt;code&gt;[site]&lt;/code&gt;. Then add an index.tsx file in the &lt;code&gt;[site]&lt;/code&gt; folder. &lt;/p&gt;

&lt;p&gt;Your new folder structure should now look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pages
└───api
└───sites
│      │
│    [site]
│      │  index.tsx
package.json
etc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the index.tsx file, add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useRouter } from "next/router";
// we will create these in the next step
import { getHostnameDataBySubdomain, getSubdomainPaths } from "@/lib/db";

// Our types for the site data
export interface Props {
  name: String
  description: String
  subdomain: String
  customDomain: String
}

export default function Index(props: Props) {
  const router = useRouter()

  if (router.isFallback) {
    return (
      &amp;lt;&amp;gt;
        &amp;lt;p&amp;gt;
          Loading...
        &amp;lt;/p&amp;gt;
      &amp;lt;/&amp;gt;
    )
  }

  return (
    &amp;lt;&amp;gt;
      &amp;lt;h1&amp;gt;
        {props.name}
      &amp;lt;/h1&amp;gt;
    &amp;lt;/&amp;gt;
  )
}

// Getting the paths for all the subdomains in our database
export async function getStaticPaths() {
  const paths = await getSubdomainPaths()

  return {
    paths,
    fallback: true
  }
}

// Getting data to display on each custom subdomain
export async function getStaticProps({ params: { site } }) {
  const sites = await getHostnameDataBySubdomain(site)

  return {
    props: sites,
    revalidate: 3600
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Adding Middleware and mock data
&lt;/h2&gt;

&lt;p&gt;A middleware file allows us to intercept the api calls to our backend and do something with it. In this case we are using the middleware to determine what hostname the api call is being made for and display the correct data. &lt;/p&gt;

&lt;p&gt;Let's create a &lt;code&gt;middleware.ts&lt;/code&gt; file in the root of our project directory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pages
└───api
└───sites
│      │
│    [site]
│      │  index.tsx
middleware.ts
package.json
etc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside of the middleware.ts file, add this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { NextRequest, NextResponse } from 'next/server'
import { getHostnameDataOrDefault } from './lib/db'

export const config = {
  matcher: ['/', '/about', '/_sites/:path'],
}

export default async function middleware(req: NextRequest) {
  const url = req.nextUrl

  // Get hostname (e.g. vercel.com, test.vercel.app, etc.)
  const hostname = req.headers.get('host')

  // If localhost, assign the host value manually
  // If prod, get the custom domain/subdomain value by removing the root URL
  // (in the case of "subdomain-3.localhost:3000", "localhost:3000" is the root URL)
  // process.env.NODE_ENV === "production" indicates that the app is deployed to a production environment
  // process.env.VERCEL === "1" indicates that the app is deployed on Vercel
  const currentHost =
    process.env.NODE_ENV === "production" &amp;amp;&amp;amp; process.env.VERCEL === "1"
      ? hostname
        .replace(`.buildwithnext.com`, "")
      : hostname.replace(`.localhost:3000`, "");



  const data = await getHostnameDataOrDefault(currentHost)

  // Prevent security issues – users should not be able to canonically access
  // the pages/sites folder and its respective contents.
  if (url.pathname.startsWith(`/_sites`)) {
    url.pathname = `/404`
  } else {
    // console.log('URL 2', req.nextUrl.href)
    // rewrite to the current subdomain under the pages/sites folder
    url.pathname = `/_sites/${data.subdomain}${url.pathname}`
  }

  return NextResponse.rewrite(url)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is a lot happening here but I tried to add more comments to clear things up. It might look scary at first but try going line by line and reading the comments. It will eventually make sense. &lt;/p&gt;

&lt;p&gt;Now let's go ahead and add a lib folder in the root of our project directory and a db.ts file inside of it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lib
└───db.ts
pages
└───api
└───sites
│      │
│    [site]
│      │  index.tsx
middleware.ts
package.json
etc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside of the db.ts file, add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Dummy data to be replaced with your database
const hostnamesDB = [
  {
    name: 'This is Site 1',
    description: 'Subdomain + custom domain',
    subdomain: 'test1',
    customDomain: 'custom-domain-1.com',
    // Default subdomain for Preview deployments and for local development
    defaultForPreview: true,
  },
  {
    name: 'This is Site 2',
    description: 'Subdomain only',
    subdomain: 'test2',
  },
  {
    name: 'This is Site 3',
    description: 'Subdomain only',
    subdomain: 'test3',
  },
]
const DEFAULT_HOST = hostnamesDB.find((h) =&amp;gt; h.defaultForPreview)

/**
 * Returns the data of the hostname based on its subdomain or custom domain
 * or the default host if there's no match.
 *
 * This method is used by middleware.ts
 */
export async function getHostnameDataOrDefault(
  subdomainOrCustomDomain?: string
) {
  if (!subdomainOrCustomDomain) return DEFAULT_HOST

  // check if site is a custom domain or a subdomain
  const customDomain = subdomainOrCustomDomain.includes('.')

  // fetch data from mock database using the site value as the key
  return (
    hostnamesDB.find((item) =&amp;gt;
      customDomain
        ? item.customDomain === subdomainOrCustomDomain
        : item.subdomain === subdomainOrCustomDomain
    ) ?? DEFAULT_HOST
  )
}

/**
 * Returns the data of the hostname based on its subdomain.
 *
 * This method is used by pages under middleware.ts
 */
export async function getHostnameDataBySubdomain(subdomain: string) {
  return hostnamesDB.find((item) =&amp;gt; item.subdomain === subdomain)
}

/**
 * Returns the paths for `getStaticPaths` based on the subdomain of every
 * available hostname.
 */
export async function getSubdomainPaths() {
  // get all sites that have subdomains set up
  const subdomains = hostnamesDB.filter((item) =&amp;gt; item.subdomain)

  // build paths for each of the sites in the previous two lists
  return subdomains.map((item) =&amp;gt; {
    return { params: { site: item.subdomain } }
  })
}

export default hostnamesDB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This one is pretty self explanatory. We basically have some dummy data that we use to get the subdomain and the data to display on the frontend. &lt;/p&gt;

&lt;p&gt;Again, go line by line and read the comments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Test the app and deploy
&lt;/h2&gt;

&lt;p&gt;We can now run &lt;code&gt;npm run dev&lt;/code&gt; to test the app. &lt;/p&gt;

&lt;p&gt;Navigate to localhost:3000 (make sure you are running on localhost:3000 because that's what we put in the middleware.ts file).&lt;/p&gt;

&lt;p&gt;Now you can try to go to &lt;code&gt;test2.localhost:3000&lt;/code&gt;. The content should change to &lt;code&gt;This is Site 2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It should work the same way if you deploy your application now! &lt;code&gt;vercel --prod&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjx7x926ckrdgzviivwpy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjx7x926ckrdgzviivwpy.png" alt="Next.js app running a multi-tenant architecture" width="622" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: Next Steps
&lt;/h2&gt;

&lt;p&gt;You can now replace the dummy data with a database such as PlanetScale and use the Prisma ORM to have your users setup their own subdomain and add data to their sites! I'll be adding more tutorials on how to do that so stay tuned. &lt;/p&gt;

&lt;p&gt;I hope this article was helpful!&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>architecture</category>
      <category>security</category>
      <category>monitoring</category>
    </item>
    <item>
      <title>Low-code solutions for Indie Hacking in 2023?</title>
      <dc:creator>iskurbanov</dc:creator>
      <pubDate>Tue, 07 Feb 2023 13:16:42 +0000</pubDate>
      <link>https://dev.to/iskurbanov/low-code-solutions-for-indie-hacking-in-2023-508i</link>
      <guid>https://dev.to/iskurbanov/low-code-solutions-for-indie-hacking-in-2023-508i</guid>
      <description>&lt;p&gt;I initially pursued becoming a developer because I wanted to build my ideas out and learning to code seemed to be the easiest way. You can just come up with solutions to problems anywhere in the world using just your laptop. Being more on the introverted side, I never liked to be in the "field" talking to prospects and selling face to face (door to door) or on the phone (I've tried and I sucked at it). &lt;/p&gt;

&lt;p&gt;Learning software development was empowering, but at the same time it didn't make things much easier right away. You still have to pick a programming language, framework, and the learning never seems to stop. &lt;/p&gt;

&lt;h2&gt;
  
  
  What about No-Code?
&lt;/h2&gt;

&lt;p&gt;Over the past few there has been an explosion of low-code and no-code solutions but it still feels like there isn't enough. There is still a big barrier between your idea and the product. Additionally, many developer entrepreneurs don't want to pay a monthly fee for something they can build themselves. I can relate. &lt;/p&gt;

&lt;p&gt;Why pay $29/month for something that can easily be deployed to Vercel for free? Especially if you are just testing out an idea. &lt;/p&gt;

&lt;h2&gt;
  
  
  Templates?
&lt;/h2&gt;

&lt;p&gt;Wordpress and Shopify themes have a good model for getting a solution up and running quickly. And recently there have been more code-oriented templates on the market like TailwindUI and such. But those are just landing page templates. What about if you want to build something fullstack? Like a job board or a directory. You will have to dig through GitHub and be lucky to stumble upon a template. But even then, you will need to spend about a week learning the stack that is used and most times those templates aren't production level solutions. &lt;/p&gt;

&lt;h2&gt;
  
  
  So what is the solution?
&lt;/h2&gt;

&lt;p&gt;Here is the tech stack that I believe is the most flexible for developers who are looking to build our their ideas and launch something to production in 2023:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Next.js is quickly becoming a Fullstack framework where you can build most of what you need with the API routes.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;a href="https://www.prisma.io/" rel="noopener noreferrer"&gt;Prisma&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;If you need a database for storage, you can use Prisma and pretty much any database provider that you need like PlanetScale or such. &lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;a href="https://www.sanity.io/" rel="noopener noreferrer"&gt;Sanity&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;If you need a CMS, there are many solutions out there. However, with the recent update, Sanity now allows you to host your Sanity CMS backend on a Next.js route. So your hobby/side project will literally have $0 in upstart costs. &lt;/p&gt;

&lt;p&gt;Stay tuned as I will be releasing tutorials and templates for this tech stack to help you quickly go from idea to launch!&lt;/p&gt;

</description>
      <category>announcement</category>
      <category>devto</category>
      <category>webmonetization</category>
      <category>crypto</category>
    </item>
    <item>
      <title>2023: Next.js &amp; Remix &amp; Qwik for Headless</title>
      <dc:creator>iskurbanov</dc:creator>
      <pubDate>Wed, 04 Jan 2023 02:31:37 +0000</pubDate>
      <link>https://dev.to/iskurbanov/the-state-of-headless-commerce-in-2023-1jan</link>
      <guid>https://dev.to/iskurbanov/the-state-of-headless-commerce-in-2023-1jan</guid>
      <description>&lt;p&gt;&lt;em&gt;Article brought to you by &lt;a href="https://www.buildnextshop.com" rel="noopener noreferrer"&gt;buildnextshop.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What Happened?
&lt;/h3&gt;

&lt;p&gt;The last few years changed everything for eCommerce worldwide. For many companies, having an online presence went from an afterthought to a necessity. &lt;/p&gt;

&lt;p&gt;Choosing the right technologies in 2020-2022 is not easy, however. Companies are faced with a lot of difficult decisions regarding their tech stack and the direction they wish to invest in. &lt;/p&gt;

&lt;h3&gt;
  
  
  Who cares?
&lt;/h3&gt;

&lt;p&gt;While out of the box solutions like Shopify themes, Wordpress and WooCommerce seem like a quick way to get up and running, many companies are running into issues with scalability and performance. &lt;/p&gt;

&lt;p&gt;This is where Headless comes into play. &lt;/p&gt;

&lt;p&gt;Headless Architecture allows for teams to quickly get up and running and not be locked into a rigid solution down the road. &lt;/p&gt;

&lt;h3&gt;
  
  
  Here are the top solutions for building Headless eCommerce stores in 2023.
&lt;/h3&gt;

&lt;h2&gt;
  
  
  1) Next.js
&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%2Ftqtn84i54mh8p6kr9axt.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%2Ftqtn84i54mh8p6kr9axt.png" alt="Next.js Homepage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next.js is definitely leading the 'all-things-frontend' movement right now. And next.js GitHub repo has just overtaken create-react-app in stars! &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%2F05w76iy69pe716nnbzf7.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%2F05w76iy69pe716nnbzf7.png" alt="Twitter post of Next.js and Github"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have been really enjoying developing with Next.js and the team is continuously pumping out one great release after another. &lt;/p&gt;

&lt;p&gt;It has gotten to a point where Next.js is becoming a complete full-stack solution replacing a backend in most use-cases. &lt;/p&gt;

&lt;h2&gt;
  
  
  2) Remix
&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%2Fdvi7vnvltyq9l6ok85hh.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%2Fdvi7vnvltyq9l6ok85hh.png" alt="Remix Homepage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A close runner-up to Next.js is quickly becoming Remix. From the copy on their website "While you were waiting for your static site to build, distributed web infra­structure got really good." &lt;/p&gt;

&lt;p&gt;It is another full-stack framework that is based on React (with a bit of a learning curve). They have also recently joined the Shopify team to continue building out the product. The Shopify team is rebuilding a lot of the Hydrogen framework to incorporate Remix.&lt;/p&gt;

&lt;p&gt;Potentially Remix will be to Shopify like React is to Facebook. Have no idea what that means but sounds exciting. &lt;/p&gt;

&lt;p&gt;It's good to note that Next.js has also been expanding their rendering stack to complement Static Site Generation (SSG) with more reliance on Server Side Rendering (SSR) and Server Components. &lt;/p&gt;

&lt;h2&gt;
  
  
  3) Qwik by Builder.io
&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%2Fhrckx96k6skk98txylxd.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%2Fhrckx96k6skk98txylxd.png" alt="Qwik by Builder.io framework Homepage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Builder.io has been quickly growing into a very important player in the CMS field and recently launched their own framework. I have personally not had to the time to create anything with it but from the feedback on twitter, it seems to be a great HTML first alternative to the other 2 frameworks. It promises features such as zero loading, lazy loading, reduced rendering, scalability, and reducing the reliability on heavy JavaScript packages. &lt;/p&gt;

&lt;p&gt;While also based on React, there is a bit of a learning curve when compared to Next.js. &lt;/p&gt;

&lt;p&gt;If you want to learn how to build a Headless eCommerce store I have recently released a public Github with a Next.js + Shopify + Tailwind CSS Starter and a Course to accompany it (for those who want guidance on how to quickly add these technologies to your arsenal).&lt;/p&gt;

&lt;p&gt;Check it out here!&lt;br&gt;
&lt;a href="https://github.com/iskurbanov/shopify-next.js-tailwind" rel="noopener noreferrer"&gt;https://github.com/iskurbanov/shopify-next.js-tailwind&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Landing page for the course (Made with Next.js and Tailwind CSS): &lt;a href="//www.buildnextshop.com"&gt;BuildNextShop.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>shopify</category>
      <category>nextjs</category>
      <category>remix</category>
    </item>
    <item>
      <title>Next.js Image Component Cheatsheet</title>
      <dc:creator>iskurbanov</dc:creator>
      <pubDate>Sat, 14 May 2022 22:51:51 +0000</pubDate>
      <link>https://dev.to/iskurbanov/nextjs-image-component-cheatsheet-524d</link>
      <guid>https://dev.to/iskurbanov/nextjs-image-component-cheatsheet-524d</guid>
      <description>&lt;p&gt;&lt;em&gt;Cheatsheet for Next.js Image Component with common use cases&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After the introduction of the Image component in Next.js version 10, it is rare to use Next.js with the regular &lt;code&gt;&amp;lt;img /&amp;gt;&lt;/code&gt; component and is now even considered incorrect! This Article is to help you learn and remember the most common uses cases for the Next.js Image component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Cheatsheet:
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;1. with predefined width and height:&lt;/strong&gt;&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Image from 'next/image'
import example from '../asset/myimage.png'

const Example = () =&amp;gt; {
  return (
    &amp;lt;Image
      src={example}
      alt="Alt text for the picture"
      width="350px"
      height="300px"
    /&amp;gt;
)

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

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;&lt;strong&gt;2. with predefined width and height with layout prop:&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;With the layout prop, you get 5 options:&lt;/p&gt;

&lt;p&gt;'fill'&lt;br&gt;
'responsive'&lt;br&gt;
'intrinsic'&lt;br&gt;
'fixed'&lt;br&gt;
and now 'raw'&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Image from 'next/image'
import example from '../asset/myimage.png'

const Example = () =&amp;gt; {
  return (
    &amp;lt;Image
      src={example}
      alt="Alt text for the picture"
      width="350px"
      height="300px"
      layout="responsive" 
  /&amp;gt;
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;&lt;strong&gt;with layout fill (dynamic image size)&lt;/strong&gt;&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Image from 'next/image'
import example from '../asset/myimage.png'

const Example = () =&amp;gt; {
  return (
    &amp;lt;Image
        src={example}
        alt="Alt text for the picture"
        layout="fill"
        objectFit="cover"
        quality={100}
   /&amp;gt;
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;&lt;strong&gt;3. styling using Tailwind CSS&lt;/strong&gt;&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Image from 'next/image'
import example from '../asset/myimage.png'

const Example = () =&amp;gt; {
  return (
    &amp;lt;div className="relative w-24 h-24 border border-gray-200 rounded-md overflow-hidden"&amp;gt;
        &amp;lt;Image
           src={product.image}
           alt={product.title}
           layout="fill"
           objectFit="cover"
       /&amp;gt;
    &amp;lt;/div&amp;gt;
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;&lt;strong&gt;4. Next.js Image as a background image&lt;/strong&gt;&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Image from 'next/image'
import example from '../asset/myimage.png'

const Background = () =&amp;gt; (
  &amp;lt;div&amp;gt;
    &amp;lt;ViewSource pathname="pages/background.js" /&amp;gt;
    &amp;lt;div className="fixed h-screen w-screen overflow-hidden
  -z-10"&amp;gt;
      &amp;lt;Image
        alt="Mountains"
        src="/mountains.jpg"
        layout="fill"
        objectFit="cover"
        quality={100}
      /&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
)

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

&lt;/div&gt;



&lt;p&gt;In the comments below, suggest some of your own favorite/most common use cases!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Learn more about Next.js at &lt;a href="https://www.buildnextshop.com"&gt;BuildNextShop.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>javascript</category>
      <category>ecommerce</category>
    </item>
    <item>
      <title>Get Started with Shopify's New Headless Hydrogen Framework</title>
      <dc:creator>iskurbanov</dc:creator>
      <pubDate>Tue, 15 Mar 2022 19:46:18 +0000</pubDate>
      <link>https://dev.to/iskurbanov/get-started-with-shopifys-new-headless-hydrogen-framework-412l</link>
      <guid>https://dev.to/iskurbanov/get-started-with-shopifys-new-headless-hydrogen-framework-412l</guid>
      <description>&lt;p&gt;Checkout examples of stores build with Hydrogen here: &lt;br&gt;
&lt;em&gt;&lt;a href="https://hydrogentemplates.io/blog/shopify-hydrogen-examples" rel="noopener noreferrer"&gt;hydrogentemplates.io&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Headless Ecommerce is carried out in multiple ways by many types of developers. Shopify has recently launched its own opinionated framework, specifically made for headless custom Shopify storefronts, so let's take a closer look.&lt;/p&gt;

&lt;h1&gt;
  
  
  So what is Shopify Hydrogen?
&lt;/h1&gt;

&lt;p&gt;According to Shopify, Hydrogen is a React based framework from Shopify that allows us to build custom headless Shopify storefronts, giving developers everything needed to build fast, personalized and dynamic E-commerce Shopify experiences.&lt;/p&gt;

&lt;p&gt;If you want to take a deeper dive, here is a great  &lt;a href="https://www.smashingmagazine.com/2021/11/hydrogen-react-framework-dynamic-contextual-personalized-ecommerce/" rel="noopener noreferrer"&gt;article&lt;/a&gt; by Ilya Grigorik, who is a principal engineer at Shopify and an author of a book on high-performance browser networking. &lt;/p&gt;

&lt;p&gt;First thing you will notice is that Hydrogen is an opinionated frameworks and is shipped with Tailwind CSS, which I personally think is great.&lt;/p&gt;

&lt;p&gt;So why should we care about using hydrogen and how is this going to work? Let's take a deeper look, then walk through the getting started portion of the Hydrogen documentation:&lt;/p&gt;

&lt;h1&gt;
  
  
  1. SSR &amp;amp; Server Components
&lt;/h1&gt;

&lt;p&gt;When we look at the architecture, hydrogen is built on top of react 18, so it comes with all the cool react 18 features like &lt;strong&gt;streaming SSR&lt;/strong&gt; (server-side rendering),  &lt;strong&gt;progressive hydration&lt;/strong&gt;, &lt;strong&gt;server components&lt;/strong&gt;, data-fetching on servers and the &lt;strong&gt;suspense component&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4c8b2zpomg3qqptnj4qt.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%2F4c8b2zpomg3qqptnj4qt.png" alt="Vite and Hydrogen"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Before making any customizations, I wanted to briefly look at Streaming server-side rendering (SSR), &lt;a href="https://shopify.dev/custom-storefronts/hydrogen/framework/react-server-components" rel="noopener noreferrer"&gt;Server components&lt;/a&gt;  (link) and the hydrogen file naming convention.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's talk about Streaming SSR.&lt;/strong&gt;&lt;br&gt;
When the client loads a page, you have time to first byte (TTFB), and the first and largest contentful paints (FCP, LCP).&lt;/p&gt;

&lt;p&gt;With client side rendering:&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%2Fpozwdubweymro9tqx9m3.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%2Fpozwdubweymro9tqx9m3.png" alt="Client Side Rendering"&gt;&lt;/a&gt;&lt;br&gt;
As you can see here, the time to first byte is fast, but the largest paint is a little delayed and in server side rendering the time to first byte lands somewhere in the middle, but the largest paint is faster.&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%2F2zamh1stmo38trv1ot8s.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%2F2zamh1stmo38trv1ot8s.png" alt="Streaming Server Side Rendering"&gt;&lt;/a&gt;&lt;br&gt;
However, when you compare Streaming server side rendering, SSR unlocks fast non-blocking first render. So all that means is it will squish the two processes together and run them side by side, which results in a faster TTFB and FCP and LCP, which is obviously better.&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%2Fn8zxph6jnxz25ztop2sn.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%2Fn8zxph6jnxz25ztop2sn.png" alt="TTFB FCP LCP"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And this is all powered by the suspense component.&lt;/p&gt;

&lt;p&gt;There is an &lt;a href="https://codesandbox.io/s/async-wave-mp5wdm?file=/server/delays.js" rel="noopener noreferrer"&gt;SSR Demo here&lt;/a&gt; that has been artificially slowed down so you can adjust the delays and see how it all works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Server Components&lt;/strong&gt;&lt;br&gt;
Now let's look at Server/ Client components and the Hydrogen rules and naming conventions related to them.&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%2F7p7y2kgfann3hnwqkxf3.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%2F7p7y2kgfann3hnwqkxf3.png" alt="React Server Components"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, there's a new naming convention in hydrogen with dot .server and the dot .client. That matters because in 'normal' react (.JS .JSX) files behave like we expect. In Hydrogen the .JS .JSX component behavior we expect are actually .client.JSX components, which can be confusing at first.  &lt;/p&gt;

&lt;h1&gt;
  
  
  2. Creating a Hydrogen App &amp;amp; Shopify Store Connection
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Shopify Partners Account&lt;/strong&gt;&lt;br&gt;
Now that we've covered some basics, we're ready to dive in.&lt;br&gt;
If you already have a Shopify Partners account and development store, you can just skip to the next step.&lt;/p&gt;

&lt;p&gt;If you don't have a Shopify partner account, you can join for &lt;a href="https://www.shopify.com/partners" rel="noopener noreferrer"&gt;free here&lt;/a&gt;. Proceed to log in, click on Stores in the top left, then Add store in the top right.&lt;/p&gt;

&lt;p&gt;Then choose Development store as the store type and fill out the required information and click Save.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shopify Storefront Access Token&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So now the only thing we need to get started with the hydrogen framework is to log into our Shopify partner store and grab a storefront access token.&lt;/p&gt;

&lt;p&gt;Once were in the store admin area we go to the &lt;strong&gt;Apps&lt;/strong&gt; tab and click &lt;strong&gt;Develop apps&lt;/strong&gt; and follow the accept screens:&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%2Fyv9u9v7ezs1kvmr1gfrk.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%2Fyv9u9v7ezs1kvmr1gfrk.png" alt="Shopify Dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select all of the scopes for the Storefront API, hit Save and then Install App. &lt;/p&gt;

&lt;p&gt;Finally, just copy the Storefront API access token to your clipboard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating a Hydrogen App&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;All we need to create a hydrogen app is to head over to the &lt;a href="https://shopify.dev/custom-storefronts/hydrogen/getting-started/create" rel="noopener noreferrer"&gt;hydrogen installation&lt;/a&gt; page and install Hydrogen based on your preferred platform/method.&lt;/p&gt;

&lt;p&gt;Since I'm on Windows with Node, I'll just use &lt;strong&gt;NPX&lt;/strong&gt;:&lt;/p&gt;

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

npx create-hydrogen-app (name your app)

Then run:
cd your-app
npm install --legacy-peer-deps
npm run dev


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

&lt;/div&gt;

&lt;p&gt;And here it's asking us to name the app. I'm just going to name it philips_hydrogen&lt;/p&gt;

&lt;p&gt;We can then CD into philips_hydrogen and run these commands.&lt;/p&gt;

&lt;p&gt;This will install the peer dependencies and then run our app using NPM run dev.&lt;/p&gt;

&lt;p&gt;After running our app, we end up on the Hydrogen demo store home page at localhost:3000&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%2F1oj3hiybl7pyri2jvqgs.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%2F1oj3hiybl7pyri2jvqgs.png" alt="Localhost"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What we want to do first is change the storefront access token and connect our storefront.&lt;/p&gt;

&lt;p&gt;Open up the folder structure, and go in to &lt;code&gt;shopify.config.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm10yote05rnw2he3q89k.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%2Fm10yote05rnw2he3q89k.png" alt="Shopify config"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Paste in the access code in the 'storefrontToken' field, and then you're going to need to paste in your domain name as shown above.&lt;/p&gt;

&lt;p&gt;Save this and you should see your connected store information on the home index page of the Hydrogen demo store.&lt;/p&gt;

&lt;h1&gt;
  
  
  3. Basic Customization
&lt;/h1&gt;

&lt;p&gt;Now that we have our storefront access token connected, we can jump over to VS code to make our first basic edits. The first change will be to update the existing h2 title from hello, snowboards to hello, Hydrogen. We just need to go to the &lt;code&gt;welcome.server.jsx&lt;/code&gt; file, which is located in the &lt;code&gt;src/components&lt;/code&gt; folder.&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%2F1x95iksmfnlezi40ncbe.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%2F1x95iksmfnlezi40ncbe.png" alt="folder structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we can see, the h2 title has been updated.&lt;/p&gt;

&lt;p&gt;Next, in the same file we will use Tailwind CSS to change the background to red-500:&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%2Frer2krmiw0zdttsps363.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%2Frer2krmiw0zdttsps363.png" alt="Tailwind"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And we see the background has updated color.&lt;/p&gt;

&lt;p&gt;Now we're going to do a bit of data fetching from the server component. There are two custom hooks that Shopify adds to hydrogen, &lt;strong&gt;useShopQuery&lt;/strong&gt; &amp;amp; &lt;strong&gt;useQuery&lt;/strong&gt;. useQuery is for all 3rd party APIs, similar to fetch and Axios, except done in a way that supports the suspense component.&lt;/p&gt;

&lt;p&gt;useShopQuery is used to fetch data from your Shopify store front, using the storefront access token.&lt;/p&gt;

&lt;p&gt;All we need to do is pass a query 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%2Fv91ng1wgcvj1pvrnhea7.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%2Fv91ng1wgcvj1pvrnhea7.png" alt="Query"&gt;&lt;/a&gt;&lt;br&gt;
Lets get started on that query by using GraphQL.&lt;br&gt;
I want to quickly point out, the demo store comes with the GraphiQL Explorer.&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%2Fzr6yuxvs25uou3455ad8.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%2Fzr6yuxvs25uou3455ad8.png" alt="GraphiQL Explorer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will have it here as an extension off of our localhost:3000/graphql&lt;/p&gt;

&lt;p&gt;If you look at the query:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftb4dzgacifb0suraiaq7.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%2Ftb4dzgacifb0suraiaq7.png" alt="Complete query"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We're going to add the shop name here:&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%2Fheo0h6f6hndq0o4sch3t.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%2Fheo0h6f6hndq0o4sch3t.png" alt="Add Shop Name"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because we're in a server component, we can console log the data, (shop name)&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%2Fkw40qs4m7ctjn3bnqqj6.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%2Fkw40qs4m7ctjn3bnqqj6.png" alt="Shop name query"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and this will display inside of our VSCode terminal.&lt;/p&gt;

&lt;p&gt;As we see, the shop name is showing:&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%2Fll3qlvctciwdr1qt5bwy.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%2Fll3qlvctciwdr1qt5bwy.png" alt="Display from query"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  4. Product Page Edits
&lt;/h1&gt;

&lt;p&gt;So now we're going to go do a few customizations of the product page. We're going to start by editing the layout in &lt;code&gt;Layout.server.jsx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And we will replace it with this code.&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%2Fz9a348pz97xaoxuo88xd.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%2Fz9a348pz97xaoxuo88xd.png" alt="Replacing code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we see right here, we have some localization information. We have the shop name, a homepage link and the cart, which has functionality. We also have the footer below.&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%2Fwsb94hqtf97r723164tb.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%2Fwsb94hqtf97r723164tb.png" alt="Changed Header"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And so when we replace this code with the more basic code above, that is just querying the shop name and returning no components:&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%2F65wngznfqqioy1r45vc2.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%2F65wngznfqqioy1r45vc2.png" alt="Full page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can see that we lose the header, there's no localization, the shop name has changed font size and there is no cart.&lt;br&gt;
We've also lost the gradient background and the footer below.&lt;/p&gt;

&lt;p&gt;Moving on, we're going to create a product list using our product cards.&lt;br&gt;&lt;br&gt;
The product list is a list of product cards that are usually mapped in from the connected store.&lt;br&gt;
The product card also comes included with hydrogen as a shared component by default, which is able to be used on both client and server components.&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%2F0mhspoxfqltuhjvth01s.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%2F0mhspoxfqltuhjvth01s.png" alt="Product Card component"&gt;&lt;/a&gt;&lt;br&gt;
As we can see now, there are two white borders on the top and the bottom, and it does a slight zoom in effect when hovering, but when we replace this code:&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%2F67xbr0qaeenwh0uzhu91.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%2F67xbr0qaeenwh0uzhu91.png" alt="Home page products"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The only visual change that we see here is the white borders are gone and there's no more zoom in effect.&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%2F62jplxewrodmhobrta1k.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%2F62jplxewrodmhobrta1k.png" alt="Zoom effect"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we're going to add our product card to the product list.&lt;br&gt;
We will create a new file in src/components, call it productList.jsx .&lt;/p&gt;

&lt;p&gt;And we'll be adding this product list to the index page.&lt;br&gt;
So what we're going to do is replace the current index code with 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%2Fcw9mwyp62p01ll2oiwnz.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%2Fcw9mwyp62p01ll2oiwnz.png" alt="index server component"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we can see, we now have our product list.&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%2Fwejg2u4nm3l11xn1llzn.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%2Fwejg2u4nm3l11xn1llzn.png" alt="Product list"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we can create then add a load more button component, enabling us to show the rest of our product cards.&lt;br&gt;
This will be a client component, so we can create that in the same src/components folder using this code:&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%2Fehpxas32ppti48txq8pz.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%2Fehpxas32ppti48txq8pz.png" alt="Loadmore component"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And then what we're going to then do is import the loadMore Component to our index page&lt;br&gt;
And when we save this time, we can see the load more button.&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%2Fqvh55yv9kwbcyd8ybo6f.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%2Fqvh55yv9kwbcyd8ybo6f.png" alt="Load more button screenshot"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Product Details&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So now we're going to do our last edit, which will be in &lt;code&gt;ProductDetails.client.jsx&lt;/code&gt; So the first thing we'll change is the header style. We're going to look for the H1 in the file, and we're going to change the text color to purple 500.&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%2Ff7awaydq67z9h3v8rf6f.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%2Ff7awaydq67z9h3v8rf6f.png" alt="Product Details page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Moving on, next we're going to update and remove components.&lt;br&gt;
It's basically saying you might want to update, add to bag, to read, add to cart, which is very simple and remove the, buy it now button.&lt;/p&gt;

&lt;p&gt;So we are going to find the following code:&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%2Fghizk7pn26rzp3yk469y.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%2Fghizk7pn26rzp3yk469y.png" alt="Code Snippet for product details"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and we're going to replace this code with this code here.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F73y70o15gfhreknadovm.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%2F73y70o15gfhreknadovm.png" alt="New Code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is removing the buy now button, keeping the add to cart, button and changing the &lt;strong&gt;add to bag&lt;/strong&gt; to read, &lt;strong&gt;add to cart&lt;/strong&gt;:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foe0vp6lpqevw1tfpiitz.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%2Foe0vp6lpqevw1tfpiitz.png" alt="Add to card button"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And as we can see the buy it now button has been removed and add to bag has been changed to add to cart.&lt;/p&gt;

&lt;h1&gt;
  
  
  5. Color Swatches
&lt;/h1&gt;

&lt;p&gt;Okay so we're going to continue editing our product options. We will add some color swatches and this is not in the documentation, but it's a fairly quick and easy, edit for us to do, to make this look better.  &lt;/p&gt;

&lt;p&gt;First we need to open the &lt;code&gt;productOptions.jsx&lt;/code&gt; file. We can see the ternary conditional line here, and we're going to add in a few lines of code:&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%2F7vqzpyr4abihzyd4durx.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%2F7vqzpyr4abihzyd4durx.png" alt="Adding product options"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Right below this div, we can just open up JavaScript notation, and we can then check if name of our option includes the word 'color':&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%2F0jahyci99eaw2ars7tfy.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%2F0jahyci99eaw2ars7tfy.png" alt="Product swatch"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So if the name includes color, then we will put in the extra div and span you see above.&lt;/p&gt;

&lt;p&gt;The values are mapped and each individual color would be one of the values and that will set the background color of each color swatch.&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%2Fbbojt8qhcy7cjjg97h3b.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%2Fbbojt8qhcy7cjjg97h3b.png" alt="Full code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Okay awesome, we now have our color swatches showing. And these colors are actually coming from the back end in the Shopify store and the store admin back-end product page.&lt;/p&gt;

&lt;p&gt;So that's it! I hope you enjoyed our dip into the Shopify Hydrogen framework.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://shopify.dev/custom-storefronts/hydrogen" rel="noopener noreferrer"&gt;Full Docs and Image Source&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Article written by &lt;a href="//www.philipbeauford.com"&gt;Philip Beauford&lt;/a&gt; for &lt;a href="https://www.buildnextshop.com" rel="noopener noreferrer"&gt;buildnextshop.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Checkout the full tutorial at &lt;a href="https://www.buildnextshop.com" rel="noopener noreferrer"&gt;BuildNextShop.com&lt;/a&gt; where we create a fully production ready Shopify Headless store using Next.js and later adapt it to Hydrogen!&lt;/p&gt;

</description>
      <category>vite</category>
      <category>react</category>
      <category>shopify</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Shopify's Hydrogen vs. Next.js - Headless Battle</title>
      <dc:creator>iskurbanov</dc:creator>
      <pubDate>Tue, 08 Mar 2022 19:56:42 +0000</pubDate>
      <link>https://dev.to/iskurbanov/the-headless-battle-shopifys-hydrogen-vs-nextjs-5bh7</link>
      <guid>https://dev.to/iskurbanov/the-headless-battle-shopifys-hydrogen-vs-nextjs-5bh7</guid>
      <description>&lt;p&gt;&lt;em&gt;Article written by &lt;a href="//www.philipbeauford.com"&gt;Philip Beauford&lt;/a&gt; for &lt;a href="https://www.buildnextshop.com" rel="noopener noreferrer"&gt;buildnextshop.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Checkout the current best Hydrogen examples here: &lt;br&gt;
&lt;em&gt;&lt;a href="https://hydrogentemplates.io/blog/shopify-hydrogen-examples" rel="noopener noreferrer"&gt;hydrogentemplates.io&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How the Shopify Hydrogen Framework compares to Next.js for Headless Architecture&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Shopify has recently released its own opinionated React framework, named &lt;em&gt;Hydrogen&lt;/em&gt;. As Shopify states, Hydrogen was built as a solution for developing custom headless Shopify storefronts. The first time I experimented with a Hydrogen demo project, I immediately noticed it felt very similar to &lt;strong&gt;Next.js&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;The architecture and overall implementation is very similar to Next but there are a few key subtle differences in the approach from both. Next even has their own &lt;a href="https://nextjs.org/commerce" rel="noopener noreferrer"&gt;commerce solution&lt;/a&gt; with &lt;a href="https://demo.vercel.store/search/shop-all" rel="noopener noreferrer"&gt;live demo&lt;/a&gt; that already support Shopify out of the box.&lt;/p&gt;

&lt;p&gt;So then why was Next.js not enough? Why did Shopify feel the need to create their own Hydrogen framework?&lt;/p&gt;

&lt;p&gt;Let's take a quick look at both frameworks for a few comparisons:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hydrogen vs Next.js&lt;/strong&gt;&lt;br&gt;
When looking at the architecture, Hydrogen is using &lt;strong&gt;Vite&lt;/strong&gt; which uses &lt;strong&gt;goLang&lt;/strong&gt;, whereas Next uses &lt;a href="https://nextjs.org/docs/advanced-features/compiler" rel="noopener noreferrer"&gt;SWC compiler&lt;/a&gt; which is built with &lt;strong&gt;Rust&lt;/strong&gt;. So it's interesting to see the difference in choice of high performance languages.&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%2Fyb2r5eqw3jhml47oiztp.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%2Fyb2r5eqw3jhml47oiztp.png" alt="Image description" width="555" height="371"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Hydrogen comes with multiple custom Shopify Components, Hooks &amp;amp; Utilities which is obviously better for a more streamlined Shopify development experience. Whereas Next.js currently has no available Shopify Components requiring more custom work to be done.&lt;/p&gt;

&lt;p&gt;Hydrogen also ships out of the box with &lt;strong&gt;Tailwind CSS&lt;/strong&gt; and although Next.js can easily integrate tailwind, it is not included in the starter Next.js project.&lt;/p&gt;

&lt;p&gt;A few similarities are both Hydrogen and Next use a page based routing system out of the pages directory and both &lt;em&gt;Streaming SSR&lt;/em&gt; &amp;amp; &lt;em&gt;React Server Components&lt;/em&gt; are available on each framework. However, Shopify claims to be more committed to Streaming SSR and Server Components overall, with Hydrogen being built around server components from the ground up.&lt;/p&gt;
&lt;h1&gt;
  
  
  Benefits of Hydrogen
&lt;/h1&gt;

&lt;p&gt;In &lt;a href="https://shopify.engineering/high-performance-hydrogen-powered-storefronts" rel="noopener noreferrer"&gt;these&lt;/a&gt; &lt;a href="https://www.smashingmagazine.com/2021/11/hydrogen-react-framework-dynamic-contextual-personalized-ecommerce/" rel="noopener noreferrer"&gt;articles&lt;/a&gt; Shopify Principal Engineer Ilya Grigorik mentions 5 general areas that separate Hydrogen from the rest:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Streaming server-side rendering for fast non-blocking first render powered by Reacts Suspense Components.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;React Server Components for efficient, post-render component-level state updates.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Built-in server and client data fetching primitives with smart cache defaults.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Flexible page and sub-request cache policies to power dynamic and edge delivery.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Oxygen Hosting.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All of these are great but not all are technically 100% exclusive to Shopify. &lt;/p&gt;

&lt;p&gt;Options 3 and 4 are essentially general descriptions of custom solutions to optimize data use over the network with some improvement in user experience. As for Streaming SSR and React Server Components, they rely on React 18 features that have no official release, but are not exclusively provided by Hydrogen. Other frameworks will (and do) have the same or similar features available.&lt;/p&gt;

&lt;p&gt;For example, Next.js, with its large developer base, supports both of these React 18 features, although currently in Alpha.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If all of that is true, why is Hydrogen still a likely better solution for Headless Shopify development?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hydrogen appears to have a slight advantage when it comes to Streaming SSR &amp;amp; React Server Components, as mentioned by Ilya Grigorik:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“One advantage that we have at Shopify, even compared to let’s say Next.js, is that we’re starting anew. We don’t have an existing ecosystem of apps that we need to move over to this new world of React Server Components.” “We’re big fans of what they’re building,” he said regarding Vercel and Next.js, “and in many ways the architecture is similar. But they are approaching it from another direction."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Vercel is about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build it&lt;/li&gt;
&lt;li&gt;Push it to the edge&lt;/li&gt;
&lt;li&gt;Then add layers of dynamic capabilities.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;"We think that given the needs of commerce, we actually need to start with the inverse. Which is, assume everything is dynamic by default, and then expose the right APIs and capabilities to be static.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Grigorik continued,,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This is not a debate about dynamic vs. static. You need both.” “Some, or perhaps even substantial parts of some storefronts” can be “cached and served from the edge” (the traditional &lt;strong&gt;JAMstack&lt;/strong&gt; model).&lt;/p&gt;

&lt;p&gt;But Shopify customers that choose Hydrogen will be building their storefronts fresh, using JavaScript. Shopify was “willing to make some more opinionated and forward-looking bets about technology choices,” said Grigorik. So it chose to build around React Server Components and create a “&lt;em&gt;dynamic by default&lt;/em&gt;” framework.&lt;/p&gt;

&lt;p&gt;“We saw a gap,” Grigorik summarized, “when we surveyed the existing tools, where it’s really hard — not impossible, but really hard — to get server-side rendering and dynamic commerce working well together.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So it seems although both frameworks are perfectly suitable for ECommerce, Hydrogen is definitely the most aligned with the Shopify ecosystem, as I would expect, but also most aligned with any merchant looking for a &lt;em&gt;Dynamic first&lt;/em&gt; approach.&lt;/p&gt;

&lt;p&gt;The real key to the Shopify edge in all of this will be Oxygen, Shopify's hosted V8 worker runtime enabling server-side requests to the Storefront API with localhost speed.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5z9ocy8yln3nj7stosbj.jpg" 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%2F5z9ocy8yln3nj7stosbj.jpg" alt="Image description" width="800" height="275"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Integrating Hydrogen into Next.js
&lt;/h2&gt;

&lt;p&gt;For those who ask, why can't I just use both? There is a hybrid &lt;a href="https://shopify.dev/custom-storefronts/hydrogen/integrate-react-frameworks" rel="noopener noreferrer"&gt;approach&lt;/a&gt; being discussed, which utilizes both by integrating custom Hydrogen components into a Next.js project.&lt;/p&gt;

&lt;p&gt;To integrate Hydrogen components in your Next.js project, first we need to install some packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @shopify/hydrogen next-transpile-modules --legacy-peer-deps --save
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we need to instruct Next.js to compile &lt;code&gt;@shopify/hydrogen&lt;/code&gt; from ESM (ES Modules) to CJS (CommonJS) by editing &lt;code&gt;next.config.js&lt;/code&gt; with this block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const withTM = require("next-transpile-modules")(["@shopify/hydrogen"]);
module.exports = withTM({
  reactStrictMode: true,
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Shopify will be supporting multiple export types in a future version of Hydrogen so this is a temporary step for now.&lt;/p&gt;

&lt;p&gt;To fetch Shopify storefront data in your Next.js project, Shopify recommends calling the Storefront API on the server similar to this code (example only):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// pages/products/[handle].jsimport {Product} from '@shopify/hydrogen';


export async function getStaticProps({params}) {
  const {data} = getShopifyData({query: QUERY, variables: {handle: params.handle}});

  return {
    props: data,
    revalidate: 5,
  };}


export function Product({data}) {
  return (
    &amp;lt;Product product={data.product}&amp;gt;
      {/** ... */}
    &amp;lt;/Product&amp;gt;
  );}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are a few current limitations when using Hydrogen inside of Next.js. You are not able to use the &lt;strong&gt;useShopQuery&lt;/strong&gt; custom hook as it is meant to be run in Hydrogens Server Components. &lt;/p&gt;

&lt;p&gt;Josh Larson of Shopify recommends writing a utility file like &lt;code&gt;getShopifyData({ query, variables })&lt;/code&gt;, which takes your storefront API credentials and makes a GraphQL query that you can then use in Next.js functions. &lt;/p&gt;

&lt;p&gt;Here is just one example of a potential &lt;code&gt;getShopifyData&lt;/code&gt;utility:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const storeDomain = "hydrogen-preview.myshopify.com"
const storefrontToken = "3b580e70970c4528da70c98e097c2fa0"


export async function getShopifyData(query, variables) {
  return await fetch(`https://${storeDomain}/api/2021-10/graphql.json`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Accept: "application/json",
      "X-Shopify-Storefront-Access-Token": storefrontToken
    },
    body: JSON.stringify({
      query,
      variables
    })
  }).then((response) =&amp;gt; {
    return response.json()
  })
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will be interesting to see how Oxygen impacts the growth of Shopify's new Hydrogen framework. Although if Hydrogen does prove to be the best 'dynamic first' React framework for Ecommerce, some good early growth could be expected.&lt;/p&gt;

&lt;p&gt;For an example of how to use Shopify with Next.js and Tailwind CSS check out this sample starter project: &lt;a href="https://github.com/iskurbanov/shopify-next.js-tailwind" rel="noopener noreferrer"&gt;https://github.com/iskurbanov/shopify-next.js-tailwind&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Checkout the example website and full tutorial at &lt;a href="https://www.buildnextshop.com" rel="noopener noreferrer"&gt;BuildNextShop.com&lt;/a&gt; where we create a fully production ready Shopify Headless store using Next.js!&lt;/p&gt;

</description>
      <category>headless</category>
      <category>nextjs</category>
      <category>react</category>
      <category>shopify</category>
    </item>
    <item>
      <title>How to Dynamically updated Next.js Static Pages with SWR</title>
      <dc:creator>iskurbanov</dc:creator>
      <pubDate>Fri, 18 Feb 2022 01:21:51 +0000</pubDate>
      <link>https://dev.to/iskurbanov/how-to-dynamically-updated-nextjs-static-pages-with-swr-23k8</link>
      <guid>https://dev.to/iskurbanov/how-to-dynamically-updated-nextjs-static-pages-with-swr-23k8</guid>
      <description>&lt;p&gt;&lt;em&gt;Article brought to you by &lt;a href="https://www.buildnextshop.com"&gt;buildnextshop.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is a continuation to the &lt;a href="https://dev.to/iskurbanov/shopify-next-js-tailwind-css-modern-ecommerce-4475"&gt;Shopify + Next.js + Tailwind CSS&lt;/a&gt; article that I wrote in September 2021. It already has over 7000 views!&lt;/p&gt;

&lt;p&gt;If you have been using React, you probably already know that Next.js is a pretty sweet framework that provides a bunch of features on top of React. Some of the popular ones include: SSR (Server-side Rendering), SSG (Static-site Generation), simplified dynamic routing, easy deployment with Vercel, and much more. &lt;/p&gt;

&lt;p&gt;In this article I would like to introduce you to &lt;a href="https://swr.vercel.app/"&gt;SWR (stale-while-revalidate)&lt;/a&gt; package that is also created by the Vercel team. &lt;/p&gt;

&lt;p&gt;SWR allows us to add CSR (Client-side rendering) to our static pages generated by Next.js.&lt;/p&gt;

&lt;p&gt;So why would we want to add SWR? Well, SSG pages give us a great speed advantage, which is super important in e-commerce. But it also has a disadvantage that we need to rebuild and redeploy any changes that happen to the static pages. This becomes a problem when we want to update small components of our app. &lt;/p&gt;

&lt;p&gt;I think this example will give you a good understanding of the power of SWR so let's dive right in!&lt;/p&gt;

&lt;p&gt;To follow along with this example, you will need to: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;set up a Shopify private app (you can refer to this &lt;a href="https://youtu.be/RgGItagzlGo"&gt;youtube tutorial on our channel&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;clone this &lt;a href="https://github.com/iskurbanov/shopify-next.js-tailwind"&gt;Github repository&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  1. Setting up our Next.js /api/available.js file
&lt;/h3&gt;

&lt;p&gt;The /api folder in Next.js is a bit like magic. It allows us to build an API endpoint right in our frontend application. They are server-side only bundles and won't increase your client-side bundle size.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;build-next-shop
 ┣ lib
 ┣ node_modules
 ┣ pages
 ┃ ┗ api 
 ┃   ┗ hello.js *
 ┣ public
 ┣ .env.local
 ┗ package.json
....

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

&lt;/div&gt;



&lt;p&gt;Let's remove everything in the &lt;code&gt;hello.js&lt;/code&gt; file, rename it to &lt;code&gt;available.js&lt;/code&gt; and paste in this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default async function available(req, res) {
  const { query: { id } } = req

  const domain = process.env.SHOPIFY_STORE_DOMAIN
  const storefrontAccessToken = process.env.SHOPIFY_STOREFRONT_ACCESSTOKEN

  async function ShopifyData(query) {
    const URL = `https://${domain}/api/2021-07/graphql.json`

    const options = {
      endpoint: URL,
      method: "POST",
      headers: {
        "X-Shopify-Storefront-Access-Token": storefrontAccessToken,
        "Accept": "application/json",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ query })
    }

    try {
      const data = await fetch(URL, options).then(response =&amp;gt; {
        return response.json()
      })

      return data
    } catch (error) {
      throw new Error("Products not fetched")
    }
  }

  async function getProduct(handle) {
    const query = `
  {
    productByHandle(handle: "${handle}") {
      id
      variants(first: 25) {
        edges {
          node {
            id
            availableForSale
          }
        }
      }
    }
  }`

    const response = await ShopifyData(query)

    const product = response.data.productByHandle ? response.data.productByHandle : []

    return product
  }

  const products = await getProduct(id)

  res.status(200)
  res.json(products)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So what is happening in this code?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;We are creating and exporting and async function &lt;code&gt;available&lt;/code&gt; with two parameters: request and response. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We are deconstructing the &lt;code&gt;req.query.id&lt;/code&gt; variable to get the &lt;code&gt;id&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Grabbing our secret values from our .env file and assigning them to domain and storefrontAccessToken variables.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Setting an options variable that contains our Shopify Graphql URL, method of request, headers, and our query body. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We created a &lt;code&gt;getProduct&lt;/code&gt; function that receives a handle (which we called id in our case). &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We save the results of our getProduct function into a &lt;code&gt;products&lt;/code&gt; variable. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We return the products variable in json format to our Next.js component that calls the API. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  2. Updating our ProductForm.js component
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;build-next-shop
 ┣ .next
 ┣ components
 ...
 ┃ ┗ ProductForm.js 
 ┣ context
 ┣ lib
 ┣ node_modules
 ┗ pages
....

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

&lt;/div&gt;



&lt;p&gt;Let's &lt;code&gt;import useSWR from "swr"&lt;/code&gt; and &lt;code&gt;import axios from "axios"&lt;/code&gt; add our custom fetcher function at the top of the component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import useSWR from "swr"
import axios from "axios"

const fetcher = (url, id) =&amp;gt; (
  axios.get(url, {
    params: {
      id: id
    }
  }).then((res) =&amp;gt; res.data)
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function replaces the default swr fetcher function and replaces it with axios (&lt;a href="https://swr.vercel.app/docs/data-fetching"&gt;read more about it here&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Then we will use the useSWR hook inside of our component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
export default function ProductForm({ product }) {

  const { data: productInventory } = useSWR(
    ['/api/available', product.handle],
    (url, id) =&amp;gt; fetcher(url, id),
    { errorRetryCount: 3 }
  )
...
// rest of the component not shown
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can &lt;code&gt;console.log(productInventory)&lt;/code&gt; and grab the data from our API! &lt;/p&gt;

&lt;h3&gt;
  
  
  3. Add a useEffect hook to update our state
&lt;/h3&gt;

&lt;p&gt;Let's add a new state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const [available, setAvailable] = useState(true)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then we can update it with our useEffect hook like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; useEffect(() =&amp;gt; {
    if (productInventory) {
      const checkAvailable = productInventory?.variants.edges.filter(item =&amp;gt; item.node.id === selectedVariant.id)

      if (checkAvailable[0].node.availableForSale) {
        setAvailable(true)
      } else {
        setAvailable(false)
      }
    }
  }, [productInventory, selectedVariant])`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First we are checking if &lt;code&gt;productInventory&lt;/code&gt; was fetched. Then we find the variant that is selected and search for it in our &lt;code&gt;productInventory&lt;/code&gt; variable and update our button state based on the result. &lt;/p&gt;

&lt;h3&gt;
  
  
  4. Update the button UI based on the availability like this:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;return (
    &amp;lt;div className="rounded-2xl p-4 shadow-lg flex flex-col w-full md:w-1/3"&amp;gt;
      &amp;lt;h2 className="text-2xl font-bold"&amp;gt;{product.title}&amp;lt;/h2&amp;gt;
      &amp;lt;span className="pb-3"&amp;gt;{formatter.format(product.variants.edges[0].node.priceV2.amount)}&amp;lt;/span&amp;gt;
      {
        product.options.map(({ name, values }) =&amp;gt; (
          &amp;lt;ProductOptions
            key={`key-${name}`}
            name={name}
            values={values}
            selectedOptions={selectedOptions}
            setOptions={setOptions}
          /&amp;gt;
        ))
      }
      {
        available ?
          &amp;lt;button
            onClick={() =&amp;gt; {
              addToCart(selectedVariant)
            }}
            className="bg-black rounded-lg text-white px-2 py-3 mt-3 hover:bg-gray-800"&amp;gt;
            Add To Card
          &amp;lt;/button&amp;gt;
          :
          &amp;lt;button
            className="rounded-lg text-white px-2 py-3 mt-3 bg-gray-800 cursor-not-allowed"&amp;gt;
            Sold out!
          &amp;lt;/button&amp;gt;
      }
    &amp;lt;/div&amp;gt;
  )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we create a ternary to check our available state and choose which button to display based on the boolean value. &lt;/p&gt;

&lt;p&gt;I hope you enjoyed the tutorial! &lt;/p&gt;

&lt;p&gt;Sample Starter Project: &lt;a href="https://github.com/iskurbanov/shopify-next.js-tailwind"&gt;https://github.com/iskurbanov/shopify-next.js-tailwind&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Checkout the example website and full tutorial at &lt;a href="https://www.buildnextshop.com"&gt;BuildNextShop.com&lt;/a&gt; where we create a fully production ready Shopify Headless store using Next.js!&lt;/p&gt;

</description>
      <category>react</category>
      <category>nextjs</category>
      <category>shopify</category>
      <category>swr</category>
    </item>
  </channel>
</rss>
