<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ariburaco</title>
    <description>The latest articles on DEV Community by ariburaco (@ariburaco).</description>
    <link>https://dev.to/ariburaco</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%2F1001098%2F36003843-6bcf-4acc-92c9-4397196afa40.png</url>
      <title>DEV Community: ariburaco</title>
      <link>https://dev.to/ariburaco</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ariburaco"/>
    <language>en</language>
    <item>
      <title>Introducing ChatGPT File Uploader Extended: A Chrome Extension for Easy File Processing (PDF, WORD, EXCEL and ZIP Files!)</title>
      <dc:creator>ariburaco</dc:creator>
      <pubDate>Mon, 22 May 2023 11:33:42 +0000</pubDate>
      <link>https://dev.to/ariburaco/introducing-chatgpt-file-uploader-extended-a-chrome-extension-for-easy-file-processing-pdf-word-excel-and-zip-files-501i</link>
      <guid>https://dev.to/ariburaco/introducing-chatgpt-file-uploader-extended-a-chrome-extension-for-easy-file-processing-pdf-word-excel-and-zip-files-501i</guid>
      <description>&lt;p&gt;Are you tired of manually processing various file types? Look no further! Introducing ChatGPT File Uploader Extended, a powerful open-source Chrome extension developed using React, TypeScript, and Vite. This extension revolutionizes the way you handle files by providing a chatbot-like conversation system for seamless file upload and processing. Whether you're dealing with text files, code snippets, documents, or spreadsheets, ChatGPT File Uploader Extended has got you covered.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try the &lt;a href="https://chrome.google.com/webstore/detail/chatgpt-file-uploader-ext/becfinhbfclcgokjlobojlnldbfillpf?hl=en-GB"&gt;Extension&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;p&gt;ChatGPT File Uploader Extended offers the following features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Upload and Process Different File Types:&lt;/strong&gt; With support for various file formats including TXT, JS, PY, HTML, CSS, JSON, CSV, MD, TS, TSX, JSX, PDF, DOC, DOCX, XLS, and XLSX, you can easily upload and process files of different types using this extension.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Automatic Text Extraction:&lt;/strong&gt; Say goodbye to manual extraction! The extension automatically extracts the text content from PDF, Word, and Excel files, saving you valuable time and effort.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Chunked Processing:&lt;/strong&gt; To overcome the limitations of chatbots, ChatGPT File Uploader Extended implements chunked processing for large files. This ensures smooth processing by dividing the file into manageable chunks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Configurable Chunk Size:&lt;/strong&gt; You have control! The extension allows you to configure the chunk size according to your needs. Adjust the chunk size to optimize the conversation flow and achieve the desired processing speed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Configurable Prompts:&lt;/strong&gt; You have more control! The extension allows you also to configure each prompt while it is sending the parts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simulated Conversation Prompts:&lt;/strong&gt; Enhance the user experience! ChatGPT File Uploader Extended generates conversation prompts based on the file context, simulating a natural chat-like interaction.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;User-Friendly Interface:&lt;/strong&gt; The extension provides a user-friendly interface for selecting files and monitoring the upload progress. You can easily track the status of your uploads and stay in control.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Supported on Google Chrome:&lt;/strong&gt; ChatGPT File Uploader Extended is a browser extension designed specifically for Google Chrome, ensuring seamless integration with your browsing experience.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Follow these simple steps to install the ChatGPT File Uploader Extended Chrome extension:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clone the repository:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   git clone https://github.com/ariburaco/chatgpt-file-uploader
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Navigate to the project directory:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   cd chatgpt-file-uploader
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Install dependencies:
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Start the development environment:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   pnpm run build:watch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: You might need the execute &lt;code&gt;run pnpm run dev&lt;/code&gt; for the first time to generate some js files.&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Open Google Chrome and go to &lt;code&gt;chrome://extensions&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enable the "Developer mode" toggle.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on the "Load unpacked" button.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select the &lt;code&gt;dist&lt;/code&gt; directory from the project folder.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Congratulations! The File Uploader extension should now be installed and visible in your extensions list.&lt;/p&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;Once you have installed the File Uploader extension, you can easily upload and process files using the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Navigate to &lt;a href="https://chat.openai.com"&gt;chat.openai.com&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You will see the &lt;code&gt;Upload File&lt;/code&gt; button below the message box.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on the &lt;code&gt;Upload File&lt;/code&gt; button.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The File Uploader interface will open in a new tab.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Specify the desired chunk size (number of characters per chunk) to control the conversation flow.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The selected file will be divided into chunks and sent to the chatbot-like conversation system for processing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The conversation prompts generated based on the file context will be displayed in the chat.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Wait for each chunk to be processed before proceeding to the next one.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once a chunk is processed, the interface will be cleared, and you can upload another file if needed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;If you want to stop sending the file as a chunk, you need to refresh the page.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Screenshots
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--odFSZJqh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kzfhtkjarrcmzcrmtkgt.supabase.co/storage/v1/object/public/postimages/6f7e98c0-0283-4fe9-a488-64405915a003_unnamed.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--odFSZJqh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kzfhtkjarrcmzcrmtkgt.supabase.co/storage/v1/object/public/postimages/6f7e98c0-0283-4fe9-a488-64405915a003_unnamed.jpg" alt="https://kzfhtkjarrcmzcrmtkgt.supabase.co/storage/v1/object/public/postimages/6f7e98c0-0283-4fe9-a488-64405915a003_unnamed.jpg" width="640" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--84FQPv_7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kzfhtkjarrcmzcrmtkgt.supabase.co/storage/v1/object/public/postimages/fc014d5b-88e3-44cb-bbbb-72ca59e64fb9_3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--84FQPv_7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kzfhtkjarrcmzcrmtkgt.supabase.co/storage/v1/object/public/postimages/fc014d5b-88e3-44cb-bbbb-72ca59e64fb9_3.jpg" alt="https://kzfhtkjarrcmzcrmtkgt.supabase.co/storage/v1/object/public/postimages/fc014d5b-88e3-44cb-bbbb-72ca59e64fb9_3.jpg" width="640" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--l-XCIc1P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kzfhtkjarrcmzcrmtkgt.supabase.co/storage/v1/object/public/postimages/a5f356d8-cc92-41f8-9b41-12c42319310d_asda.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--l-XCIc1P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://kzfhtkjarrcmzcrmtkgt.supabase.co/storage/v1/object/public/postimages/a5f356d8-cc92-41f8-9b41-12c42319310d_asda.png" alt="https://kzfhtkjarrcmzcrmtkgt.supabase.co/storage/v1/object/public/postimages/a5f356d8-cc92-41f8-9b41-12c42319310d_asda.png" width="800" height="593"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;The File Uploader extension provides a configuration option for the chunk size. By default, the chunk size is set to 500 characters. If you want to change the chunk size, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Locate the "Chunk Size" input field.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enter the desired chunk size value. A range of 10,000 to 15,000 characters is recommended for optimal performance.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Supported File Types
&lt;/h2&gt;

