<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Jake Prins</title>
    <description>The latest articles on Forem by Jake Prins (@jakeprins).</description>
    <link>https://forem.com/jakeprins</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%2F173305%2F204e4793-6166-4fc8-afba-8132ef92daf4.jpg</url>
      <title>Forem: Jake Prins</title>
      <link>https://forem.com/jakeprins</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jakeprins"/>
    <language>en</language>
    <item>
      <title>How to Convert a Next.js Application to React.js</title>
      <dc:creator>Jake Prins</dc:creator>
      <pubDate>Mon, 30 Sep 2024 14:32:21 +0000</pubDate>
      <link>https://forem.com/jakeprins/how-to-convert-a-nextjs-application-to-reactjs-858</link>
      <guid>https://forem.com/jakeprins/how-to-convert-a-nextjs-application-to-reactjs-858</guid>
      <description>&lt;p&gt;If you've built a web application using Next.js but now need to convert it to a pure React.js application, you're not alone. Whether it's for simplicity, specific project requirements, or a preference for client-side rendering, converting from Next.js to React can be straightforward with the right guidance. In this article, I'll walk you through the steps to &lt;strong&gt;convert a Next.js app to React.js&lt;/strong&gt;, ensuring a smooth transition while maintaining your application's core functionality.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you're looking to convert a React.js application to Next.js instead, check out my &lt;a href="https://www.jakeprins.com/blog/how-to-convert-reactjs-to-nextjs" rel="noopener noreferrer"&gt;other article on how to convert React.js to Next.js&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why Convert Next.js to React.js?
&lt;/h2&gt;

&lt;p&gt;Next.js is a fantastic framework that offers server-side rendering (SSR), static site generation (SSG), and a host of other features out of the box. However, these features might be overkill for smaller projects or unnecessary if you prefer client-side rendering (CSR) with React.js. Converting to React.js can simplify your build process, reduce server dependencies, and give you more control over your application's architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the Differences
&lt;/h2&gt;

&lt;p&gt;Before diving into the conversion process, it's essential to understand the key differences between Next.js and React.js:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Server-Side Rendering vs. Client-Side Rendering:&lt;/strong&gt; Next.js supports SSR and SSG, whereas React.js is primarily for CSR.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Routing:&lt;/strong&gt; Next.js has a built-in file-based routing system. In React.js, you'll need to use a library like React Router.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Routes:&lt;/strong&gt; Next.js allows you to create API routes within the same project. In React.js, you'd typically separate the frontend and backend.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Steps to Convert Next.js to React.js
&lt;/h2&gt;

&lt;p&gt;Let's get started with the step-by-step guide on how to convert a Next.js application to React.js.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Set Up a New React.js Application
&lt;/h3&gt;

&lt;p&gt;First, create a new React.js project using a tool like Create React App (CRA) or Vite.&lt;/p&gt;

&lt;p&gt;Using Create React App:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-react-app my-react-app
&lt;span class="nb"&gt;cd &lt;/span&gt;my-react-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using Vite:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init vite@latest my-react-app &lt;span class="nt"&gt;--template&lt;/span&gt; react
&lt;span class="nb"&gt;cd &lt;/span&gt;my-react-app
npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Transfer Dependencies
&lt;/h3&gt;

&lt;p&gt;Copy the dependencies and devDependencies from your Next.js project's package.json to the new React.js project's package.json. Run &lt;code&gt;npm install&lt;/code&gt; or &lt;code&gt;yarn install&lt;/code&gt; to install them.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Migrate Components and Pages
&lt;/h3&gt;

&lt;p&gt;Copy the contents of your Next.js components and pages directories into your React.js project's src directory. Since Next.js uses a pages directory for routing, you'll need to adjust this structure.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Implement Routing with React Router
&lt;/h3&gt;

&lt;p&gt;Next.js handles routing automatically based on the pages directory. In React.js, you'll need to set up routing manually.&lt;/p&gt;

&lt;p&gt;Install React Router:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;react-router-dom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set Up Routes in src/App.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BrowserRouter&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-router-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Home&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;./Home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;About&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;./About&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="c1"&gt;// Import other components as needed&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Routes&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt; &lt;span class="na"&gt;element&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Home&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/about"&lt;/span&gt; &lt;span class="na"&gt;element&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;About&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Add other routes */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Routes&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Adjust Data Fetching Methods
&lt;/h3&gt;

&lt;p&gt;In Next.js, data fetching is done using getServerSideProps, getStaticProps, or getInitialProps. In React.js, you'll need to handle data fetching within your components, typically using useEffect and useState.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&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;setData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&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="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Update the API endpoint as needed&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&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="nf"&gt;setData&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;span class="p"&gt;[])&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Render your data */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. Handle API Routes
&lt;/h3&gt;

&lt;p&gt;If your Next.js app uses API routes within the pages/api directory, you'll need to migrate these to a separate backend service or adjust your frontend to fetch from external APIs.&lt;/p&gt;

&lt;p&gt;Options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a Separate Backend: Use Node.js, Express, or any backend framework to set up API endpoints.&lt;/li&gt;
&lt;li&gt;Use External APIs: If possible, adjust your frontend to consume external APIs directly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  7. Update Environment Variables
&lt;/h3&gt;

&lt;p&gt;Next.js uses environment variables prefixed with &lt;code&gt;NEXT_PUBLIC_&lt;/code&gt; for client-side variables. In React.js, create a .env file at the root of your project and prefix variables with &lt;code&gt;REACT_APP_&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;REACT_APP_API_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://api.example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Access them in your code using &lt;code&gt;process.env.REACT_APP_API_URL&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Remove Next.js Specific Configurations
&lt;/h3&gt;

&lt;p&gt;Delete any Next.js specific configurations like next.config.js. Also, remove any Next.js-specific imports or packages that are no longer needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Test Your Application
&lt;/h3&gt;

&lt;p&gt;Run your React.js application to ensure everything works as expected.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go through each route and functionality to verify that the conversion was successful.&lt;/p&gt;

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

&lt;p&gt;Converting a Next.js application to React.js involves setting up a new React project and migrating your components, adjusting routing, and handling data fetching differently. While Next.js offers many powerful features, a pure React.js application provides simplicity and flexibility, especially for projects that don't require server-side rendering.&lt;/p&gt;

&lt;p&gt;By following this guide on how to convert Next.js to React.js, you should have a seamless transition.&lt;/p&gt;

&lt;p&gt;Thanks for reading! If you're interested in going the other way around, check out my article on &lt;a href="https://www.jakeprins.com/blog/how-to-convert-reactjs-to-nextjs" rel="noopener noreferrer"&gt;how to convert a React.js application to Next.js&lt;/a&gt;. For more updates on new projects or articles, follow me on Twitter: &lt;a href="https://twitter.com/jake_prins" rel="noopener noreferrer"&gt;@jake_prins&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>tutorial</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to create a ChatGPT application using Next.js and the OpenAI API.</title>
      <dc:creator>Jake Prins</dc:creator>
      <pubDate>Thu, 06 Apr 2023 07:06:02 +0000</pubDate>
      <link>https://forem.com/jakeprins/how-to-create-a-chatgpt-application-using-nextjs-and-the-openai-api-30mk</link>
      <guid>https://forem.com/jakeprins/how-to-create-a-chatgpt-application-using-nextjs-and-the-openai-api-30mk</guid>
      <description>&lt;h2&gt;
  
  
  Build a ChatGPT application with Next.js, TypeScript, and TailwindCSS.
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Node.js and npm installed on your machine&lt;/li&gt;
&lt;li&gt;A basic understanding of React and TypeScript&lt;/li&gt;
&lt;li&gt;An OpenAI API key — you can sign up for an account and generate an API key from the &lt;a href="https://platform.openai.com/account/api-keys"&gt;OpenAI website&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What we will build
&lt;/h3&gt;

&lt;p&gt;Following this tutorial, we will use the OpenAI API to create a simple chat application like ChatGPT.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cptSXk9L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/v2/resize:fit:4800/format:webp/1%2A1ALWm32Mtdble4nh4TDfFA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cptSXk9L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/v2/resize:fit:4800/format:webp/1%2A1ALWm32Mtdble4nh4TDfFA.jpeg" alt="ChatGPT Tutorial Application" width="880" height="603"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Setting up the project
&lt;/h2&gt;

&lt;p&gt;We will use the &lt;a href="https://github.com/apideck-io/next-starter-kit"&gt;Next.js Starter Kit&lt;/a&gt; from &lt;a href="https://apideck.com/"&gt;Apideck&lt;/a&gt; to set up our project. It comes with TypeScript, TailwindCSS, and the &lt;a href="https://developers.apideck.com/components"&gt;Apideck Components&lt;/a&gt; library pre-installed.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Create a new project using the command line:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn create-next-app --example https://github.com/apideck-io/next-starter-kit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Choose your project name and navigate to your new folder. Inside, create a &lt;code&gt;.env.local&lt;/code&gt; file at the root of your project and add the following line (replacing &lt;code&gt;YOUR_OPENAI_API_KEY&lt;/code&gt; with your actual key):
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;YOUR_OPENAI_API_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Writing the API client
&lt;/h2&gt;

&lt;p&gt;To not expose your OpenAI API key, we will create an API endpoint instead of making requests to the API directly from our browser. Follow these steps to set up your endpoint using a &lt;a href="https://nextjs.org/docs/api-routes/introduction"&gt;Next.js API route&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Locate the pages folder of your project and create a new subfolder named &lt;code&gt;api&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; Inside the &lt;code&gt;api&lt;/code&gt;folder, create a new TypeScript file named &lt;code&gt;createMessage.ts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt; In the &lt;code&gt;createMessage.ts&lt;/code&gt; file, we can either use the OpenAI SDK or issue an HTTP request to the OpenAI API to generate a new message for our “conversation” with the AI. We will use the direct API call in this tutorial.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is the code for our API route.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextApiRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NextApiResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;createMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextApiRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextApiResponse&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OPENAI_API_KEY&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.openai.com/v1/chat/completions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;body&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="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;messages&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;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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;fetch&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;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&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;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;apiKey&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="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="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="k"&gt;await&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;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;data&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&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;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&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="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this example, we’re utilizing the &lt;code&gt;gpt-3.5-turbo&lt;/code&gt; model, as it’s currently available at the time of writing. If you possess access to GPT-4, you can alter the value as necessary.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;messages&lt;/code&gt; value is an array that stores messages from our chat-based conversation with the AI. Each message contains both a &lt;code&gt;role&lt;/code&gt; and &lt;code&gt;content&lt;/code&gt;. The &lt;code&gt;role&lt;/code&gt; can be either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;system&lt;/em&gt;&lt;/strong&gt;
This is the initial prompt sent to the AI, which gives it instructions on how to behave. For example, you may use “You are ChatGPT, a language model trained by OpenAI.” or “You are a software engineer who develops software programs, web applications, and mobile applications using various programming languages and development tools.” Experimenting with different initial system messages can help you fine-tune the AI’s behavior.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;user&lt;/em&gt;&lt;/strong&gt;
This represents the user’s input. For example, the user could ask, “Can you provide a JavaScript function fetching the current weather?”&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;assistant&lt;/em&gt;&lt;/strong&gt;
This is the AI’s response, which the API endpoint will return.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 3: Creating the messaging functions
&lt;/h2&gt;