&lt;p&gt;ChatGPT File Uploader Extended supports a wide range of file types for upload and processing, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TXT: Plain text files&lt;/li&gt;
&lt;li&gt;JS: JavaScript files&lt;/li&gt;
&lt;li&gt;PY: Python files&lt;/li&gt;
&lt;li&gt;HTML: HTML files&lt;/li&gt;
&lt;li&gt;CSS: CSS files&lt;/li&gt;
&lt;li&gt;JSON: JSON files&lt;/li&gt;
&lt;li&gt;CSV: Comma-separated values files&lt;/li&gt;
&lt;li&gt;MD: Markdown files&lt;/li&gt;
&lt;li&gt;TS: TypeScript files&lt;/li&gt;
&lt;li&gt;TSX: TypeScript JSX files&lt;/li&gt;
&lt;li&gt;JSX: JSX files&lt;/li&gt;
&lt;li&gt;PDF: PDF files&lt;/li&gt;
&lt;li&gt;DOC: Microsoft Word documents (DOC format)&lt;/li&gt;
&lt;li&gt;DOCX: Microsoft Word documents (DOCX format)&lt;/li&gt;
&lt;li&gt;XLS: Microsoft Excel spreadsheets (XLS format)&lt;/li&gt;
&lt;li&gt;XLSX: Microsoft Excel spreadsheets (XLSX format)&lt;/li&gt;
&lt;li&gt;ZIP Files&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ZIP Files
&lt;/h2&gt;

&lt;p&gt;You can select a ZIP file that contains multiple text-based files. If the files are like images, or png that cannot be directly read as text, we have introduced a feature to skip those files. basically, we can ignore some kind of extensions or we can specify the names of the files directly in the extension settings as below:&lt;/p&gt;

&lt;h2&gt;
  
  
  About the Boilerplate
&lt;/h2&gt;

&lt;p&gt;ChatGPT File Uploader Extended is built upon the &lt;a href="https://github.com/Jonghakseo/chrome-extension-boilerplate-react-vite"&gt;chrome-extension-boilerplate-react-vite&lt;/a&gt; boilerplate, which provides a solid foundation for developing Chrome extensions using React and TypeScript.&lt;/p&gt;

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

&lt;p&gt;ChatGPT File Uploader Extended simplifies the process of uploading and processing files by leveraging the power of React, TypeScript, and Vite. Say goodbye to manual file handling and embrace a more efficient and interactive approach. Give the extension a try and experience the convenience it brings to your file-processing workflows.&lt;/p&gt;




&lt;p&gt;If you have any questions or need further assistance, please don't hesitate to reach out to us. Happy file processing with ChatGPT File Uploader Extended! &lt;/p&gt;

&lt;p&gt;Please if you have any suggestions, please let me know, and I'll try to implement them. Also, feel free to contact me to contribute the &lt;a href="https://github.com/ariburaco/chatgpt-file-uploader-extended"&gt;project&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The Project inspired by this youtube video: &lt;a href="https://www.youtube.com/watch?v=iR99LO28nzM&amp;amp;t=2s"&gt;https://www.youtube.com/watch?v=iR99LO28nzM&amp;amp;t=2s&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Last but not least, of course this post is prepared with the help of ChatGPT :) &lt;/p&gt;

</description>
      <category>chatgpt</category>
      <category>chrome</category>
      <category>extension</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Optimizing Next.js App Performance for Speed and SEO</title>
      <dc:creator>ariburaco</dc:creator>
      <pubDate>Sat, 28 Jan 2023 21:33:10 +0000</pubDate>
      <link>https://dev.to/ariburaco/optimizing-nextjs-app-performance-for-speed-and-seo-j3b</link>
      <guid>https://dev.to/ariburaco/optimizing-nextjs-app-performance-for-speed-and-seo-j3b</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Welcome to our article on optimizing your Next.js app's performance through the use of getServerSideProps and getStaticProps. As a big NextJS fan, I want to show how can we get the best results using NextJS's power.&lt;/p&gt;

&lt;p&gt;In this article, we will delve into the details of these two methods and show you how to use them effectively to fetch data in the most efficient way possible. Whether you're a seasoned Next.js developer or just getting started, this article will provide you with the knowledge you need to take your app's performance to the next level. So, let's get started and see how we can use these powerful tools to improve the speed and functionality of your Next.js app.&lt;/p&gt;

&lt;h2&gt;
  
  
  The importance of optimizing the Next.js app's performance
&lt;/h2&gt;

&lt;p&gt;When it comes to building web applications, performance is key. Nobody wants to use a slow and clunky app, and in today's fast-paced world, people expect websites to load quickly and smoothly. This is especially true when it comes to Next.js, a popular framework for building React apps. With Next.js, you can build powerful and efficient web apps, but it's important to take the time to optimize your app's performance to ensure that it runs at its best.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the meaning of Optimization
&lt;/h2&gt;

&lt;p&gt;Optimizing your Next.js app's performance can mean the difference between a successful app and one that falls short. It can also mean the difference between a good user experience and a frustrating one. And let's not forget about SEO, search engines like Google will also reward the fast and optimized websites with better ranking which will bring more traffic to your website.&lt;br&gt;
If you're working with Next.js, you might have heard of this fancy feature called incremental static regeneration. Basically, it's a way for Next.js to optimize the performance of your web app by only regenerating the parts that have changed, instead of the whole thing every time. Sounds pretty cool, right?&lt;/p&gt;

&lt;p&gt;Let's break down getServerSideProps and getStaticProps, and how they can help you optimize your Next.js app's performance.&lt;/p&gt;
&lt;h2&gt;
  
  
  Understanding getServerSideProps
&lt;/h2&gt;

&lt;p&gt;getServerSideProps is a method that lets you fetch data on the server-side during the initial request. This is perfect for situations where the data being fetched is specific to the user, or when the data is dynamic and changes often.&lt;/p&gt;

&lt;p&gt;Here's a simple example of how you might use getServerSideProps to fetch a user's profile information:&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getServerSideProps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Fetch user's profile information&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&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="s2"&gt;`https://my-api.com/users/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Pass user data to the page component&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Understanding getStaticProps
&lt;/h2&gt;

&lt;p&gt;On the other hand, getStaticProps is a method that lets you fetch data at build time, and the data is then stored as a JSON file. This is perfect for situations where the data being fetched is static, and doesn't change often.&lt;/p&gt;