&lt;p&gt;Now that the endpoint is ready to interface with the AI, we can begin designing our user interface to facilitate interaction. To start, we’ll create the &lt;code&gt;sendMessage&lt;/code&gt; function. Here’s how:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Create a new file named &lt;code&gt;sendMessage.ts&lt;/code&gt; in the &lt;code&gt;utils&lt;/code&gt; folder.&lt;/li&gt;
&lt;li&gt; Add the following code to &lt;code&gt;sendMessage.ts&lt;/code&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ChatCompletionRequestMessage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;openai&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sendMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChatCompletionRequestMessage&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;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;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/createMessage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&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;application/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="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;messages&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="k"&gt;await&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;json&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="nx"&gt;log&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this function in place, you can establish communication between the user interface and the AI via the API endpoint.&lt;/p&gt;

&lt;p&gt;Now let’s setup the logic to create new messages inside a &lt;code&gt;useMessages&lt;/code&gt; hook. Inside the &lt;code&gt;utils&lt;/code&gt; folder, create a file named &lt;code&gt;useMessages.ts&lt;/code&gt; and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useToast&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@apideck/components&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ChatCompletionRequestMessage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;openai&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ReactNode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;sendMessage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./sendMessage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ContextProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChatCompletionRequestMessage&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="nx"&gt;addMessage&lt;/span&gt;&lt;span class="p"&gt;:&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="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;isLoadingAnswer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&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;ChatsContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ContextProps&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({})&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;MessagesProvider&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ReactNode&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;addToast&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useToast&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;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setMessages&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ChatCompletionRequestMessage&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isLoadingAnswer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsLoadingAnswer&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initializeChat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;systemMessage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChatCompletionRequestMessage&lt;/span&gt; &lt;span class="o"&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;system&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;You are ChatGPT, a large language model trained by OpenAI.&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="na"&gt;welcomeMessage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChatCompletionRequestMessage&lt;/span&gt; &lt;span class="o"&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;assistant&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hi, How can I help you today?&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;setMessages&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;systemMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;welcomeMessage&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// When no messages are present, we initialize the chat the system message and the welcome message&lt;/span&gt;
    &lt;span class="c1"&gt;// We hide the system message from the user in the UI&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;messages&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;initializeChat&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="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setMessages&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;addMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;setIsLoadingAnswer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="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="na"&gt;newMessage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChatCompletionRequestMessage&lt;/span&gt; &lt;span class="o"&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="nx"&gt;content&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;newMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newMessage&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

      &lt;span class="c1"&gt;// Add the user message to the state so we can see it immediately&lt;/span&gt;
      &lt;span class="nx"&gt;setMessages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newMessages&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;data&lt;/span&gt; &lt;span class="p"&gt;}&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;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newMessages&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;reply&lt;/span&gt; &lt;span class="o"&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="c1"&gt;// Add the assistant message to the state&lt;/span&gt;
      &lt;span class="nx"&gt;setMessages&lt;/span&gt;&lt;span class="p"&gt;([...&lt;/span&gt;&lt;span class="nx"&gt;newMessages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reply&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="c1"&gt;// Show error when something goes wrong&lt;/span&gt;
      &lt;span class="nx"&gt;addToast&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;An error occurred&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;type&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&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;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;setIsLoadingAnswer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ChatsContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;addMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isLoadingAnswer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ChatsContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ChatsContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ContextProps&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Implement the message UI components
&lt;/h2&gt;

&lt;p&gt;Having set up our functions, we can now design UI components that will use these functions to create an interactive chat interface. Follow the steps below:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Create a new file called &lt;code&gt;MessageForm.tsx&lt;/code&gt; in the &lt;code&gt;components&lt;/code&gt; folder of your project and add the following code:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TextArea&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@apideck/components&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useMessages&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utils/useMessages&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MessageForm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setContent&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&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;addMessage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useMessages&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;handleSubmit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;addMessage&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="nx"&gt;setContent&lt;/span&gt;&lt;span class="p"&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="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;
      &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"relative mx-auto max-w-3xl rounded-t-xl"&lt;/span&gt;
      &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSubmit&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;" supports-backdrop-blur:bg-white/95 h-[130px] rounded-t-xl border-t border-l border-r border-gray-200 border-gray-500/10 bg-white p-5 backdrop-blur dark:border-gray-50/[0.06]"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt; &lt;span class="na"&gt;htmlFor&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"content"&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"sr-only"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          Your message
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TextArea&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"content"&lt;/span&gt;
          &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Enter your message here..."&lt;/span&gt;
          &lt;span class="na"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;autoFocus&lt;/span&gt;
          &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"border-0 !p-3 text-gray-900 shadow-none ring-1 ring-gray-300/40 backdrop-blur focus:outline-none focus:ring-gray-300/80 dark:bg-gray-800/80 dark:text-white dark:placeholder-gray-400 dark:ring-0"&lt;/span&gt;
          &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"absolute right-8 bottom-10"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex space-x-3"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt; &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"small"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              Send
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;svg&lt;/span&gt;
                &lt;span class="na"&gt;xmlns&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2000/svg"&lt;/span&gt;
                &lt;span class="na"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"none"&lt;/span&gt;
                &lt;span class="na"&gt;viewBox&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"0 0 24 24"&lt;/span&gt;
                &lt;span class="na"&gt;strokeWidth&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="na"&gt;stroke&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"currentColor"&lt;/span&gt;
                &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"ml-1 h-4 w-4"&lt;/span&gt;
              &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;path&lt;/span&gt;
                  &lt;span class="na"&gt;strokeLinecap&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"round"&lt;/span&gt;
                  &lt;span class="na"&gt;strokeLinejoin&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"round"&lt;/span&gt;
                  &lt;span class="na"&gt;d&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"M6 12L3.269 3.126A59.768 59.768 0 0121.485 12 59.77 59.77 0 013.27 20.876L5.999 12zm0 0h7.5"&lt;/span&gt;
                &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;svg&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Now that we have set up the message UI components, we need to create the component to render the list of messages.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new file called &lt;code&gt;MessagesList.tsx&lt;/code&gt; in the &lt;code&gt;components&lt;/code&gt; folder and add the following code:
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MessagesList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isLoadingAnswer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useMessages&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"mx-auto max-w-3xl pt-8"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isUser&lt;/span&gt; &lt;span class="o"&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;role&lt;/span&gt; &lt;span class="o"&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="k"&gt;if&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;role&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;system&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="kc"&gt;null&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
            &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`message-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`fade-up mb-4 flex &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;
              &lt;span class="nx"&gt;isUser&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;justify-end&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;justify-start&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;max-w-md&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="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isUser&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt;
                &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://www.teamsmart.ai/next-assets/team/ai.jpg"&lt;/span&gt;
                &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"h-9 w-9 rounded-full"&lt;/span&gt;
                &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"avatar"&lt;/span&gt;
              &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
              &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;maxWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;calc(100% - 45px)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`group relative rounded-lg px-3 py-2 &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;
                &lt;span class="nx"&gt;isUser&lt;/span&gt;
                  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;from-primary-700 to-primary-600 mr-2 bg-gradient-to-br text-white&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;ml-2 bg-gray-200 text-gray-700 dark:bg-gray-800 dark:text-gray-200&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;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="nx"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isUser&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt;
                &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://www.teamsmart.ai/next-assets/profile-image.png"&lt;/span&gt;
                &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"h-9 w-9 cursor-pointer rounded-full"&lt;/span&gt;
                &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"avatar"&lt;/span&gt;
              &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isLoadingAnswer&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"mb-4 flex justify-start"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt;
            &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://www.teamsmart.ai/next-assets/team/ai.jpg"&lt;/span&gt;
            &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"h-9 w-9 rounded-full"&lt;/span&gt;
            &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"avatar"&lt;/span&gt;
          &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"loader relative ml-2 flex items-center justify-between space-x-1.5 rounded-full bg-gray-200 p-2.5 px-4 dark:bg-gray-800"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"block h-3 w-3 rounded-full"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"block h-3 w-3 rounded-full"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"block h-3 w-3 rounded-full"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;We do not want to show the initial system message, so if the &lt;code&gt;role&lt;/code&gt; is &lt;code&gt;system&lt;/code&gt; we return &lt;code&gt;null&lt;/code&gt;. Next, we adjust the styling of the messages based on if the &lt;code&gt;role&lt;/code&gt; is either &lt;code&gt;assisten&lt;/code&gt; or &lt;code&gt;user&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;While we are waiting for a response, we show a loading element. For this &lt;code&gt;loader&lt;/code&gt; element to animate, we need to add some custom CSS. Inside the styles folder, create a &lt;code&gt;globals.css&lt;/code&gt; file and add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.loader&lt;/span&gt; &lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;animation-name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;bounce&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;animation-duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;animation-iteration-count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;infinite&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;animation-timing-function&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ease-in-out&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.loader&lt;/span&gt; &lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="nd"&gt;:nth-child&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;animation-delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50ms&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.loader&lt;/span&gt; &lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="nd"&gt;:nth-child&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;3&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;animation-delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;150ms&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;Make sure to import the CSS file into your &lt;code&gt;_app.tsx&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;styles/globals.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;styles/tailwind.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ToastProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@apideck/components&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppProps&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pageProps&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;AppProps&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;JSX&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Element&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ToastProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;pageProps&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ToastProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;We can use our message UI components in our application now that we have built them. Locate the &lt;code&gt;pages&lt;/code&gt; directory and open &lt;code&gt;index.tsx&lt;/code&gt;. Remove the boilerplate code in this file.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Layout&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;components/Layout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MessageForm&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;components/MessageForm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MessagesList&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;components/MessageList&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextPage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MessagesProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utils/useMessages&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;IndexPage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MessagesProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MessagesList&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"fixed bottom-0 right-0 left-0"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MessageForm&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;MessagesProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;We have wrapped our components with the &lt;code&gt;MessageProvider&lt;/code&gt; so we can share the state between the components. We also added a container div to the &lt;code&gt;MessageForm&lt;/code&gt; component, so it has a fixed position at the bottom of the page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Running the chat application
&lt;/h2&gt;

&lt;p&gt;Nice job! We now reached the point where we could see our chat application in action. Here’s how you can test your ChatGPT application:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Make sure your development server is running. (&lt;code&gt;yarn dev&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt; Navigate to the root URL of your application in your browser. (&lt;code&gt;localhost:3000&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt; You should see the UI rendered on the screen. Type a message in the text field at the bottom and hit &lt;em&gt;Send&lt;/em&gt;. The AI chatbot will respond to your message.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can now engage in a conversation with your AI chatbot! Feel free to experiment with different types of messages and see how the AI responds.&lt;/p&gt;

&lt;h1&gt;
  
  
  Final words
&lt;/h1&gt;

&lt;p&gt;Thank you for reading! The complete source code can be found &lt;a href="https://github.com/jakeprins/nextjs-chatgpt-tutorial"&gt;here&lt;/a&gt;&lt;a href="https://github.com/jakeprins/nextjs-chatgpt-tutorial."&gt;.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you found this tutorial useful, please connect with me on &lt;a href="https://twitter.com/jake_prins"&gt;Twitter&lt;/a&gt; or visit my personal website at &lt;a href="https://jakeprins.com/"&gt;jakeprins.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In addition, be sure to check out &lt;a href="http://teamsmart.ai/"&gt;TeamSmart AI&lt;/a&gt; for my complete ChatGPT application. It’s a Chrome extension that allows different AI team members to help you with your daily tasks.&lt;/p&gt;

</description>
      <category>chatgpt</category>
      <category>nextjs</category>
      <category>tailwindcss</category>
      <category>ai</category>
    </item>
    <item>
      <title>How to Set Up Tailwind CSS 2 With Next.js 10</title>
      <dc:creator>Jake Prins</dc:creator>
      <pubDate>Fri, 01 Jan 2021 17:54:13 +0000</pubDate>
      <link>https://forem.com/jakeprins/how-to-set-up-tailwind-css-2-with-next-js-10-5376</link>
      <guid>https://forem.com/jakeprins/how-to-set-up-tailwind-css-2-with-next-js-10-5376</guid>
      <description>&lt;p&gt;In the last months of 2020, a couple of great framework updates have been released. First was the release of &lt;a href="https://nextjs.org/blog/next-10"&gt;Next.js 10&lt;/a&gt;, which came with a lot of nice features, like the new image component that automatically optimizes images.&lt;/p&gt;

&lt;p&gt;Secondly, 18 months after the 1.0 release, the Tailwind team released &lt;a href="https://blog.tailwindcss.com/tailwindcss-v2"&gt;v2.0&lt;/a&gt; of their CSS framework. This new update included lots of improvements like a &lt;a href="https://blog.tailwindcss.com/tailwindcss-v2#all-new-color-palette"&gt;new color palette&lt;/a&gt; and &lt;a href="https://blog.tailwindcss.com/tailwindcss-v2#dark-mode"&gt;dark mode support&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Using the latest version of Next.js with Tailwind CSS is a very powerful combination to create and style web applications. Let’s walk through the steps of setting a new project up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Start a New Next.js Project
&lt;/h3&gt;

&lt;p&gt;Assuming you have installed &lt;a href="https://classic.yarnpkg.com/en/docs/install/#mac-stable"&gt;Yarn&lt;/a&gt;, open your terminal and run &lt;code&gt;yarn create next-app&lt;/code&gt; in your projects folder.&lt;/p&gt;

&lt;p&gt;You will get prompted with the following message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What is your project named?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fill in a name, hit enter, and wait until your project is ready. Then, type &lt;code&gt;cd &amp;lt;your-project-name&amp;gt;&lt;/code&gt; to make sure you are inside that directory where you can run &lt;code&gt;yarn dev&lt;/code&gt; to start the development server. You should now have your new Next.js 10 project up and running.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install Tailwind and Its Dependencies
&lt;/h3&gt;

&lt;p&gt;Tailwind CSS is a plugin built on &lt;a href="https://postcss.org/"&gt;PostCSS&lt;/a&gt;, a tool for transforming CSS with JavaScript. The v2.0 has been updated for the latest PostCSS release, which requires installing &lt;code&gt;postcss&lt;/code&gt; and &lt;code&gt;autoprefixer&lt;/code&gt; as peer dependencies alongside Tailwind itself.&lt;/p&gt;

&lt;p&gt;Add Tailwind and install PostCSS as well as autoprefixer using npm or yarn:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add tailwindcss postcss autoprefixer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create Config Files
&lt;/h3&gt;

&lt;p&gt;We need to add a &lt;code&gt;tailwind.config.js&lt;/code&gt; and a &lt;code&gt;postcss.config.js&lt;/code&gt; file to the root of our application. Use the following command to set this up:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This will create a &lt;code&gt;tailwind.config.js&lt;/code&gt; file at the root of your project:&lt;/p&gt;

&lt;p&gt;Learn more about configuring Tailwind in the &lt;a href="https://tailwindcss.com/docs/configuration"&gt;configuration documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It will also create a &lt;code&gt;postcss.config.js&lt;/code&gt; file that includes &lt;code&gt;tailwindcss&lt;/code&gt; and &lt;code&gt;autoprefixer&lt;/code&gt; configured:&lt;/p&gt;

&lt;h3&gt;
  
  
  Import the CSS
&lt;/h3&gt;

&lt;p&gt;Let’s create a &lt;code&gt;styles&lt;/code&gt; folder and import Tailwind CSS from a CSS file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch styles/tailwind.css
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside &lt;code&gt;tailwind.css&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@tailwind base;
@tailwind components;
@tailwind utilities;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To add global CSS to a Next.js app, we need to override the default &lt;code&gt;App&lt;/code&gt; component. With Next.js 10, you should already have &lt;code&gt;_app.js&lt;/code&gt; inside your pages folder. Now import the stylesheet we created:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import '../styles/globals.css'
import '../styles/tailwind.css';export default function MyApp({ Component, pageProps }) {
  return &amp;lt;Component {...pageProps} /&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cool, now we are ready to add some Tailwind CSS magic to our home page. Go to &lt;code&gt;/pages/index.js&lt;/code&gt; (or &lt;code&gt;/pages/index.tsx&lt;/code&gt; if you use TypeScript) and add some elements with Tailwind CSS classes. For example:&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;yarn dev&lt;/code&gt; to see your app on &lt;a href="https://localhost:4202/settings/departments"&gt;http://localhost:3000&lt;/a&gt; in your browser.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure PurgeCSS
&lt;/h3&gt;

&lt;p&gt;One problem with Tailwind CSS is the large file size, but &lt;a href="https://github.com/FullHuman/purgecss"&gt;PurgeCSS&lt;/a&gt; can fix this. PurgeCSS reduces the file size by scanning your HTML and removing any classes that aren’t used. We only want this in production because if we are developing, we want to be able to use any Tailwind CSS class without running the build process.&lt;/p&gt;

&lt;p&gt;Now with Tailwind CSS v2, PurgeCSS is already included. All you have to do is update the &lt;code&gt;tailwind.config.js&lt;/code&gt; file so Tailwind can tree-shake unused styles in production builds. Update your file like this:&lt;/p&gt;

&lt;p&gt;For now, we check all of our code inside &lt;code&gt;.js, .jsx, .ts or .tsx&lt;/code&gt; files that live in either the &lt;code&gt;pages/&lt;/code&gt; or &lt;code&gt;components/&lt;/code&gt; folder. If you plan to add HTML in other folders like &lt;code&gt;containers/&lt;/code&gt; or something, make sure you add that folder to this configuration file.&lt;/p&gt;

&lt;p&gt;You can read the guide from Tailwind on &lt;a href="https://tailwindcss.com/docs/optimizing-for-production"&gt;optimizing for production&lt;/a&gt; to learn more about tree-shaking unused styles for best performance.&lt;/p&gt;

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

&lt;p&gt;Now we are ready to work with the latest versions of Next.js and Tailwind CSS without having to worry about bundle sizes!&lt;/p&gt;

&lt;p&gt;That’s it! Thanks for reading. I hope it was helpful.&lt;/p&gt;




&lt;p&gt;If you’re interested in saving time on your next project and skip implementing authentication, payments, etc. then check out &lt;a href="https://serverless.page"&gt;Serverless SaaS&lt;/a&gt;, the SaaS starter-kit for React developers. You can also follow me on &lt;a href="https://twitter.com/jakeprins_nl"&gt;Twitter&lt;/a&gt;, or at &lt;a href="https://jakeprins.com"&gt;jakeprins.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>tailwindcss</category>
      <category>css</category>
    </item>
    <item>
      <title>NextWind: A free starter-kit for building landing pages + blog</title>
      <dc:creator>Jake Prins</dc:creator>
      <pubDate>Wed, 16 Dec 2020 12:18:06 +0000</pubDate>
      <link>https://forem.com/jakeprins/nextwind-a-free-starter-kit-for-building-landing-pages-blog-3khk</link>
      <guid>https://forem.com/jakeprins/nextwind-a-free-starter-kit-for-building-landing-pages-blog-3khk</guid>
      <description>&lt;p&gt;I made a starter-kit for building a blog or landing pages quickly with Next.js, Tailwind CSS, and Netlify CMS. &lt;/p&gt;

&lt;p&gt;It allows you to switch between different versions of page sections from within the CMS. To do this, simply change for example &lt;code&gt;hero_version&lt;/code&gt; from 1 to 2 or 3. The preview is immediately updated to show you the styling of the selected version. &lt;/p&gt;

&lt;p&gt;The sections are mostly brought to you by &lt;a href="https://mertjf.github.io/tailblocks/"&gt;Tailblocks&lt;/a&gt;, some ready-to-use sections built with Tailwind CSS. &lt;/p&gt;

&lt;p&gt;You can find the repository here: &lt;a href="https://github.com/jakeprins/nextwind"&gt;https://github.com/jakeprins/nextwind&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>typescript</category>
      <category>netlify</category>
      <category>tooling</category>
    </item>
    <item>
      <title>How to Use ESLint and Prettier in Your Next.js </title>
      <dc:creator>Jake Prins</dc:creator>
      <pubDate>Sun, 13 Dec 2020 18:06:12 +0000</pubDate>
      <link>https://forem.com/jakeprins/how-to-use-eslint-and-prettier-in-your-next-js-2ech</link>
      <guid>https://forem.com/jakeprins/how-to-use-eslint-and-prettier-in-your-next-js-2ech</guid>
      <description>&lt;p&gt;Automated lint tools can help developers save time and keep everybody on the same page. When everybody on your team follows the same rules, you don’t have to waste time discussing code style issues. These tools can catch a lot of syntax and type errors.&lt;/p&gt;

&lt;p&gt;Combining &lt;a href="https://eslint.org/"&gt;ESLint&lt;/a&gt; with &lt;a href="https://prettier.io/"&gt;Prettier&lt;/a&gt; is a nice way to perform both automated syntax scans on your code and reformatting. This will ensure that consistent rules are being followed for indentation, spacing, semicolons, etc.&lt;/p&gt;

&lt;p&gt;Let’s set up these technologies to use them in a &lt;a href="https://nextjs.org/"&gt;Next.js&lt;/a&gt; project that uses &lt;a href="https://www.typescriptlang.org/"&gt;TypeScript&lt;/a&gt;. If you are starting a new project, you can &lt;a href="https://medium.com/better-programming/how-to-set-up-next-js-with-typescript-5f912766c88"&gt;read my article&lt;/a&gt; about how to set up Next.js with TypeScript.&lt;/p&gt;




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

&lt;p&gt;Let’s start by adding the core ESLint linting library, the parser to lint TypeScript code, a TypeScript-specific plug-in, and a React-specific plug-in to our project.&lt;/p&gt;

&lt;p&gt;In the terminal, go to the root of your project and run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-react
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We should now create a &lt;code&gt;.eslintrc.json&lt;/code&gt; file at the root of our project. We can add our linting rules in this file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch .eslintrc.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can already add the default options to that file. We will add our options as we go:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "parser": {},
  "extends": \[\],
  "rules": {},
  "globals": {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, ESLint depends on a parser to read JavaScript code. We use &lt;a href="https://github.com/typescript-eslint/typescript-eslint#readme"&gt;@typescript-eslint/parser&lt;/a&gt; (an alternative parser that can read TypeScript), so we need to tell ESLint to use it instead. Besides that, we use &lt;a href="https://github.com/typescript-eslint/typescript-eslint"&gt;@typescript-eslint/eslint-plugin&lt;/a&gt; (a list of rules you can turn on or off). We also extend the plug-in &lt;a href="https://github.com/yannickcr/eslint-plugin-react"&gt;react/recommended&lt;/a&gt;, which contains React-specific linting rules.&lt;/p&gt;

&lt;p&gt;To configure the parser and extend the plug-ins, we need to modify the file we need to update our config 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;{
  "parser": "@typescript-eslint/parser",
  "extends": [
    "plugin:@typescript-eslint/recommended",
    "plugin:react/recommended"
  ],
  "plugins": [
    "@typescript-eslint",
    "react/recommended"
  ],
  "rules": {},
  "globals": {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next.js does not require you to import React into each component, which means you will start getting errors if you use this config in a Next.js application. We can fix this by adding &lt;code&gt;React&lt;/code&gt; into our &lt;code&gt;global&lt;/code&gt; and turning the &lt;code&gt;react-in-jsx-scope&lt;/code&gt; rule off.&lt;/p&gt;

&lt;p&gt;Our final config will 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;{
  "parser": "@typescript-eslint/parser",
  "extends": [
    "plugin:@typescript-eslint/recommended",
    "plugin:react/recommended"
  ],
  "plugins": [
    "@typescript-eslint",
    "react"
  ],
  "rules": {
    "react/react-in-jsx-scope": "off"
  },
  "globals": {
    "React": "writable"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;p&gt;Now let’s add Prettier and some plugins to make it work nicely with ESLint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add -D prettier eslint-config-prettier eslint-plugin-prettier
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/prettier/eslint-config-prettier"&gt;eslint-config-prettier&lt;/a&gt; will disable any linting rule that might interfere with an existing Prettier rule, and &lt;a href="https://github.com/prettier/eslint-plugin-prettier"&gt;eslint-plugin-prettier&lt;/a&gt; will run Prettier analysis as part of ESLint.&lt;/p&gt;

&lt;p&gt;Let’s add them to our ESLint config to finish up our ESLint configuration. Make sure to put Prettier last so it can override other configs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "parser": "@typescript-eslint/parser",
  "extends": [
    "plugin:@typescript-eslint/recommended",
    "plugin:react/recommended",
    "plugin:prettier/recommended",
    "plugin:prettier/react",
    "plugin:prettier/@typescript-eslint"
  ],
  "plugins": [
    "@typescript-eslint",
    "react",
    "prettier"
  ],
  "rules": {
    "react/react-in-jsx-scope": "off"
  },
  "globals": {
    "React": "writable"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Prettier is opinionated and intentionally limits the number of options (&lt;a href="https://prettier.io/docs/en/why-prettier.html"&gt;read why&lt;/a&gt;). If you want, you can overwrite some rules of Prettier by creating a &lt;code&gt;.prettierrc&lt;/code&gt; file in the root of your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch .prettierrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following configuration is an example file. I personally use this as my setting, but you can find all available configurations &lt;a href="https://prettier.io/docs/en/configuration.html"&gt;in the official documentation&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "semi": true,
    "singleQuote": true
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add a git hook
&lt;/h3&gt;

&lt;p&gt;Optionally, you can use &lt;a href="https://github.com/typicode/husky"&gt;husky&lt;/a&gt; and &lt;a href="https://github.com/azz/pretty-quick"&gt;pretty-quick&lt;/a&gt; to add a git hook that will always lint and format your changed files.&lt;/p&gt;

&lt;p&gt;First, install them as dev dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add pretty-quick husky -D
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now add the following &lt;code&gt;husky&lt;/code&gt; and &lt;code&gt;lint-staged&lt;/code&gt; configuration to your &lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"scripts": {
  ...
  "lint": "eslint --ext .ts,.tsx",
},
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the pre-commit hook in your &lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"husky": {
  "hooks": {
    "pre-commit": "pretty-quick --staged &amp;amp;&amp;amp; npm run lint"
   }
},
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, whenever you commit your changes, it will format and lint your new code.&lt;/p&gt;




&lt;h3&gt;
  
  
  Code Editor Extensions
&lt;/h3&gt;

&lt;p&gt;If you haven’t done so already, I recommend installing the &lt;a href="https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode"&gt;Prettier&lt;/a&gt; and &lt;a href="https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint"&gt;ESLint&lt;/a&gt; extensions for your code editor. If you don’t want to format your file manually every time, you can format it on save as well. I highly recommend this. For Visual Studio Code, all you need to do is open your VSCode User settings/preferences and set the &lt;code&gt;Format On Save&lt;/code&gt; option to &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That’s it! Thanks for reading. I hope it was helpful.&lt;/p&gt;




&lt;p&gt;If you’re interested in saving time on your next project and skip implementing authentication, payments, etc. then check out &lt;a href="https://serverless.page"&gt;Serverless SaaS&lt;/a&gt;, the SaaS starter-kit for React developers. You can also follow me on &lt;a href="https://twitter.com/jakeprins_nl"&gt;Twitter&lt;/a&gt;, or at &lt;a href="https://jakeprins.com"&gt;jakeprins.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>react</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>SASS vs CSS-in-JS vs Tailwind CSS</title>
      <dc:creator>Jake Prins</dc:creator>
      <pubDate>Sat, 12 Dec 2020 14:59:00 +0000</pubDate>
      <link>https://forem.com/jakeprins/sass-vs-css-in-js-vs-tailwind-css-17nn</link>
      <guid>https://forem.com/jakeprins/sass-vs-css-in-js-vs-tailwind-css-17nn</guid>
      <description>&lt;p&gt;As a developer, there are many choices to make when building your next application. The rise of serverless technologies allows developers to build and run applications without thinking about servers and this also allows front-end developers to create full-stack applications and build SaaS web apps.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;Stack Choices&lt;/strong&gt;, I take a closer look at some technologies that can help us to build these types of applications and try to make a good decision on what to use. In the last episodes, I took a look at &lt;a href="https://medium.com/stack-choices-javascript-vs-typescript-c9db39b67bf6"&gt;JavaScript vs TypeScript&lt;/a&gt;, &lt;a href="https://medium.com/stack-choices-react-vs-vue-vs-angular-vs-svelte-49aa0170c634"&gt;React vs Vue vs Angular vs Svelte&lt;/a&gt;, and &lt;a href="https://medium.com/stack-choices-create-react-app-vs-next-js-f0f3c4db7083"&gt;Create React App vs Next.js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This time, let’s take a look at some options for styling the application. I’ve worked with different approaches like CSS modules, Styled-Components, frameworks like Bootstrap, or just vanilla CSS. In this post, we are going to focus on three of my favorites: SASS, CSS-in-JS, and Tailwind.&lt;/p&gt;

&lt;h2&gt;
  
  
  SASS
&lt;/h2&gt;

&lt;p&gt;Going with classical CSS, using a preprocessor like SASS has been my way of styling applications for years. CSS is easy to learn but very hard to maintain. That’s why, as your project grows larger, you need a proper structure. &lt;a href="http://getbem.com/"&gt;BEM&lt;/a&gt; (Block Element Modifiers), is a naming styling that tries to solve the naming problem and structure that CSS often run into. BEM also provides a better structure for your CSS code and scalable CSS.&lt;/p&gt;

&lt;p&gt;CSS preprocessors in combination with BEM definitely improve the development experience a lot, but that doesn’t mean it’s perfect. When your codebase grows, you might start to wonder in which files you should put certain styles and how it should be scoped. You also wonder if old styles are still being used. And you also have to think about performance: you don’t want to load in every single line of CSS on the first page when most of it is used on other pages.&lt;/p&gt;

&lt;p&gt;There are many solutions to these problems, but one approach that I personally like is writing your CSS in JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  CSS-in-JS
&lt;/h2&gt;

&lt;p&gt;There are multiple CSS-in-JS libraries out there, like &lt;a href="https://styled-components.com/"&gt;Styled-Components&lt;/a&gt;, &lt;a href="https://emotion.sh/docs/introduction"&gt;Emotion&lt;/a&gt;, and &lt;a href="https://github.com/vercel/styled-jsx"&gt;Styled-JSX&lt;/a&gt;, and it has some benefits over using classic CSS. I personally really like the fact that it makes it simple to add specific CSS to a component. All styles are only applied to the component, so this also means you do not have to learn methodologies like BEM, use long class names, or need to think about where you put your styles.&lt;/p&gt;

&lt;p&gt;The other main advantage is that styles are rendered only if the component is on screen. You don’t have to worry about performance or unused styles. Also, because of the component-based architecture, we can have changes controlled by props. If you are a JavaScript developer I think you don’t need a lot of time to feel very familiar with writing your styles in JavaScript as well.&lt;/p&gt;

&lt;p&gt;At first look, CSS-in-JS might look difficult, because the learning curve is a little bit bigger than using SASS. But if you are working on a component-heavy JavaScript project, I think CSS-in-JS is definitely worth trying out.&lt;/p&gt;

&lt;h2&gt;
  
  
  TailwindCSS
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://tailwindcss.com/"&gt;Tailwind&lt;/a&gt; is a CSS framework, but not like Bootstrap or Ant Design. It’s a utility-first framework, which means it doesn’t focus on predesigned components like buttons, cards, and alerts. It provides low-level utility classes that let you build completely custom designs without leaving your HTML.&lt;/p&gt;

&lt;p&gt;If you go for a framework, you usually need to stick to the components of that framework, which can lead to overriding unwanted styles or battling specificity wars. Tailwind is different, it’s basically a different way of styling your application.&lt;/p&gt;

&lt;p&gt;There are great benefits of using Tailwind, like development speed. Tailwind provides almost all the tools you need to build out a site in just HTML, so you rarely need to write any custom CSS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"md:flex"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"md:flex-shrink-0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"rounded-lg md:w-56"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"[https://cdn-images-1.medium.com/fit/c/32/32/1\*\_SiS1xvFOqiK6TnkiGcZ2A.jpeg](https://cdn-images-1.medium.com/fit/c/32/32/1*_SiS1xvFOqiK6TnkiGcZ2A.jpeg)"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Jake"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mt-4 md:mt-0 md:ml-6"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-sm tracking-wide uppercase text-cloud-burst-600 font- bold"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Marketing&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"block mt-1 text-lg font-semibold leading-tight text-gray-900 hover:underline"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Finding customers for your new business&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mt-2 text-gray-600"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Getting a new business off the ground is a lot of hard work. Here are five ideas you can use to find your first customers.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tailwind was built from the ground-up to be super customizable. It comes with a default configuration, but you can simply override the default configuration with a &lt;code&gt;tailwind.config.js&lt;/code&gt; file in your project.&lt;/p&gt;

&lt;p&gt;Also, any changes you make will be made in your templates, therefore only affecting the page you’re working on.&lt;/p&gt;

&lt;p&gt;Besides that, all its utilities are also generated with responsive versions which are very helpful if you want to make your application look nice on mobile, tablet, and desktop.&lt;/p&gt;

&lt;p&gt;One thing I didn’t like about using Tailwind is the long class names you can end up with. The more styling you need on a single element, the longer that class name is going to be. This harms the readability of your HTML files a bit, but after a while, I got used to it and it doesn’t bother me that much anymore.&lt;/p&gt;

&lt;p&gt;The other problem with Tailwind is the large file size, but you can use &lt;a href="https://github.com/FullHuman/purgecss"&gt;PurgeCSS&lt;/a&gt; to fix this. PurgeCSS reduces the file size by scanning your HTML and removing any classes that aren’t used. Luckily, setting up PurgeCSS to work with Tailwind is easy, so this could make Tailwind an absolute winner.&lt;/p&gt;

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

&lt;p&gt;There are many ways to manage the styling of your application. In the beginning, this is easy, but when your projects start to grow you will encounter difficulties. Using a traditional approach to CSS is not a wrong decision, but nowadays there are other options you could consider. Personally, I like CSS-in-JS a lot and as a JavaScript developer, it makes sense to me to go with this approach.&lt;/p&gt;

&lt;p&gt;On the other hand, I’ve been working a lot with TailwindCSS lately and I don’t think I’ve ever been that excited about a CSS framework. I made some projects, like &lt;a href="http://remoterocket.io"&gt;RemoteRocket.io&lt;/a&gt;, with TailwindCSS and I’ve noticed a huge boost in productivity while working on it. Although it requires some time to learn all the utility classes, you barely need to write any CSS anymore once you master those. And not needing to switch files while styling your HTML elements feels like a blessing.&lt;/p&gt;

&lt;p&gt;With all that in mind, I’ve made my stack choice: &lt;strong&gt;TailwindCSS&lt;/strong&gt;. If you think differently, please try to change my mind! Reach out top me on Twitter: &lt;a href="https://twitter.com/jakeprins_nl"&gt;@jakeprins_nl&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;If you’re interested in saving time on your next project and skipping implementing authentication, payments, tests, etc. then &lt;a href="https://serverless.page/"&gt;subscribe here&lt;/a&gt; to follow my progress in building the SAAS starter-kit for React developers. You can also &lt;a href="https://twitter.com/jakeprins_nl"&gt;follow me on Twitter&lt;/a&gt;, or at &lt;a href="https://www.jakeprins.com/"&gt;www.jakeprins.com&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>React vs Vue vs Angular vs Svelte</title>
      <dc:creator>Jake Prins</dc:creator>
      <pubDate>Sat, 12 Dec 2020 14:57:00 +0000</pubDate>
      <link>https://forem.com/jakeprins/react-vs-vue-vs-angular-vs-svelte-4026</link>
      <guid>https://forem.com/jakeprins/react-vs-vue-vs-angular-vs-svelte-4026</guid>
      <description>&lt;h1&gt;
  
  
  React vs Vue vs Angular vs Svelte
&lt;/h1&gt;

&lt;p&gt;5 min read&lt;/p&gt;

&lt;p&gt;As a developer, there are many choices to make when building your next application. The rise of serverless technologies allows developers to build and run applications without thinking about servers and this also allows front-end developers to create full-stack applications and &lt;a href="https://serverless.page/"&gt;build SAAS web apps&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;Stack Choices&lt;/strong&gt;, we take a closer look at some technologies that can help us to build these types of applications and try to make a good decision on what to use. In the last episode, I took a look at &lt;a href="https://medium.com/stack-choices-javascript-vs-typescript-c9db39b67bf6"&gt;JavaScript vs TypeScript&lt;/a&gt;. This time, let’s take a look at the JavaScript frameworks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Angular
&lt;/h2&gt;

&lt;p&gt;This JavaScript framework, developed by Google, has been around for a while and it’s not really the cool kid on the block inside the frontend community. The move from angular 1 (AngularJS) to Angular 2, which was so different it required complete rewrites, seems to left some scars, but times have changed and lots of progress has been made.&lt;/p&gt;

&lt;p&gt;Updating your application to the next major version of Angular has never been easier. Since Angular 8, you can just use &lt;code&gt;ng update&lt;/code&gt; it to update your application and its dependencies. Besides that, with the new Angular CLI, you can generate components, routes, services, and pipes with a simple command. Besides that, Angular is very stable and has support for great technologies like Typescript and Web Workers, etc. Also, the new &lt;strong&gt;Ivy&lt;/strong&gt; renderer is officially released in Angular 9, which decreased payload size and has a lot of other interesting benefits.&lt;/p&gt;

&lt;h3&gt;
  
  
  My opinion
&lt;/h3&gt;

&lt;p&gt;After first working with React for quite some time I joined a team that worked with Angular. I have now worked with them for over a year and although I was a bit skeptical at the beginning, I started to like Angular more and more. Some people complain about the file size or that the framework is too bloated, but I think it’s nice to have a framework that has lots of features built-in. It’s not as easy to pick up as Vue or React, and I also wouldn't choose it for smaller side-projects, but for production applications, especially those that you need to work on with multiple people, Angular is a very nice framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  React
&lt;/h2&gt;

&lt;p&gt;According to NPM trends, React is by far the most downloaded framework. Stack Overflow Trends also reveals that React receives the largest percentage. It’s easy to see why lots of people choose React for there new applications: it’s a save bet. Large companies such as Airbnb and Netflix have been using React.js for many years now, and we see that the technology is being embraced by more and more companies. The interest in React among developers is huge and that makes it a technology that will probably gain even more popularity in the upcoming years.&lt;/p&gt;

&lt;h3&gt;
  
  
  My opinion
&lt;/h3&gt;

&lt;p&gt;Most popular doesn't mean it’s the best, also React has its flaws. But personally, I absolutely like working with it. I have made most of my side-projects with React, like &lt;a href="https://www.raterfox.com/"&gt;RaterFox&lt;/a&gt;, &lt;a href="https://codestash.co/"&gt;Codestash&lt;/a&gt;, &lt;a href="https://www.makermove.com/"&gt;MakerMove&lt;/a&gt;, and more. I think it’s easy to get started with React, but when you build large applications you find yourself reaching for a lot of other libraries just to get some basic things done, like routing or global state management. These libraries usually all have there strong points and weaknesses. It’s nice to have the freedom to choose but at some point, I think it would help the developer community if we could just all go for the same thing. Instead of introducing yet another state management library or another way to implement CSS-in-JS, I think it might be beneficial to sometimes have fewer choices.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I’ve made a React boilerplate called &lt;a href="https://www.reactmilkshake.com/"&gt;React Milkshake&lt;/a&gt; that can give you a headstart with your new project. And I’m working on a React starter-kit with Nextjs to build full-stack SaaS applications. You can &lt;a href="https://serverless.page/"&gt;sign up here&lt;/a&gt; to get notified when it launches.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Vue
&lt;/h2&gt;

&lt;p&gt;Another amazing JS framework is &lt;a href="https://vuejs.org/"&gt;Vue.js&lt;/a&gt;. With very detailed documentation and a fairly low learning curve, Vue.js is a suitable choice when you want to experiment with a new framework as a developer.&lt;/p&gt;

&lt;p&gt;Because of the resemblance to React and Angular in terms of architecture, it is an easy transition from other frameworks. Loved for its small size, speed and flexibility, Vue.js delivers even &lt;a href="https://www.stefankrause.net/js-frameworks-benchmark6/webdriver-ts-results/table.html"&gt;better performance&lt;/a&gt; compared to other frontend frameworks.&lt;/p&gt;

&lt;p&gt;Vue.js currently still has a much smaller market share compared to React. Due to the positive opinions from the developer community and the growth in the use of Vue, it seems likely that Vue.js will continue to develop positively.&lt;/p&gt;

&lt;h3&gt;
  
  
  My opinion
&lt;/h3&gt;

&lt;p&gt;I have little personal experience with Vue, but to experiment with it I made &lt;a href="https://remoterocket.io/"&gt;RemoteRocket&lt;/a&gt;, a platform with all the remote jobs from popular remote job sites. It’s easy to pick up, especially with the Vue CLI, and I definitely recommend giving Vue a try (if you haven’t already).&lt;/p&gt;

&lt;h2&gt;
  
  
  Svelte
&lt;/h2&gt;

&lt;p&gt;The big underdog of the frontend frameworks: Svelte. It’s been around for a couple of years and in April 2019 version 3.00 was released. Svelte is a little different than React, Vue, or Angular because it compiles your code to tiny, framework-less vanilla JS. And it’s not just very performant, with no run-time dependencies, it’s also very elegant and easy to learn the framework. It’s npm downloads have more than tripled over the last year, and in the results of the &lt;a href="https://2019.stateofjs.com/front-end-frameworks/svelte/"&gt;2019 State of JS survey&lt;/a&gt;, it showed that 44.9% of JS developers were interested in learning Svelte. Time has to tell if people will actually adopt it in production applications, so I’m curious about what the future will bring for Svelte.&lt;/p&gt;

&lt;h3&gt;
  
  
  My opinion
&lt;/h3&gt;

&lt;p&gt;I personally haven’t got the time to try out Svelte, but it’s very high up on my list of technologies to explore. If you want to learn more I can recommend you &lt;a href="https://www.youtube.com/watch?v=AdNJ3fydeao"&gt;this&lt;/a&gt; video of Rich Harris’ (the creator of Svelte) talk about Rethinking reactivity or to listen to &lt;a href="https://syntax.fm/show/250/scott-teaches-wes-svelte-and-sapper"&gt;this&lt;/a&gt; podcast episode of the &lt;a href="http://syntax.fm"&gt;Syntax.fm&lt;/a&gt; where Scott Tolinski teaches Wes Bos about Svelte. It got me really excited and I can’t wait to start trying it out myself!&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Angular, React, Vue, or Svelte, are all great frameworks. I’ve worked with all of them except Svelte. I would really love to work with Svelte, but for my plan to build &lt;a href="https://serverless.page/"&gt;the best JavaScript boilerplate&lt;/a&gt; for building a SAAS business, I need to go with a framework I’m very experienced with. Besides that, popularity plays an important role, and for that reason, my choice has become: &lt;strong&gt;React&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you think differently, please try to change my mind! Any other opinions? Leave them in the comments.&lt;/p&gt;




&lt;p&gt;If you’re interested in saving time on your next project and skipping implementing authentication, payments, tests, etc. then &lt;a href="https://serverless.page/"&gt;subscribe here&lt;/a&gt; to follow my progress in building the SAAS starter-kit for JavaScript developers. You can also &lt;a href="https://twitter.com/jakeprins_nl"&gt;follow me on Twitter&lt;/a&gt;, or at &lt;a href="https://www.jakeprins.com/"&gt;www.jakeprins.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>react</category>
      <category>vue</category>
      <category>angular</category>
      <category>svelte</category>
    </item>
    <item>
      <title>How to Implement Netlify CMS With Next.js</title>
      <dc:creator>Jake Prins</dc:creator>
      <pubDate>Mon, 30 Nov 2020 09:28:52 +0000</pubDate>
      <link>https://forem.com/jakeprins/how-to-implement-netlify-cms-with-next-js-4gc1</link>
      <guid>https://forem.com/jakeprins/how-to-implement-netlify-cms-with-next-js-4gc1</guid>
      <description>&lt;h4&gt;
  
  
  &lt;em&gt;Manage the content of your Next.js apps through a free Git-based CMS&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;If you’re starting a new React project, you might want to consider &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; and &lt;a href="https://www.netlifycms.org/" rel="noopener noreferrer"&gt;Netlify CMS&lt;/a&gt;. In this article, we take a look at why this would be a great choice and walk through the process of setting up a new project using these technologies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Next.js?
&lt;/h2&gt;

&lt;p&gt;As I stated in &lt;a href="https://medium.com/better-programming/how-to-set-up-next-js-with-typescript-5f912766c88" rel="noopener noreferrer"&gt;a previous article&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“There are many important details you need to consider when you start a new project with React. Your code has to be bundled using a bundler like webpack and transformed using a compiler like Babel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://reactjs.org/docs/create-a-new-react-app.html" rel="noopener noreferrer"&gt;Create React App&lt;/a&gt; can be a nice tool to handle this for you and give you a massive head start, but what about code-splitting, pre-rendering for performance, and SEO or server-side rendering?&lt;/p&gt;

&lt;p&gt;To build a complete React application, you need more than CRA provides you with. You can save yourself some time by using Next.js, a React framework that provides a solution to all of these problems.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you want to read more about CRA vs. Next.js, check out &lt;a href="https://codeburst.io/stack-choices-create-react-app-vs-next-js-f0f3c4db7083" rel="noopener noreferrer"&gt;Stack choices: Create React App vs Next.js&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Netlify CMS?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.netlifycms.org/" rel="noopener noreferrer"&gt;Netlify CMS&lt;/a&gt; is an open-source Git-based content management system. It is based on client-side JavaScript and handles content updates directly in Git. Because all content is just stored in your Git repository, you don’t need to have anything hosted on a server. It’s completely free and a great fit to combine with Next.js to build landing pages or blogs that are manageable through a nice UI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s Begin
&lt;/h2&gt;

&lt;p&gt;Let’s begin building our landing page with some basic text to get familiar with Netlify CMS. You can find the source code of this part of the tutorial &lt;a href="https://github.com/jakeprins/nextjs-netlify-cms" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt; or check out &lt;a href="http://serverless.page/" rel="noopener noreferrer"&gt;serverless.page&lt;/a&gt; for a complete boilerplate that also includes features like authentication and billing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set up your project
&lt;/h3&gt;

&lt;p&gt;You can start by creating a new Next.js project with &lt;code&gt;npx create-next-app&lt;/code&gt;. In this example, we are going to use TypeScript. You can follow &lt;a href="https://medium.com/better-programming/how-to-set-up-next-js-with-typescript-5f912766c88" rel="noopener noreferrer"&gt;this tutorial&lt;/a&gt; on how to set up Next.js with Typescript.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Markdown Files for Our Content
&lt;/h2&gt;

&lt;p&gt;Netlify CMS works with markdown files, and it’s a great way to manage the content of your landing page or blog. Let’s begin by creating a markdown file that will have some data we want to show on our home screen.&lt;/p&gt;

&lt;p&gt;Make a &lt;code&gt;content&lt;/code&gt; directory that will hold all our markdown files. Next, create a &lt;code&gt;pages&lt;/code&gt; directory and a markdown file called &lt;code&gt;content/pages/home.md&lt;/code&gt;. This file will hold the data that we want to show on our home page. Let’s start by adding a title, description, and image for the “hero” section of our landing page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
hero_title: "Build a SaaS faster with React"
hero_description: "Serverless SaaS is aiming to be the perfect starting point for your next React app to build full-stack SaaS applications. Visit serverless.page for more info."
---
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we need to tell webpack how to load markdown files. Let’s use &lt;code&gt;frontmatter-markdown-loader&lt;/code&gt; for this. Start by installing that package as a dev dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add frontmatter-markdown-loader -D
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, create a new &lt;code&gt;next.config.js&lt;/code&gt; file at the root of your project with the following content:&lt;/p&gt;

&lt;h3&gt;
  
  
  Create the home page
&lt;/h3&gt;

&lt;p&gt;Cool, now let’s add some code to the index page to make it our home page.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;pages/index.tsx&lt;/code&gt;, add the following:&lt;/p&gt;

&lt;p&gt;Let’s have a look at what’s going on here. The most important part is the exported &lt;code&gt;getStaticProps&lt;/code&gt; function. If you export an &lt;code&gt;async&lt;/code&gt; function called &lt;code&gt;getStaticProps&lt;/code&gt; from a page, Next.js will pre-render this page at build time using the props returned by &lt;code&gt;getStaticProps&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;On our page, we import our markdown file called &lt;code&gt;home.md&lt;/code&gt; and pass it a &lt;code&gt;content&lt;/code&gt; prop to our component. Our home page can now use the &lt;code&gt;hero_title&lt;/code&gt; and &lt;code&gt;hero_description&lt;/code&gt; attributes of the markdown file.&lt;/p&gt;

&lt;p&gt;Let’s try it out and see if it’s working:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;You should see your amazing hero section, ready to be styled and managed with your upcoming CMS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implement Netlify CMS
&lt;/h2&gt;

&lt;p&gt;There are different ways to add Netlify CMS to your project. We are going to use the official npm package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add netlify-cms-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add the configuration
&lt;/h3&gt;

&lt;p&gt;Before we can initialize our CMS, we need to create a config file. Create a &lt;code&gt;cms&lt;/code&gt; directory at the root of your project and paste the following configuration to your &lt;code&gt;cms/config.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;cms_manual_init&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;github&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;yourname/your-github-repo-name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;branch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;main&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;media_folder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public/img&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;public_folder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;img&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pages&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Pages&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content/pages/home.md&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hero Title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hero_title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hero Description&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hero_description&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;markdown&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="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Netlify CMS has different options on how to handle authentication. We are going to use this config file to tell Netlify CMS that we want to use the GitHub for this. For repositories stored on GitHub, the &lt;code&gt;github&lt;/code&gt; back end allows CMS users to log in directly with their GitHub account. Note that all users must have push access to their content repository for this to work.&lt;/p&gt;

&lt;p&gt;If you haven’t done already, now would be a good time to &lt;a href="https://github.com/new" rel="noopener noreferrer"&gt;create your repository on GitHub&lt;/a&gt;, add the name of your repo to the config file, and push your code to GitHub. Go ahead — I’ll wait.&lt;/p&gt;

&lt;p&gt;Good, but before we move on, let’s take a look at the most important setting of our configuration: the &lt;code&gt;collections&lt;/code&gt;. This determines how content types and editor fields in the UI generate files and content in your repository.&lt;/p&gt;

&lt;p&gt;Inside &lt;code&gt;collections&lt;/code&gt;, we create a &lt;code&gt;pages&lt;/code&gt; collection that has some settings for the &lt;code&gt;home&lt;/code&gt; page. For now, we only added the &lt;code&gt;hero_title&lt;/code&gt; and &lt;code&gt;hero_description&lt;/code&gt; fields. You can set which &lt;a href="https://www.netlifycms.org/docs/widgets/#header" rel="noopener noreferrer"&gt;widget&lt;/a&gt; to use for the given property.&lt;/p&gt;

&lt;p&gt;You can read about all other configuration options &lt;a href="https://www.netlifycms.org/docs/configuration-options" rel="noopener noreferrer"&gt;in the documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initialize the CMS
&lt;/h3&gt;

&lt;p&gt;Next, let’s create an admin page for our CMS. Add the following code to &lt;code&gt;pages/admin.tsx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;dynamic&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/dynamic&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;config&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;../cms/config&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;CMS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;netlify-cms-app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;cms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;cms&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;ssr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Loading...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AdminPage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CMS&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Now you should be able to navigate to &lt;a href="https://localhost:4202/" rel="noopener noreferrer"&gt;http://localhost:3000/admin&lt;/a&gt; and see a GitHub login button. Hit the button and see your nice new CMS!&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%2Fmiro.medium.com%2Fmax%2F700%2F1%2AsCq_bD6q9UjrCg-YhKpL_A.png" class="article-body-image-wrapper"&gt;&lt;img alt="Blank CMS" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F700%2F1%2AsCq_bD6q9UjrCg-YhKpL_A.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Try it out
&lt;/h3&gt;

&lt;p&gt;Cool, now try it out! Select “Home” and you will see the edit page. You can edit the &lt;code&gt;hero_title&lt;/code&gt; and &lt;code&gt;hero_description&lt;/code&gt; properties and click the &lt;code&gt;publish&lt;/code&gt; button. When you publish, Netlify CMS is making a commit to your repository with the changes you just made. You can take a look at the last commit after you have published some changes.&lt;/p&gt;

&lt;p&gt;Now, all you have to do is &lt;code&gt;git pull&lt;/code&gt; to get those changes locally and navigate back to &lt;a href="http://localhost:3000/" rel="noopener noreferrer"&gt;http://localhost:3000/&lt;/a&gt;. You will see that the home page contains your changes. Sweet!&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Images
&lt;/h2&gt;

&lt;p&gt;Most hero sections contain a pretty image. Let’s use the &lt;code&gt;image&lt;/code&gt; widget to add an image to our hero section. Go to your &lt;code&gt;cms/config.js&lt;/code&gt; file and add the following object to the &lt;code&gt;fields&lt;/code&gt; array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hero Image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hero_image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we could simply add an image to our &lt;code&gt;public/img&lt;/code&gt; folder and add it to our &lt;code&gt;home.md&lt;/code&gt;, but to demonstrate how Netlify CMS works, we are going to use the CMS to do it.&lt;/p&gt;

&lt;p&gt;First, we need to upload an image to our integrated media library. On the dashboard of the CMS, click the “Media” link in the top navbar and upload an image. After that, navigate to the edit screen of the home page.&lt;/p&gt;

&lt;p&gt;You should now see the added &lt;code&gt;hero_image&lt;/code&gt; field with a button that says, “Choose an image.” You can now select your uploaded image and publish the changes.&lt;/p&gt;

&lt;p&gt;Great, we should now have a new commit to our repo with the new changes. If our application was already in production, we could see the changes live, but since we want to see these changes locally, we need to first pull them from GitHub.&lt;/p&gt;

&lt;p&gt;After you have run &lt;code&gt;git pull&lt;/code&gt;, there is really only one thing left to do, which is adding the image to our home page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hero_image&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="s1"&gt;hero image&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, run &lt;code&gt;yarn dev&lt;/code&gt; and go to &lt;a href="http://localhost:3000/" rel="noopener noreferrer"&gt;http://localhost:3000/&lt;/a&gt; to see your added image!&lt;/p&gt;

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

&lt;p&gt;Netlify CMS is a very useful library you can add to your Next.js apps. It’s just a client-side React application, and it uses Git to store content in your own repository. This has some nice benefits: You don’t need to host your CMS separately and it fits perfectly in your Git workflow. This is great for managing the content of a landing page or blog post.&lt;/p&gt;

&lt;p&gt;If you are looking for a complete boilerplate, check out &lt;a href="http://serverless.page/" rel="noopener noreferrer"&gt;serverless.page&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;We have covered a lot in this tutorial, but we have only seen the basics of how Netlify CMS works in a Next.js application. There is a lot more we can do! Stay tuned for upcoming articles to continue our work with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A blog&lt;/li&gt;
&lt;li&gt;More widgets for managing content&lt;/li&gt;
&lt;li&gt;Styling and CMS previews&lt;/li&gt;
&lt;li&gt;Customizing with additional configuration settings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;View the source code of this tutorial &lt;a href="https://github.com/jakeprins/nextjs-netlify-cms" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for reading! You can find me on Twitter (&lt;a href="https://twitter.com/jakeprins_nl" rel="noopener noreferrer"&gt;@jakeprins_nl&lt;/a&gt;) or read more at &lt;a href="https://jakeprins.com/blog" rel="noopener noreferrer"&gt;jakeprins.com/blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>react</category>
      <category>nextjs</category>
      <category>cms</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Create React App vs Next.js</title>
      <dc:creator>Jake Prins</dc:creator>
      <pubDate>Mon, 12 Oct 2020 13:23:50 +0000</pubDate>
      <link>https://forem.com/jakeprins/create-react-app-vs-next-js-2dp4</link>
      <guid>https://forem.com/jakeprins/create-react-app-vs-next-js-2dp4</guid>
      <description>&lt;p&gt;As a developer, there are many choices to make when building your next application. The rise of serverless technologies allows developers to build and run applications without thinking about servers and this also allows front-end developers to create full-stack applications and build SAAS web apps.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;Stack Choices&lt;/strong&gt;, we take a closer look at some technologies that can help us to build these types of applications and try to make a good decision on what to use. In the last episodes, I took a look at &lt;a href="https://medium.com/stack-choices-javascript-vs-typescript-c9db39b67bf6"&gt;JavaScript vs TypeScript&lt;/a&gt; and &lt;a href="https://medium.com/stack-choices-react-vs-vue-vs-angular-vs-svelte-49aa0170c634"&gt;React vs Vue vs Angular vs Svelte&lt;/a&gt;. This time, let’s take a look at &lt;a href="https://reactjs.org/docs/create-a-new-react-app.html"&gt;&lt;strong&gt;Create React App&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;(CRA) vs&lt;/strong&gt; &lt;a href="https://nextjs.org/"&gt;&lt;strong&gt;Next.js&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://reactjs.org/docs/create-a-new-react-app.html"&gt;CRA&lt;/a&gt; is a tool that gives you a massive head start when building React apps. It saves you from time-consuming setup and configuration. You simply run one command and Create React App sets up the tools you need to start your React project. This is great to start focusing on building your application from the start and don’t waste time configuring your webpack etc. But for building performing production-ready applications, you might need a little bit more. You might need serverside-rendering for SEO, or code-splitting to increase performance. You could use a boilerplate that has some features built-in (like &lt;a href="https://www.reactmilkshake.com/"&gt;React Milkshake&lt;/a&gt;), or you can take a look at a framework like &lt;a href="https://nextjs.org/"&gt;Next.js&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next.js
&lt;/h2&gt;

&lt;p&gt;Next.js is a framework built by &lt;a href="https://vercel.com/dashboard"&gt;Vercel&lt;/a&gt;. It’s open-source, based on Node.js and Babel, and it integrates with React to develop single-page applications. It makes Serversside rendering very easy. According to &lt;a href="https://nextjs.org/"&gt;nextjs.org&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;With Next.js, server rendering React applications has never been easier, no matter where your data is coming from.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Next.js also supports static exporting, pre-Rendering, and has a lot more nice features like automatic building size optimization, faster dev compilation, and preview mode.&lt;/p&gt;

&lt;p&gt;In my opinion, the current version of Nextjs is what React was missing for a long time. It has all the features you need when you build a production-ready application that needs to perform. Also, the docs are nice and it’s becoming more and more popular among front-end developers.&lt;/p&gt;

&lt;p&gt;Next.js is really good, but that doesn’t mean you should always go with this framework.&lt;/p&gt;

&lt;p&gt;Although it makes server-side rendering a lot easier, it still introduces some complexity. For instance, if you use Redux, your store should also be in sync on the server. And when you use translated labels inside your application, be aware that this must also be handled on the server.&lt;/p&gt;

&lt;p&gt;Also, for every server-rendered route that you have, a serverless function will be created. Currently, the free tier a limitation of 12 serverless functions, so if you use SSR and your app has more than 12 routes you need to pay for hosting. This might not be a problem for everybody, but when you build your app with CRA you are sure you can host it on platforms like &lt;a href="https://vercel.com/dashboard"&gt;Vercel&lt;/a&gt;, &lt;a href="https://netlify.com/"&gt;Netlify&lt;/a&gt;, or &lt;a href="https://render.com/"&gt;Render&lt;/a&gt; for free. I wrote an article that dives a little deeper into this, you can read it here: &lt;a href="https://medium.com/better-programming/why-i-migrated-from-next-js-to-create-react-app-7e74834e8431"&gt;Why I Migrated From Next.js to Create React App&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;CRA is a great starting point for your next app, but to take things to the next level I think Nextjs can come in handy. It does introduce a little more complexity in certain areas and I’m not really happy with serverless functions limitations, but I think Next.js offers so many nice features that my decision is clear: &lt;strong&gt;Next.js&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you think differently, please try to change my mind! Any other opinions? Leave them in the comments.&lt;/p&gt;




&lt;p&gt;If you’re interested in saving time on your next project and skip implementing authentication, payments, etc. then &lt;a href="https://serverless.page/"&gt;subscribe here&lt;/a&gt; to follow my progress in building the SaaS starter-kit for React developers. You can also &lt;a href="https://twitter.com/jakeprins_nl"&gt;follow me on Twitter&lt;/a&gt;, or at &lt;a href="https://www.jakeprins.com/"&gt;www.jakeprins.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>react</category>
      <category>nextjs</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Stack Choises: JavaScript vs TypeScript</title>
      <dc:creator>Jake Prins</dc:creator>
      <pubDate>Fri, 09 Oct 2020 12:12:38 +0000</pubDate>
      <link>https://forem.com/jakeprins/stack-choises-javascript-vs-typescript-gdl</link>
      <guid>https://forem.com/jakeprins/stack-choises-javascript-vs-typescript-gdl</guid>
      <description>&lt;h1&gt;
  
  
  JavaScript vs TypeScript
&lt;/h1&gt;

&lt;p&gt;As a developer, there are many choices to make when building your next application. The rise of serverless technologies allows developers to build and run applications without thinking about servers and this also allows front-end developers to create full-stack applications and build SAAS web apps.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;Stack Choices&lt;/strong&gt;, we take a closer look at some technologies that can help us to build these types of applications and try to make a good decision on what to use. This time, let’s take a look at going with plain old JavaScript or the rising star: &lt;a href="https://www.typescriptlang.org/"&gt;TypeScript&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  What is TypeScript?
&lt;/h1&gt;

&lt;p&gt;TypeScript is an open-source language that builds on JavaScript by adding static type definitions. Types provide a way to describe the shape of an object, providing better documentation, and allowing TypeScript to validate that your code is working correctly.&lt;/p&gt;

&lt;p&gt;You can easily use Typescript when starting a new React application by running &lt;code&gt;yarn create-react-app my-app --template typescript&lt;/code&gt; or work with Angular, which comes with Typescript by default.&lt;/p&gt;

&lt;h1&gt;
  
  
  How popular is TypeScript?
&lt;/h1&gt;

&lt;p&gt;TypeScript seems to be taking over front-end development. Almost 90% of developers (who filled in &lt;a href="https://2019.stateofjs.com/javascript-flavors/typescript/"&gt;the state of js survey&lt;/a&gt;) admit they would like to use or learn TypeScript in their next project. Besides that, it's one of the most loved languages, according to the 2019 &lt;a href="https://insights.stackoverflow.com/survey/2019#most-loved-dreaded-and-wanted"&gt;Developer Survey&lt;/a&gt; by Stack Overflow.&lt;/p&gt;

&lt;h1&gt;
  
  
  My personal experience
&lt;/h1&gt;

&lt;p&gt;I have been working with Typescript full-time for over a year now, and I have experienced the benefits of using TypeScript when working in a team. Something I personally like is, for example, the rich IDE support. I’m using &lt;a href="https://code.visualstudio.com/"&gt;VSCode&lt;/a&gt; and it offers features like code navigation, autocompletion, and providing accurate suggestions. You also get feedback while typing like flagging type-related errors as soon as they occur. This can help you write more maintainable code.&lt;/p&gt;

&lt;p&gt;Although TypeScript is really good, it’s not perfect. In the beginning, I didn’t like working with TypeScript at all. It requires some time to learn and you need to write more code than with just JavaScript.&lt;/p&gt;

&lt;p&gt;Here are, in my opinion, the pros and cons of choosing Typescript for your next project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pros for using Typescript
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;It has rich IDE support&lt;/li&gt;
&lt;li&gt;It has object-oriented programming features&lt;/li&gt;
&lt;li&gt;It helps to spot bugs early&lt;/li&gt;
&lt;li&gt;It is used in popular frameworks&lt;/li&gt;
&lt;li&gt;It’s growing in popularity&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Cons for using Typescript
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Writing more code&lt;/li&gt;
&lt;li&gt;Takes time to learn&lt;/li&gt;
&lt;li&gt;Adds complexity&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Although TypeScript requires you to write some more code and could take developers some time to learn, it’s benefits outweigh that in my opinion. We also see steady growth in the adoption of the language so I think this is not a hard decision to make. My stack choice: TypeScript.&lt;/p&gt;

&lt;p&gt;If you think differently, please try to change my mind! Any other opinions? Leave them in the comments.&lt;/p&gt;




&lt;p&gt;If you’re interested in saving time on your next project and skipping implementing authentication, payments, tests, etc. then &lt;a href="https://serverless.page/"&gt;subscribe here&lt;/a&gt; to follow my progress in building the SAAS starter-kit for JavaScript developers. You can also &lt;a href="https://twitter.com/jakeprins_nl"&gt;follow me on Twitter&lt;/a&gt;, or at &lt;a href="https://www.jakeprins.com/"&gt;www.jakeprins.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>How to Set Up Next.js With TypeScript</title>
      <dc:creator>Jake Prins</dc:creator>
      <pubDate>Fri, 18 Sep 2020 06:47:23 +0000</pubDate>
      <link>https://forem.com/jakeprins/how-to-set-up-next-js-with-typescript-255o</link>
      <guid>https://forem.com/jakeprins/how-to-set-up-next-js-with-typescript-255o</guid>
      <description>&lt;p&gt;If you start a new React project, you might want to consider &lt;a href="https://nextjs.org/"&gt;Next.js&lt;/a&gt; and &lt;a href="https://www.typescriptlang.org/"&gt;TypeScript&lt;/a&gt;. In this article, I explain why this would be a great choice and walk you through the process of setting up a new project using these technologies.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Next.js
&lt;/h2&gt;

&lt;p&gt;There are many important details you need to consider when you start a new project with React. Your code has to be bundled using a bundler, like webpack, and transformed using a compiler, like Babel.&lt;/p&gt;

&lt;p&gt;Create React App can be a nice tool to handle this for you and give you a massive head start, but what about code-splitting, prerendering for performance, and SEO or server-side rendering?&lt;/p&gt;

&lt;p&gt;To build a complete React application, you need more than CRA provides you with. You can save your self some time by using a Next.js, a React framework that provides a solution to all of these problems.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why TypeScript?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.typescriptlang.org/"&gt;TypeScript&lt;/a&gt; is an open-source language that builds on JavaScript by adding static type definitions. Types provide a way to describe the shape of an object, providing better documentation and allowing TypeScript to validate that your code is working correctly.&lt;/p&gt;

&lt;p&gt;TypeScript seems to be taking over front-end development. Almost 90% of developers (who filled in &lt;a href="https://2019.stateofjs.com/javascript-flavors/typescript/"&gt;the State of JS survey&lt;/a&gt;) admit they’d like to use or learn to use TypeScript in their next project. Besides that, it’s one of the most loved languages, according to the 2019 &lt;a href="https://insights.stackoverflow.com/survey/2019#most-loved-dreaded-and-wanted"&gt;developer survey&lt;/a&gt; by Stack Overflow.&lt;/p&gt;

&lt;p&gt;It’s very popular and has lots of benefits during development. I’ve specified these benefits some more in “&lt;a href="https://codeburst.io/stack-choices-javascript-vs-typescript-c9db39b67bf6"&gt;Stack Choices: JavaScript vs TypeScript&lt;/a&gt;.”&lt;/p&gt;




&lt;h2&gt;
  
  
  Let’s Start
&lt;/h2&gt;

&lt;p&gt;If you start from scratch, open your terminal, and inside your projects folder, run &lt;code&gt;yarn create next-app&lt;/code&gt; (Yarn is used in this example, but you could, of course, also go with npm).&lt;/p&gt;

&lt;p&gt;You’ll get prompted with the following message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What is your project named?
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Fill in a name, and hit enter. The next message you’ll see is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pick a template
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Choose &lt;code&gt;Default starter app&lt;/code&gt;, and wait until your project is ready. Then, type &lt;code&gt;cd &amp;lt;your-project-name&amp;gt;&lt;/code&gt; in your terminal to make sure you’re inside the directory where you can run &lt;code&gt;yarn dev&lt;/code&gt; to start the development server.&lt;/p&gt;

&lt;p&gt;If everything is fine, we can set up TypeScript. Start by creating an empty &lt;code&gt;tsconfig.json&lt;/code&gt; file in the root of your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch tsconfig.json
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Try restarting the development server (&lt;code&gt;yarn dev&lt;/code&gt;). You’ll get a warning message, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;It looks like you're trying to use TypeScript but do not have the required package(s) installed.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Follow the instructions to install TypeScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add --dev typescript @types/react @types/node
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, try starting the development server again. After starting the server, Next.js will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Populate the &lt;code&gt;tsconfig.json&lt;/code&gt; file for you. You may customize this file.&lt;/li&gt;
&lt;li&gt;Create the &lt;code&gt;next-env.d.ts&lt;/code&gt; file, which ensures Next.js types are picked up by the TypeScript compiler. You should &lt;em&gt;not&lt;/em&gt; touch this file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let’s try it out by changing the &lt;code&gt;index.js&lt;/code&gt; to &lt;code&gt;index.tsx&lt;/code&gt;. If nothing breaks, that means you can now use TypeScript for your Next.js application.&lt;/p&gt;

&lt;p&gt;And that’s it! Good luck with your project, and feel free to ask any questions if you have any.&lt;/p&gt;

&lt;p&gt;Thanks for reading.&lt;/p&gt;




&lt;p&gt;If you’re interested in saving time on your next project and skip implementing authentication, payments, teams, and more, then &lt;a href="https://serverless.page/"&gt;go here&lt;/a&gt; and subscribe to follow my progress in building the SaaS starter-kit for React developers. You can also &lt;a href="https://twitter.com/jakeprins_nl"&gt;follow me on Twitter&lt;/a&gt;, or at &lt;a href="https://www.jakeprins.com/"&gt;www.jakeprins.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>react</category>
      <category>typescript</category>
      <category>tutorial</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Code Splitting by Routes and Components in React</title>
      <dc:creator>Jake Prins</dc:creator>
      <pubDate>Thu, 30 Jan 2020 09:06:37 +0000</pubDate>
      <link>https://forem.com/jakeprins/code-splitting-by-routes-and-components-in-react-525c</link>
      <guid>https://forem.com/jakeprins/code-splitting-by-routes-and-components-in-react-525c</guid>
      <description>&lt;p&gt;When your app's bundle starts to grow it will slow things down. That's why we see a lot more use of code-splitting in modern web development. Code-splitting is the process of taking one large bundle containing your entire app and splitting them up into multiple smaller bundles which contain separate parts of your app. This technique allows you to load chunks of code only when needed. &lt;/p&gt;

&lt;p&gt;For example, when a visitor enters your application on the homepage, there is no need to load in all the code related to a completely separate page. That user might not even go to that route at all, so we only want to load it when the user navigates to that page. If we can load only the code necessary for the home page this means our initial loading time will be a lot faster, especially on slow networks. &lt;/p&gt;

&lt;p&gt;In this post, we will take a look at how we can boost the performance of our React applications by implementing code-splitting using &lt;a href="https://github.com/jamiebuilds/react-loadable"&gt;React Loadable&lt;/a&gt;. If you rather save time and start with a boilerplate that includes code-splitting, try out &lt;a href="https://www.reactmilkshake.com/"&gt;React Milkshake&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Route-based splitting
&lt;/h3&gt;

&lt;p&gt;A great way to get started is to implement route-based code-splitting, which means we load code chucks according to the current route.&lt;/p&gt;

&lt;p&gt;Normally, our routes could something look like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import { Route, Switch } from 'react-router-dom';

import Home from 'pages/Home';
import Example from 'pages/Example';

const Routes = () =&amp;gt; {
  return (
    &amp;lt;Switch&amp;gt;
      &amp;lt;Route path='/' exact component={Home} /&amp;gt;
      &amp;lt;Route path='/example' component={Example} /&amp;gt;
    &amp;lt;/Switch&amp;gt;
  );
};

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

&lt;/div&gt;

&lt;p&gt;Now, let's refactor these routes to implement code splitting using React Loadable. The &lt;code&gt;Loadable&lt;/code&gt; higher-order component takes an object with two keys: &lt;code&gt;loader&lt;/code&gt; and &lt;code&gt;loading&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import { Route, Switch } from 'react-router-dom';
import Loadable from 'react-loadable';

const AsyncHome = Loadable({
  loader: () =&amp;gt; import('./pages/Home'),
  loading: &amp;lt;div&amp;gt;Loading...&amp;lt;/div&amp;gt;
});

const AsyncExample = Loadable({
  loader: () =&amp;gt;
    import('./pages/Example'),
  loading: &amp;lt;div&amp;gt;Loading...&amp;lt;/div&amp;gt;
});

const Routes = () =&amp;gt; {
  return (
    &amp;lt;Switch&amp;gt;
      &amp;lt;Route path='/' exact component={AsyncHome} /&amp;gt;
      &amp;lt;Route path='/example' component={AsyncExample} /&amp;gt;
    &amp;lt;/Switch&amp;gt;
  );
};

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

&lt;/div&gt;

&lt;p&gt;With this simple setup, the code related to the &lt;code&gt;Example&lt;/code&gt; component will only load when that route is active. If you open your inspector in your browser and go to your network tab (js), you can see that if you change your routes a new code chunk will be loaded. &lt;/p&gt;

&lt;p&gt;Pro-tip. If you want to give your chunk a name instead of a generated hash, so you can clearly see which chunk just loaded, you can set the &lt;code&gt;webpackChunkName&lt;/code&gt; like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const AsyncExample = Loadable({
  loader: () =&amp;gt;
    import(/* webpackChunkName: "Example" */ './pages/Example'),
  loading: &amp;lt;div&amp;gt;Loading...&amp;lt;/div&amp;gt;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Sometimes components load really quickly (&amp;lt;200ms) and the loading screen only quickly flashes on the screen. A number of user studies have proven that this causes users to perceive things taking longer than they really have. If you don't show anything, users perceive it as being faster. Thankfully, your loading component will also get a pastDelay prop which will only be true once the component has taken longer to load than a set delay. Be default, delay is set to 200ms.&lt;/p&gt;

&lt;p&gt;To do that, let's create a &lt;code&gt;Loader&lt;/code&gt; component that we can use in our sample component that will now look like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const AsyncExample = Loadable({
  loader: () =&amp;gt;
    import(/* webpackChunkName: "Example" */ './pages/Example'),
  loading: Loader
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And our &lt;code&gt;Loader&lt;/code&gt; component:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';

const Loader = (props) =&amp;gt; {
    if (props.pastDelay) {
        return &amp;lt;h2&amp;gt;Loading...&amp;lt;/h2&amp;gt;
    } else {
        return null
    }
}

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

&lt;/div&gt;

&lt;p&gt;But what if something goes wrong while loading the code? Well, luckily React Loadable also provides users with an &lt;code&gt;error&lt;/code&gt; prop. This means our final &lt;code&gt;Loader&lt;/code&gt; component will look like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';

const Loader = ({ pastDelay, error }) =&amp;gt; {
    if (error) {
    return (
      &amp;lt;h2&amp;gt;Sorry, there was a problem loading the page.&amp;lt;/h2&amp;gt;
    );
  } else if (pastDelay) {
    return (
       &amp;lt;h2&amp;gt;Loading...&amp;lt;/h2&amp;gt;
    );
  } else {
    return null;
  }
};

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

&lt;/div&gt;

&lt;p&gt;And that's it! &lt;/p&gt;

&lt;h3&gt;
  
  
  Load on hover
&lt;/h3&gt;

&lt;p&gt;Now we can even go a little further. We can also start loading the next chunk as soon as the user starts to hover over the link. To achieve this, all we have to do is call &lt;code&gt;preload()&lt;/code&gt; on our Loadable component. It will look something like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState } from 'react';
import { Link } from 'react-router-dom';

import { AsyncExample } from 'routes';

const SideBar = () =&amp;gt; {
  return (
    &amp;lt;div className='sidebar'&amp;gt;           
      &amp;lt;Link to='/' exact={true}&amp;gt;Home&amp;lt;/Link&amp;gt;
      &amp;lt;Link 
        to='/example' 
        onMouseOver={() =&amp;gt; AsyncExample.preload()}&amp;gt;
        Example
      &amp;lt;/Link&amp;gt;     
    &amp;lt;/div&amp;gt;
  );
};

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

&lt;/div&gt;

&lt;p&gt;And that's it, awesome!&lt;/p&gt;

&lt;h3&gt;
  
  
  Component-based splitting
&lt;/h3&gt;

&lt;p&gt;Now that we know how to code split based on the current route, let's take it even a little further and look at how we can code split on component level. Inside your container component, you might render different components based on a certain state, like if a user is logged in or not. We can achieve this with the same Loadable component. Take a look at this example, in which a component is only rendered into the view once the user clicks on the button.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState } from 'react';
import Loadable from 'react-loadable';
import Loader from 'components/Loader';

const SomeComponent = Loadable({
  loader: () =&amp;gt; import('components/SomeComponent'),
  loading: Loading
});

const App = () =&amp;gt; {
    const [showComponent, setShowComponent] = useState(false);

  return (
    if (showComponent) {
      return &amp;lt;SomeComponent /&amp;gt;;
    } else {
      return (
        &amp;lt;&amp;gt;
          &amp;lt;h1&amp;gt;Hello! 👋&amp;lt;/h1&amp;gt;
          &amp;lt;button onClick={() =&amp;gt; setShowComponent(true)}&amp;gt;Click me!&amp;lt;/button&amp;gt;
        &amp;lt;/&amp;gt;
      );
    }
  );
};

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

&lt;/div&gt;

&lt;p&gt;Obviously, with such a simple component, it doesn’t make a difference, but with larger components in an app, it can be a good idea to implement code-splitting on component-level like this.&lt;/p&gt;

&lt;p&gt;And with this, you should be ready to implement code splitting in your React apps! Check out the repo of &lt;a href="https://github.com/jamiebuilds/react-loadable"&gt;React Loadable&lt;/a&gt; for more options. If you are looking for a nice boilerplate that comes with code-splitting out of the box, try out &lt;a href="https://www.reactmilkshake.com/"&gt;React Milkshake&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Thanks for reading! If you want to ben notified when I release new projects or articles then follow me on twitter: &lt;a href="https://twitter.com/jakeprins_nl"&gt;@jakeprins_nl&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>react</category>
      <category>tutorial</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