&lt;p&gt;Here's an example of how you might use getStaticProps to fetch a list of blog posts:&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getStaticProps&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;slug&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;string&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;blogPosts&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;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getEntries&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fields.slug[in]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;slug&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;blogPost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;blogPosts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&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;fields&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;IBlogPostFields&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;blogPost&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;To be able to use getStaticProbs, we need to specify all the paths of pages that we want to create statically. So, with getStaticPaths function we are defining all the paths.&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getStaticPaths&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;allPosts&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;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getEntries&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;paths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;allPosts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&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;post&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="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blocking&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The differences between getServerSideProps and getStaticProps
&lt;/h2&gt;

&lt;p&gt;So, the main difference between getServerSideProps and getStaticProps is that the former is executed on the server-side during the initial request and the latter is executed during the build time.&lt;/p&gt;

&lt;p&gt;It's important to keep in mind that, getStaticProps is only called at build time, whereas getServerSideProps is called on each request, so it's better to use it for dynamic data, and use getStaticProps for static data, this way you can get the best performance out of your Next.js app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Improving the getStaticProps with On Deman Revalidation
&lt;/h2&gt;

&lt;p&gt;One way you can take advantage of this is by using on-demand revalidation. It's a fancy way of saying that you can selectively revalidate certain parts of your app, without having to regenerate the whole thing. You can do this using the getStaticProps and getServerSideProps methods, which let you specify which data needs to be revalidated.&lt;/p&gt;

&lt;p&gt;So, we said that static pages are only generated when the build time. But what if we want to serve these pages dynamically and frequently? NextJS &lt;/p&gt;

&lt;p&gt;There is a great feature for revalidating static page content using the NextJS API directory. Here is the official example from NextJS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// pages/api/revalidate.js&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;handler&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;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Check for secret to confirm this is a valid request&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;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secret&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;MY_SECRET_TOKEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;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;401&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;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid token&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;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// this should be the actual path not a rewritten path&lt;/span&gt;
    &lt;span class="c1"&gt;// e.g. for "/blog/[slug]" this should be "/blog/post-1"&lt;/span&gt;
    &lt;span class="k"&gt;await&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;revalidate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/path-to-revalidate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&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;revalidated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// If there was an error, Next.js will continue&lt;/span&gt;
    &lt;span class="c1"&gt;// to show the last successfully generated page&lt;/span&gt;
    &lt;span class="k"&gt;return&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;send&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 revalidating&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I found the best way of revalidating the posts for Contentful Headless CMS is creating a webhook while creating, publishing, and updating. With this way, we can trigger the revalidating functionality in the background.&lt;/p&gt;

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

&lt;p&gt;Optimizing the performance of your Next.js app is crucial for building a successful and efficient web application. By using features like getServerSideProps and getStaticProps, you can improve the speed and performance of your app, and make sure that it's running at its best. Remember that performance is not only important for user experience but also for SEO, faster website means better ranking and more traffic. By following the best practices outlined in this article, you can take your Next.js app to the next level and ensure that it's running at its peak performance.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: This article prepared with help of ChatGPT&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props"&gt;getServerSideProps&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nextjs.org/docs/basic-features/data-fetching/get-static-props"&gt;getStaticProps&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nextjs.org/docs/basic-features/data-fetching/get-static-paths"&gt;getStaticPaths&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nextjs.org/docs/basic-features/data-fetching/incremental-static-regeneration#using-on-demand-revalidation"&gt;Incremental Data Fetching&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>optimization</category>
      <category>dynamicfetch</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Removing sensitive data from Git history</title>
      <dc:creator>ariburaco</dc:creator>
      <pubDate>Tue, 24 Jan 2023 16:48:30 +0000</pubDate>
      <link>https://dev.to/ariburaco/removing-sensitive-data-from-git-history-13ni</link>
      <guid>https://dev.to/ariburaco/removing-sensitive-data-from-git-history-13ni</guid>
      <description>&lt;p&gt;Hello folks, this will be a quick but really handy post. Let's say we are working on a side project that we didn't care the sensitive data like credentials of API keys and we want to make the repo public on Github.&lt;/p&gt;

&lt;p&gt;I've found a great tool to clear all the commit history of the specific file, in my case it was &lt;code&gt;.env.example&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;The tool is called &lt;a href="https://github.com/newren/git-filter-repo/" rel="noopener noreferrer"&gt;git-filter-repo&lt;/a&gt; and it is developed with python. &lt;/p&gt;

&lt;p&gt;So, to use the library, first we need to install the python script using:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pip install git-filter-repo&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and then we are running this code to delete all the history of the selected file:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git filter-branch --force --index-filter "git rm --cached --ignore-unmatch &amp;lt;the path of file that you want delete&amp;gt;" --prune-empty --tag-name-filter cat -- --all&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;When you run the code, you will see the remote branch and local are different. Now, you just need to push your local changes with this command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git push origin --force --all&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That's it! Now, when you check the Github, you wont't see any history about that file. &lt;/p&gt;

&lt;p&gt;Hope this will help someone having the same issue.&lt;/p&gt;

&lt;p&gt;`&lt;/p&gt;

</description>
      <category>learning</category>
      <category>fullstack</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Sending Emails with Ease: A Step-by-Step Guide to Using Nodemailer with TypeScript in Next.js</title>
      <dc:creator>ariburaco</dc:creator>
      <pubDate>Sun, 22 Jan 2023 11:00:23 +0000</pubDate>
      <link>https://dev.to/ariburaco/sending-emails-with-ease-a-step-by-step-guide-to-using-nodemailer-with-typescript-in-nextjs-528e</link>
      <guid>https://dev.to/ariburaco/sending-emails-with-ease-a-step-by-step-guide-to-using-nodemailer-with-typescript-in-nextjs-528e</guid>
      <description>&lt;h2&gt;
  
  
  About Nodemailer
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/nodemailer" rel="noopener noreferrer"&gt;Nodemailer&lt;/a&gt; is a popular library for sending emails in Node.js. It allows you to send emails using various transport methods, such as SMTP, AWS SES, and more. In this post, we will be using Nodemailer with TypeScript to send emails from a Next.js application.&lt;/p&gt;

&lt;p&gt;Before diving into the code example, let's go over some key concepts of Nodemailer. Nodemailer is a module for Node.js applications to send emails. It supports various transport methods such as SMTP, AWS SES, and more. With Nodemailer, you can send plaintext or HTML emails, attachments, and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Cases for Nodemailer
&lt;/h2&gt;

&lt;p&gt;Nodemailer is a versatile library that can be used in a variety of different use cases. Some common use cases include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Sending confirmation emails: When a user signs up for a service or makes a purchase, a confirmation email can be sent to their email address to confirm the action.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sending password reset emails: When a user forgets their password, a password reset link can be sent to their email address to allow them to reset their password.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sending notifications: Applications can send notifications to users via email, such as updates on their account or new features that have been added.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sending marketing emails: Applications can send marketing emails to users, such as newsletters or promotional offers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sending bulk emails: Applications can send bulk emails to a large number of users at once, such as in the case of a mass mailing campaign.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sending automated emails: Applications can send automated emails in response to certain events or actions, such as when a user's account is about to expire.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Send HTML email Templates: Applications can use Nodemailer to send HTML email Templates, which can be designed and customized to match the look and feel of the application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sending emails with attachments: Applications can use Nodemailer to send emails with attachments, such as invoices, receipts, or other files.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are just a few examples of the many use cases for Nodemailer, it is a very flexible library that can be used in many different ways to meet the needs of your application.&lt;/p&gt;

&lt;p&gt;In this post, we'll be using the SMTP transport method to send emails using a Gmail account. We will be using TypeScript to write our code, which adds type safety and improved code organization to our application.&lt;/p&gt;

&lt;p&gt;Now that we understand the basics of Nodemailer and TypeScript, let's take a look at the code example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation of Emailer Class
&lt;/h2&gt;

&lt;p&gt;The code below shows an implementation of the Nodemailer library in TypeScript. The Emailer class is used to send emails using a Gmail account. It uses the &lt;code&gt;nodemailer.createTransport()&lt;/code&gt; method to create a transporter object, which is used to send emails.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;nodemailer&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nodemailer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MailOptions&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nodemailer/lib/json-transport&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Emailer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;transporter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;nodemailer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Transporter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transporter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nodemailer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTransport&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gmail&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&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;GMAIL_USER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;pass&lt;/span&gt;&lt;span class="p"&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;GMAIL_PASSWORD&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="kr"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;sendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mailOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MailOptions&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transporter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendMail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mailOptions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kr"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;notifyAdminForNewUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;notifyAdminNewUserEmailTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kr"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;notifyUserForSignup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;newUserEmailTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;emailer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Emailer&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;newUserEmailTemplate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&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;GMAIL_USER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;subject&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;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, Welcome to the our website`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Welcome to the our website&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
      &amp;lt;h1&amp;gt;Welcome to our website!&amp;lt;/h1&amp;gt;
      &amp;lt;p&amp;gt;We're glad you've decided to join us. We hope you find everything you're looking for here and enjoy using our site.&amp;lt;/p&amp;gt;
      &amp;lt;p&amp;gt;If you have any questions or need any help, please don't hesitate to contact us. Thank you for signing up!&amp;lt;/p&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;as&lt;/span&gt; &lt;span class="nx"&gt;MailOptions&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;notifyAdminNewUserEmailTemplate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&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;GMAIL_USER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&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;GMAIL_USER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`New User: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; - email: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;email&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="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`New User: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; - email: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;email&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="na"&gt;html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
      &amp;lt;h1&amp;gt;New User: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/h1&amp;gt;
      &amp;lt;p&amp;gt;email: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/p&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;as&lt;/span&gt; &lt;span class="nx"&gt;MailOptions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The class has two methods, &lt;code&gt;notifyAdminForNewUser&lt;/code&gt; and &lt;code&gt;notifyUserForSignup&lt;/code&gt;, which use the &lt;code&gt;sendEmail&lt;/code&gt; method to send emails to the new user and the admin, respectively. The &lt;code&gt;sendEmail&lt;/code&gt; method takes in a mailOptions object, which contains the recipient's email, subject, and the message.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;newUserEmailTemplate&lt;/code&gt; and &lt;code&gt;notifyAdminNewUserEmailTemplate&lt;/code&gt; functions are used to create the &lt;code&gt;mailOptions&lt;/code&gt; object for the new user and admin emails, respectively. They take in the user's email and username as arguments and return an object with the recipient's email, subject, and message.&lt;/p&gt;

&lt;p&gt;It's worth noting that the code is using &lt;code&gt;process.env.GMAIL_USER&lt;/code&gt; and &lt;code&gt;process.env.GMAIL_PASSWORD&lt;/code&gt; to authenticate with &lt;code&gt;gmail&lt;/code&gt;, You should replace it with your own Gmail user and password.&lt;/p&gt;

&lt;p&gt;To obtain the Gmail password, you should go to the settings on Gmail and create an App Password, please remember that you need to activate the 2FA for your google account.&lt;/p&gt;

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

&lt;p&gt;Nodemailer with TypeScript makes it easy to send emails from a Next.js application. With the help of the &lt;code&gt;Emailer&lt;/code&gt; class and the &lt;code&gt;mailOptions&lt;/code&gt; object, you can send emails with ease. Of course, this implementation will only work on the server side of the NextJS Application. If you want to send email from client side, you just need to create an API endpoint under the &lt;code&gt;/pages/api&lt;/code&gt;directory. &lt;/p&gt;

&lt;p&gt;In this post, we've shown how to send emails using a Gmail account, but you can also use other transport methods such as AWS SES to send emails. You can expand the class methods to meet your needs.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: The post prepared by the help of ChatGPT, but all code part is written by my.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thank you for reading my post! If you enjoyed it and found it informative, I would greatly appreciate it. If you're interested in more content like this, be sure to check out &lt;a href="https://www.mystickynotes.net" rel="noopener noreferrer"&gt;my blog&lt;/a&gt; for more articles on similar topics.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>alibabachallenge</category>
      <category>productivity</category>
      <category>uiux</category>
    </item>
    <item>
      <title>Animate everything with Framer Motion</title>
      <dc:creator>ariburaco</dc:creator>
      <pubDate>Sat, 21 Jan 2023 22:03:53 +0000</pubDate>
      <link>https://dev.to/ariburaco/animate-everything-with-framer-motion-mpd</link>
      <guid>https://dev.to/ariburaco/animate-everything-with-framer-motion-mpd</guid>
      <description>&lt;h2&gt;
  
  
  What is Framer Motion
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.framer.com/motion/" rel="noopener noreferrer"&gt;Framer Motion&lt;/a&gt; is a powerful animation library for React. It provides a set of easy-to-use components that allow developers to add animations to their React applications with minimal code.&lt;/p&gt;

&lt;p&gt;One of the key features of Framer Motion is its use of the Physics engine, which allows for realistic and natural-feeling animations. This means that animations in Framer Motion respond to the user's interactions in a way that feels more intuitive and less robotic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use cases of Framer Motion
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Page Transitions: Framer Motion can be used to create smooth page transitions, allowing you to create a seamless user experience as users navigate through your application. For example, you can use the AnimatePresence component to fade out the current page while fading in the new page, creating a smooth transition between pages.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Image Carousels: You can use Framer Motion's animation capabilities to create dynamic and engaging image carousels. For example, you can use the motion.div component to create a slide transition between images, and use the useAnimation hook to control the timing and easing of the animation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Animated Buttons: Framer Motion can also be used to add animations to buttons, making them more engaging and interactive. For example, you can use the motion.button component to create an animated button that changes color or size when hovered over, creating a more dynamic and engaging user experience.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scroll-Triggered Animations: Framer Motion's useViewportScroll hook can be used to create animations that are triggered when the user scrolls to a certain point on the page. For example, you can use this hook to create a floating effect for an element as the user scrolls down the page.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Drag and Drop Interactions: Framer Motion's drag and dragControls components can be used to create drag and drop interactions in your application. For example, you can use these components to create a to-do list where users can drag and drop items to reorder them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Parallax Scrolling: Framer Motion's useTransform hook can be used to create a parallax scrolling effect, where elements on the page move at different speeds as the user scrolls. This can be used to create a more immersive and dynamic user experience.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Another great feature of Framer Motion is its use of the Animation controls, which allow developers to easily control the timing, duration, and easing of animations. This makes it easy to create complex animations with minimal code and allows for fine-tuning of the animation to achieve the desired effect.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Simple Opacity Animation Component
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AnimatePresence&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;motion&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;framer-motion&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;AnimateOpacityProps&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;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AnimateOpacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;AnimateOpacityProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AnimatePresence&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wait&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;
      &lt;span class="nx"&gt;initial&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;opacity&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;animate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
      &lt;span class="nx"&gt;exit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;opacity&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="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/motion.div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/AnimatePresence&lt;/span&gt;&lt;span class="err"&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;AnimateOpacity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;In addition to its powerful animation capabilities, Framer Motion also provides a set of layout and gesture components that make it easy to add advanced interactions to your React applications. For example, the layout component allows you to easily create responsive and flexible layouts, while the gesture component provides a set of easy-to-use gestures such as swipe, tap, and press.&lt;/p&gt;

&lt;p&gt;Overall, Framer Motion is an excellent choice for developers looking to add animations and advanced interactions to their React applications. Its powerful animation capabilities, intuitive API, and easy-to-use components make it a great choice for both beginners and experienced developers alike.&lt;/p&gt;

&lt;p&gt;If you're looking to add animations to your React projects, Framer Motion is definitely worth checking out. It's easy to use, powerful, and provides a great set of features that make it a great choice for any React developer.&lt;/p&gt;

&lt;p&gt;Note: the post is created by the help of ChatGPT. But the React component itself created by me.&lt;/p&gt;

</description>
      <category>gratitude</category>
    </item>
    <item>
      <title>Authentication with Firebase in NextJS, with SSR!</title>
      <dc:creator>ariburaco</dc:creator>
      <pubDate>Fri, 20 Jan 2023 11:40:06 +0000</pubDate>
      <link>https://dev.to/ariburaco/authentication-with-firebase-in-nextjs-with-ssr-e76</link>
      <guid>https://dev.to/ariburaco/authentication-with-firebase-in-nextjs-with-ssr-e76</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this post, we will learn how to set up user authentication in a Next.js application using Firebase. Firebase is a popular backend-as-a-service provider that offers a variety of tools for building web and mobile applications, including user authentication. By the end of this tutorial, you will have a basic understanding of how to use Firebase to authenticate users in your Next.js application, allowing them to sign in, sign up, and sign out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;The first step will create a project under &lt;a href="https://console.firebase.google.com" rel="noopener noreferrer"&gt;firebase console&lt;/a&gt;, once you create a web project, firebase will provide you a code snippet to use on the client side.&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="c1"&gt;// Import the functions you need from the SDKs you need&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;initializeApp&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;firebase/app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getAuth&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;firebase/auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getFirestore&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;firebase/firestore&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// TODO: Add SDKs for Firebase products that you want to use&lt;/span&gt;
&lt;span class="c1"&gt;// https://firebase.google.com/docs/web/setup#available-libraries&lt;/span&gt;

&lt;span class="c1"&gt;// Your web app's Firebase configuration&lt;/span&gt;
&lt;span class="c1"&gt;// For Firebase JS SDK v7.20.0 and later, measurementId is optional&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firebaseConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="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;NEXT_PUBLIC_FIREBASE_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="na"&gt;authDomain&lt;/span&gt;&lt;span class="p"&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;NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="na"&gt;projectId&lt;/span&gt;&lt;span class="p"&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;NEXT_PUBLIC_FIREBASE_PROJECT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="na"&gt;storageBucket&lt;/span&gt;&lt;span class="p"&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;NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="na"&gt;messagingSenderId&lt;/span&gt;&lt;span class="p"&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;NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="p"&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;NEXT_PUBLIC_FIREBASE_APP_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="na"&gt;measurementId&lt;/span&gt;&lt;span class="p"&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;NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


&lt;span class="c1"&gt;// Initialize Firebase&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;firebaseConfig&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;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getFirestore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&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;auth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getAuth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Client Side Authentication
&lt;/h2&gt;

&lt;p&gt;Once you initialize the firebase app, you are good to go!&lt;/p&gt;

&lt;p&gt;Firebase has a lot of providers for authentication, like social logins with Google, Github, Apple, Facebook and etc. Also, you can choose a simple email and password login. In this example, I’ll create the users manually, since only admin users will be able to log in.&lt;/p&gt;

&lt;p&gt;After selecting the provider and creating the users, we can start building our sign-in logic.&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;auth&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;configs/firebase-config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;onIdTokenChanged&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;User&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;firebase/auth&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;admin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setAdmin&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;User&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

 &lt;span class="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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;unsubscribe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;onIdTokenChanged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&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;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nf"&gt;setAdmin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nf"&gt;setAdmin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;

   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;unsubscribe&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;So, we will use this useEffect hook on the login page, if someone logs in, it automatically assigns the user to our state. And this is the actual login function:&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;signInWithEmailAndPassword&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;firebase/auth&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;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setEmail&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="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;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPassword&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="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;signInwithFirebase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;signInWithEmailAndPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&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="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FirebaseError&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;FirebaseError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code&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;That’s it! Now you are authenticated with Firebase Auth. After this point, you can create a Context Provider to store the Auth User in the whole application.&lt;/p&gt;

&lt;p&gt;There is one caveat in this approach and that is SSR. Since we are checking the authentication on the client side, when we first load the page, we might get some flickery behaviors. But wait, there is a solution for this also! &lt;/p&gt;

&lt;h2&gt;
  
  
  Server Side Authentication - Power of the “getServerSideProps”
&lt;/h2&gt;

&lt;p&gt;So, the basic idea is that we need to validate the authenticated user on the backend server before loading the page. Able to do this, we need another library called firebase-admin, with this library we are able to do a lot of things such as creating users, databases, and validations.&lt;/p&gt;

&lt;p&gt;Here is the basic configuration of the firebase-admin app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;admin&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;firebase-admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/* eslint-disable import/prefer-default-export */&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;credential&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;firebase-admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;initializeApp&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;firebase-admin/app&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;serviceAccount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ServiceAccountFile.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;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;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apps&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="nf"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
   &lt;span class="na"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;serviceAccount&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
 &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;adminSDK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Once we configured the adminSDK, we can use it on our application. &lt;/p&gt;

&lt;p&gt;So, the logic of the server side auth verification is that we need to validate the users token on the backend. So, once we are logged in as a user, firebase gives us a unique user token. Somehow we need to pass this token value to our backend and the best way to do this cookies! &lt;/p&gt;

&lt;p&gt;Here is the implementation of the server side validation of the authenticated user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;nookies&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;nookies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;adminSDK&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;configs/firebase-admin-config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getServerSideProps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GetServerSidePropsContext&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;cookies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nookies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&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="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="na"&gt;isLoggedIn&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="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;token&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;adminSDK&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;verifyIdToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;token&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="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;isLoggedIn&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="p"&gt;}&lt;/span&gt;

   &lt;span class="c1"&gt;// the user is authenticated!&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;uid&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;token&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;user&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;adminSDK&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="na"&gt;isLoggedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="p"&gt;};&lt;/span&gt;
 &lt;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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="na"&gt;isLoggedIn&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;And of course, once we logged on the client side we need to store the user token in the cookies. So, the client side implementation will be change a little bit.&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="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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;unsubscribe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;onIdTokenChanged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&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;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nf"&gt;setAdmin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&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;token&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;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getIdToken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
       &lt;span class="nx"&gt;nookies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nf"&gt;setAdmin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="nx"&gt;nookies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;token&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;

   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;unsubscribe&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

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

&lt;/div&gt;



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

&lt;p&gt;That’s it! Now, you have both client and server-side authentication. Using this approach you can create excellent web applications.&lt;br&gt;
We have learned how to set up user authentication in a Next.js application using Firebase. We have seen how Firebase makes it easy to handle user registration and login, and how to use Firebase's authentication API to authenticate users in our application. We also saw how to use Firebase's Firestore to store user data and how to protect routes based on the authenticated user. With this knowledge, you should now be able to add user authentication to your Next.js applications easily and securely. Happy hacking!&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
