<?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: Hugo Ramon Pereira</title>
    <description>The latest articles on Forem by Hugo Ramon Pereira (@hramonpereira).</description>
    <link>https://forem.com/hramonpereira</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%2F566606%2F324226ff-be83-48c4-b97a-18506cfa2005.jpg</url>
      <title>Forem: Hugo Ramon Pereira</title>
      <link>https://forem.com/hramonpereira</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/hramonpereira"/>
    <language>en</language>
    <item>
      <title>How to Manage User Authentication in React.js, Next.js, Vue.js, and Nuxt.js Using Clerk</title>
      <dc:creator>Hugo Ramon Pereira</dc:creator>
      <pubDate>Tue, 01 Oct 2024 00:21:14 +0000</pubDate>
      <link>https://forem.com/hramonpereira/how-to-manage-user-authentication-in-reactjs-nextjs-vuejs-and-nuxtjs-using-clerk-136l</link>
      <guid>https://forem.com/hramonpereira/how-to-manage-user-authentication-in-reactjs-nextjs-vuejs-and-nuxtjs-using-clerk-136l</guid>
      <description>&lt;p&gt;&lt;strong&gt;INTRODUCTION&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Authentication is a very important component to any software, application, system, it provides an extra layer of security by restricting areas of your application. For example a dashboard with important information, it can not be accessed unless the user is authenticated. Of course we can implement user, email and password for the user to create and then the user receives an email to validate the email and only then the user can access the content which is allowed for the ones authenticated, this flow is still very popular in use, but it has additional steps that many users are somewhat bored to take, since authentication with a provider be it Google, Microsoft, Apple or others is much simpler, with just a few clicks you can get authenticated and you don't even have to leave the current screen you are in. This ease of access should definitely be considered when building your applications so that the user can choose which one he wants.&lt;/p&gt;

&lt;p&gt;In this article we will use Clerk with React.js and Next.js, unfortunately Clerk is not fully supported for Vue.js or Nuxt.js applications yet, in the Clerk's official docs we can find mentions for Vue.js but to use it via SDK.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CLERK WITH REACT.JS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The first step is to log into Clerk's website and choose the providers you want to be available in your application. You can choose up to 3 providers in the free-tier, if you wish to have more providers then you will need to upgrade your account.&lt;/p&gt;

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

&lt;p&gt;The second step to add it to a React.js application is quite simple. First we need to install the clerk package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @clerk/clerk-react
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we need to set up our environment variables, first check if you already have a env.local file to add the key there, in case you don't have this file you can go ahead and create it to add the clerk publishable key, as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VITE_CLERK_PUBLISHABLE_KEY=pk_test_************************
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next step is to import the publishable key, we can do this by going to the main.ts file and import it there, you can also add a if check to avoid Typescript errors.&lt;br&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 ReactDOM from 'react-dom/client'
import App from './App.tsx'
import './index.css'

// Import your publishable key
const PUBLISHABLE_KEY = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY

if (!PUBLISHABLE_KEY) {
  throw new Error('Missing Publishable Key')
}

ReactDOM.createRoot(document.getElementById('root')!).render(
  &amp;lt;React.StrictMode&amp;gt;
    &amp;lt;App /&amp;gt;
  &amp;lt;/React.StrictMode&amp;gt;,
)

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

&lt;/div&gt;



&lt;p&gt;Now we have to add the  to our application also in the main.ts file but now we have to wrap the whole app with the  as shown below and attach the publishableKey to it:&lt;br&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 ReactDOM from 'react-dom/client'
import App from './App.tsx'
import './index.css'
import { ClerkProvider } from '@clerk/clerk-react'

// Import your publishable key
const PUBLISHABLE_KEY = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY

if (!PUBLISHABLE_KEY) {
  throw new Error('Missing Publishable Key')
}

ReactDOM.createRoot(document.getElementById('root')!).render(
  &amp;lt;React.StrictMode&amp;gt;
    &amp;lt;ClerkProvider publishableKey={PUBLISHABLE_KEY} afterSignOutUrl="/"&amp;gt;
      &amp;lt;App /&amp;gt;
    &amp;lt;/ClerkProvider&amp;gt;
  &amp;lt;/React.StrictMode&amp;gt;,
)

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

&lt;/div&gt;



&lt;p&gt;Now the final step is to add the Clerk Components in the header component to handle the authentication steps such as sign in, sign out, the button with the Authenticators we choose during the process like Google, Microsoft, Github, Apple and many others available. You can organize your Header component the way you want just import the components from Clerk and it should work.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { SignedIn, SignedOut, SignInButton, UserButton } from '@clerk/clerk-react'

export function Header() {
  return (
    &amp;lt;header&amp;gt;
      &amp;lt;SignedOut&amp;gt;
        &amp;lt;SignInButton /&amp;gt;
      &amp;lt;/SignedOut&amp;gt;
      &amp;lt;SignedIn&amp;gt;
        &amp;lt;UserButton /&amp;gt;
      &amp;lt;/SignedIn&amp;gt;
    &amp;lt;/header&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And don't forget to add the package React-Router-Dom to navigate to whatever the page is after the user is authenticated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CLERK WITH NEXT.JS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To add Clerk to a Next.js application the steps are almost identical, just a few changes, let's see how to do that.&lt;/p&gt;

&lt;p&gt;First log into Clerk's website with your account and select the providers and proceed to add the publishable key and remember that Next.js has a different naming convention for its environment variables.&lt;/p&gt;

&lt;p&gt;And using Next.js requires 2 values to be added in the environment file, a secret key is added in Next.js a publishable key and a secret key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_************************
CLERK_SECRET_KEY=sk_test_************************
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next step is to add a middleware to intercept routes for unauthenticated users, you can create a file named middleware.ts in the root directory. Then this is the code to make it validate routes and force authentication by using the functions auth() and protect() provided by Clerk:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'

const isProtectedRoute = createRouteMatcher(['/dashboard(.*)', '/forum(.*)'])

export default clerkMiddleware((auth, req) =&amp;gt; {
  if (isProtectedRoute(req)) auth().protect()
})

export const config = {
  matcher: [
    // Skip Next.js internals and all static files, unless found in search params
    '/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
    // Always run for API routes
    '/(api|trpc)(.*)',
  ],
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now we are going to add  to our main layout.tsx file wrapping the entire application and make Clerk globally available.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { ClerkProvider, SignInButton, SignedIn, SignedOut, UserButton } from '@clerk/nextjs'
import './globals.css'
import Header from '@/components/Header';


export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    &amp;lt;ClerkProvider&amp;gt;
      &amp;lt;html lang="en"&amp;gt;
        &amp;lt;body&amp;gt;
          &amp;lt;Header /&amp;gt;
          &amp;lt;main&amp;gt;{children}&amp;lt;/main&amp;gt;
        &amp;lt;/body&amp;gt;
      &amp;lt;/html&amp;gt;
    &amp;lt;/ClerkProvider&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now we add our Header component and use Clerk components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { SignedIn, SignedOut, SignInButton, UserButton } from '@clerk/nextjs';

export function Header() {
  return (
    &amp;lt;header&amp;gt;
      &amp;lt;SignedOut&amp;gt;
        &amp;lt;SignInButton /&amp;gt;
      &amp;lt;/SignedOut&amp;gt;
      &amp;lt;SignedIn&amp;gt;
        &amp;lt;UserButton /&amp;gt;
      &amp;lt;/SignedIn&amp;gt;
    &amp;lt;/header&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;CLERK WITH VUE&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In order to add Clerk to a Vue.js application we are gonna need to use the Clerk's SDK. And the process is very simple, this is one of the benefits of using Clerk, its simplicity.&lt;/p&gt;

&lt;p&gt;Install the SDK into your project by using the command:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Add the publishable key to your project, unlike Next.js, for Vue.js and React.js there is only one key to be added to the .env.local file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VITE_CLERK_PUBLISHABLE_KEY=pk_test_************************
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then import the Clerk publishable key in the main.ts file into the src folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createApp } from 'vue'
import App from './App.vue'

const PUBLISHABLE_KEY = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY

if (!PUBLISHABLE_KEY) {
  throw new Error('Missing Publishable Key')
}

const app = createApp(App)
app.mount('#app')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add clerkPlugin from vue-clerk&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createApp } from 'vue'
import App from './App.vue'
import { clerkPlugin } from 'vue-clerk'

const PUBLISHABLE_KEY = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY

if (!PUBLISHABLE_KEY) {
  throw new Error('Missing Publishable Key')
}

const app = createApp(App)
app.use(clerkPlugin, {
  publishableKey: PUBLISHABLE_KEY
})
app.mount('#app')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now create your header component and make use of the Clerk pre-built components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script setup&amp;gt;
     import { SignedIn, SignedOut, SignInButton, UserButton } from 'vue-clerk'
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
  &amp;lt;SignedOut&amp;gt;
    &amp;lt;SignInButton /&amp;gt;
  &amp;lt;/SignedOut&amp;gt;
  &amp;lt;SignedIn&amp;gt;
    &amp;lt;UserButton /&amp;gt;
  &amp;lt;/SignedIn&amp;gt;
&amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And use vue-router to navigate to the authenticated pages when the user is done authenticating.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CLERK WITH NUXT.JS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nuxt.js applications require the use of Vue-clerk to and some additional steps in order to make Clerk work with Nuxt.js architecture. It's a different process just like with Next.js because both technologies have similar purposes.&lt;/p&gt;

&lt;p&gt;In the nuxt.config.ts we add the module vue-clerk/nuxt into the modules array and by doing so all the components and composables will be auto-imported&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['vue-clerk/nuxt'],
  clerk: {
    appearance: {},
  }
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now the environment variables are added in your environment file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NUXT_PUBLIC_CLERK_PUBLISHABLE_KEY=your_publishable_key
NUXT_CLERK_SECRET_KEY=your_secret_key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The environment variables will be loaded in the &lt;em&gt;nuxt.config.ts&lt;/em&gt; file using the runtimeConfig and beware the naming conventions they must match the NUXT_PUBLIC_YOUR_ENV and the runtimeConfig object otherwise we might run into inconsistencies between the dev and build environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default defineNuxtConfig({
  modules: ['vue-clerk/nuxt'],
  clerk: {
    appearance: {},
  }
  runtimeConfig: {
    public: {
      clerkPublishableKey: process.env.CLERK_PUBLISHABLE_KEY,
    },
  }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the next step is to use Clerk Components in for example a &lt;em&gt;Header&lt;/em&gt; component and use it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script lang="ts" setup&amp;gt;
// You don't have to import anything from  Clerk
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
  &amp;lt;div&amp;gt;
    &amp;lt;SignIn /&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also have to protect the routes that need authentication and if the user is not authorized he will be redirected to a home page or wherever we want.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// middleware/auth.ts
import { defineNuxtRouteMiddleware, navigateTo } from '#app';
import { useClerk } from '@clerk/clerk-vue';

export default defineNuxtRouteMiddleware(() =&amp;gt; {
  const clerk = useClerk();

  if (!clerk.user.value) {
    return navigateTo('/sign-in');
  }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next step is to add types to make sure Clerk works with Typescript. Since we are using SDKs for Vue.js and Nuxt.js it is not necessary to install the package @clerk/types because the SDKs include their own type definitions. You can read the file in the repository to be certain of what the exact types are.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { UserResource } from '@clerk/types';

// Example function using Clerk's user type
function getUserName(user: UserResource) {
  Return { 
user.firstName || 'Guest', 
user.emailAddresses; 
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only thing that is left is to enable typescript module for building the application to be later deployed into production.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default defineNuxtConfig({
  modules: ['vue-clerk/nuxt'],
  clerk: {
    appearance: {},
  }
  runtimeConfig: {
    public: {
      clerkPublishableKey: process.env.CLERK_PUBLISHABLE_KEY,
    },
  }
  buildModules: ['@nuxt/typescript-build'], // Enable TypeScript
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;CONCLUSION&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Authentication with Clerk is very simple and easy, now you can add it to your projects and have another option for your users to choose and this will be better for User Experience. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;REFERENCES&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://clerk.com/docs/quickstarts/react" rel="noopener noreferrer"&gt;https://clerk.com/docs/quickstarts/react&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://clerk.com/docs/quickstarts/nextjs" rel="noopener noreferrer"&gt;https://clerk.com/docs/quickstarts/nextjs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://vue-clerk.vercel.app/" rel="noopener noreferrer"&gt;https://vue-clerk.vercel.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://clerk.com/docs/references/react/use-clerk" rel="noopener noreferrer"&gt;https://clerk.com/docs/references/react/use-clerk&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/wobsoriano/nuxt-clerk-template/tree/main" rel="noopener noreferrer"&gt;https://github.com/wobsoriano/nuxt-clerk-template/tree/main&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.vue-clerk.com/guides/nuxt" rel="noopener noreferrer"&gt;https://www.vue-clerk.com/guides/nuxt&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/@clerk/types" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/@clerk/types&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/clerk/javascript/blob/e483037f61b4cfa8a04be27971f3b09eb88c84ac/packages/types/src/user.ts#L52" rel="noopener noreferrer"&gt;https://github.com/clerk/javascript/blob/e483037f61b4cfa8a04be27971f3b09eb88c84ac/packages/types/src/user.ts#L52&lt;/a&gt;&lt;/p&gt;

</description>
      <category>clerk</category>
      <category>vue</category>
      <category>react</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Protected Routes with React.js and Next.js</title>
      <dc:creator>Hugo Ramon Pereira</dc:creator>
      <pubDate>Fri, 17 Nov 2023 19:00:03 +0000</pubDate>
      <link>https://forem.com/hramonpereira/protected-routes-with-reactjs-and-nextjs-31o9</link>
      <guid>https://forem.com/hramonpereira/protected-routes-with-reactjs-and-nextjs-31o9</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In order to handle routes in &lt;strong&gt;React.js&lt;/strong&gt; we have to install a third party package named &lt;strong&gt;React-Router-Dom&lt;/strong&gt;. This package wasn't developed by the React core team but it is a trusted package in React's community.&lt;/p&gt;

&lt;p&gt;So this article aims to show ways to implement routes that can only be accessed when the user is somehow authenticated or authorized to have access to specific pages of our applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Protected Routes with React.js
&lt;/h3&gt;

&lt;p&gt;We will start with &lt;strong&gt;React.js&lt;/strong&gt; and the first thing we need to do is to install &lt;strong&gt;React-Router-Dom&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i react-router-dom
yarn add react-router-dom
pnpm add react-router-dom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will be creating a &lt;em&gt;router.ts&lt;/em&gt; file and for that we need to change the structure of our app a bit.&lt;/p&gt;

&lt;p&gt;The first step is to create the router file and for that we will create a folder called &lt;strong&gt;router&lt;/strong&gt; inside the &lt;strong&gt;src&lt;/strong&gt; directory. I am following the naming convention to name all the component files as &lt;em&gt;index.tsx&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In the &lt;strong&gt;router&lt;/strong&gt; file, first we need to create a functional component named as Router and import 3 components from the package &lt;strong&gt;React-Router-Dom&lt;/strong&gt;, &lt;strong&gt;Browser Router&lt;/strong&gt;, &lt;strong&gt;Routes&lt;/strong&gt; and &lt;strong&gt;Route&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We will create three pages and so we will have three routes as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { AuthGuard } from '../auth/AuthGuard';
import { Signin } from '../view/pages/signin';
import { Signup } from '../view/pages/signup';
import { Dashboard } from '../view/pages/dashboard';

export function Router() {
  return (
    &amp;lt;BrowserRouter&amp;gt;
      &amp;lt;Routes&amp;gt;
        &amp;lt;Route path='/signin' element={&amp;lt;Signin /&amp;gt;} /&amp;gt;
        &amp;lt;Route path='/signup' element={&amp;lt;Signup /&amp;gt;} /&amp;gt;
        &amp;lt;Route path='/' element={&amp;lt;Dashboard /&amp;gt;} /&amp;gt;
      &amp;lt;/Routes&amp;gt;  
    &amp;lt;/BrowserRouter&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The order is to have the &lt;strong&gt;BrowserRouter&lt;/strong&gt; wrapping all the &lt;strong&gt;Routes&lt;/strong&gt; and inside the &lt;strong&gt;Routes&lt;/strong&gt; we have the specific &lt;strong&gt;Route&lt;/strong&gt; file with its path and the element which is the component of the page, they are imported in the first lines of the router component.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;pages/components&lt;/em&gt; rendered as elements of each &lt;strong&gt;Route&lt;/strong&gt; are created in the &lt;strong&gt;View&lt;/strong&gt; folder and inside that we have a folder for each &lt;em&gt;page/component&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The second step is to go to the &lt;em&gt;App.tsx&lt;/em&gt; file and use our &lt;strong&gt;Router&lt;/strong&gt; component there.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Router } from './router';

export function App() {
  return (
    &amp;lt;Router /&amp;gt;
  );
}

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

&lt;/div&gt;



&lt;p&gt;And now we will create the &lt;strong&gt;AuthGuard&lt;/strong&gt; component that is going to protect the routes and allow us to access the dashboard &lt;em&gt;page/component&lt;/em&gt; only after we are signed in. As a good practice we will create a folder called auth and create the &lt;strong&gt;AuthGuard&lt;/strong&gt; component there.&lt;br&gt;
&lt;/p&gt;

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

interface AuthGuardProps {
  isPrivate: boolean;
}

export function AuthGuard({ isPrivate }: AuthGuardProps) {
  const signedIn = false;

  if (!signedIn &amp;amp;&amp;amp; isPrivate) {
    return &amp;lt;Navigate to='/signin' replace /&amp;gt;;
  }

  if (signedIn &amp;amp;&amp;amp; !isPrivate) {
    return &amp;lt;Navigate to='/' replace /&amp;gt;;
  }

  return &amp;lt;Outlet /&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;strong&gt;AuthGuard&lt;/strong&gt; component we are using two components from &lt;strong&gt;React-Router-Dom&lt;/strong&gt;. &lt;strong&gt;Outlet&lt;/strong&gt; which is placed in the parent route and it will render the &lt;em&gt;child routes&lt;/em&gt;, the &lt;strong&gt;Outlet&lt;/strong&gt; component will be very useful because we will be using &lt;em&gt;nested routes&lt;/em&gt;. And the &lt;strong&gt;Navigate&lt;/strong&gt; component is the one responsible for redirecting us to the specified route, the property called replace which will not add your current path to the history.&lt;/p&gt;

&lt;p&gt;We created a simple interface that contains only one single prop called &lt;strong&gt;isPrivate&lt;/strong&gt; and we will use this prop to control if the route requires the user to be authenticated or not.&lt;/p&gt;

&lt;p&gt;We have the logic that controls where we will be redirected whether the user is signedIn or the route is private or not and at the end of the component we return the &lt;strong&gt;Outlet&lt;/strong&gt; component.&lt;/p&gt;

&lt;p&gt;We can also create another &lt;strong&gt;AuthGuard&lt;/strong&gt; that requires a token from &lt;em&gt;localStorage&lt;/em&gt;, in case we wish to implement a different approach.&lt;br&gt;
&lt;/p&gt;

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

interface AuthGuardProps extends PropsWithChildren;

export function AuthGuard({ children }: AuthGuardProps) {
  if (localStorage.getItem('token')) {
    return children;
  }

  return &amp;lt;Navigate to'/' /&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So now we head back to the Router component and we will use the &lt;strong&gt;AuthGuard&lt;/strong&gt; to wrap our &lt;strong&gt;Routes&lt;/strong&gt; with it and establish which one is private or not. And the &lt;strong&gt;Route&lt;/strong&gt; that will be wrapped by the &lt;strong&gt;AuthGuard&lt;/strong&gt; is the one that will be rendered by the &lt;strong&gt;Outlet&lt;/strong&gt; component. Since the &lt;strong&gt;AuthGuard&lt;/strong&gt; is the parent because it is wrapping the &lt;em&gt;child route&lt;/em&gt;, thus making &lt;em&gt;nested routing&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { AuthGuard } from '../auth/AuthGuard';
import { Signin } from '../view/pages/signin';
import { Signup } from '../view/pages/signup';
import { Dashboard } from '../view/pages/dashboard';

export function Router() {
  return (
    &amp;lt;BrowserRouter&amp;gt;
      &amp;lt;Routes&amp;gt;

        {/* Public Routes */}
        &amp;lt;Route element={&amp;lt;AuthGuard isPrivate={false} /&amp;gt;}&amp;gt;
          &amp;lt;Route path='/signin' element={&amp;lt;Signin /&amp;gt;} /&amp;gt;
          &amp;lt;Route path='/signup' element={&amp;lt;Signup /&amp;gt;} /&amp;gt;
        &amp;lt;/Route&amp;gt;

        {/* Private Route - Require Authentication */}
        &amp;lt;Route element={&amp;lt;AuthGuard isPrivate /&amp;gt;}&amp;gt;
          &amp;lt;Route path='/' element={&amp;lt;Dashboard /&amp;gt;} /&amp;gt;
        &amp;lt;/Route&amp;gt;

      &amp;lt;/Routes&amp;gt;  
    &amp;lt;/BrowserRouter&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the same code as earlier, but now we have our &lt;strong&gt;AuthGuard&lt;/strong&gt; component wrapping the &lt;strong&gt;routes&lt;/strong&gt;, we are passing the boolean prop isPrivate to indicate which ones are &lt;em&gt;private&lt;/em&gt; or &lt;em&gt;public&lt;/em&gt; and in the &lt;strong&gt;AuthGuard&lt;/strong&gt; component we are returning the &lt;strong&gt;Outlet&lt;/strong&gt; component which will render the route that is being wrapped by the &lt;strong&gt;AuthGuard&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is a very simple but efficient implementation, easy to read and not that many lines of code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating Protected Routes with Next.js
&lt;/h2&gt;

&lt;p&gt;For a &lt;strong&gt;Next.js&lt;/strong&gt; application we will use a different approach since &lt;strong&gt;Next.js&lt;/strong&gt; handles the routes itself with the &lt;strong&gt;Pages Router&lt;/strong&gt; system where you can create a file named page and it will become an available route, there's no need for a third-party package like &lt;strong&gt;React-Router-Dom&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We will start in the main &lt;strong&gt;Layout&lt;/strong&gt; file, in there we will wrap the &lt;em&gt;children&lt;/em&gt; inside the body with two components: &lt;strong&gt;AuthProvider&lt;/strong&gt; and &lt;strong&gt;ProtectRoute&lt;/strong&gt;, the &lt;strong&gt;AuthProvider&lt;/strong&gt; is a context created in the contexts folder, the code is as follows:&lt;br&gt;
&lt;/p&gt;

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

import { 
  useState, 
  useEffect,
  useContext,
  createContext,     
  PropsWithChildren
} from "react";
import useLocalStorage from "../hooks/useLocalStorage";

interface AuthProviderProps extends PropsWithChildren{};

interface SessionProps {
  access_token?: string;
};

interface ContextProps {
  session: SessionProps;
  isSignedIn: boolean;
  isLoading: boolean;
};

const AuthContext = createContext&amp;lt;ContextProps&amp;gt;({
  session: {},
  isSignedIn: false,
  isLoading: false
});

function AuthProvider({ children }: AuthProviderProps) {
  const [session, setSession] = useState&amp;lt;SessionProps&amp;gt;({});
  const [isLoading, setIsLoading] = useState&amp;lt;boolean&amp;gt;(true);
  const isSignedIn = !!session &amp;amp;&amp;amp; !!session?.access_token;
  const storage = useLocalStorage();

  useEffect(() =&amp;gt; {
    try {
      const sessionStorage = storage.getItem('session') as SessionProps
      setIsLoading(true);

      if (sessionStorage.access_token) {
        setSession(sessionStorage);
        return;
      }
      setSession({});
    } catch (error) {
      setSession({});
      setIsLoading(false);
    } finally {
      setIsLoading(false);
    }
  }, [storage]);

  return (
    &amp;lt;AuthContext.Provider value={{ session, isSignedIn, isLoading }}&amp;gt;
      {children}
    &amp;lt;/AuthContext.Provider&amp;gt;
  );
}

export function useAuth() {
  return useContext(AuthContext);
}

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

&lt;/div&gt;



&lt;p&gt;In the context we make use of a custom hook called &lt;strong&gt;useLocalStorage( )&lt;/strong&gt; to separate the logic for basic operations using the &lt;em&gt;localStorage&lt;/em&gt; property, &lt;strong&gt;getItem&lt;/strong&gt;, &lt;strong&gt;setItem&lt;/strong&gt;, &lt;strong&gt;clear&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And we are using a third-party package called &lt;strong&gt;React-Secure-Storage&lt;/strong&gt; to encrypt and decrypt the data stored in &lt;em&gt;localStorage&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;First, let's download the package and then we start building the custom hook.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i react-secure-storage
yarn add react-secure-storage
pnpm add react-secure-storage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





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

import secureLocalStorage from 'react-secure-storage';

function useLocalStorage() {
    const storage = secureLocalStorage;

    function setItem&amp;lt;T&amp;gt;(key: string, value: T){
        storage.setItem(key, value as number | string | object | boolean);
    }

    function getItem(key: string): string |number | object| boolean | null{
        return storage.getItem(key);
    }

    function clear(){
        storage.clear();
    }

    return {
        getItem,
        setItem,
        clear
    };
}

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

&lt;/div&gt;



&lt;p&gt;And now we will create the component &lt;strong&gt;ProtectRoute&lt;/strong&gt;. This component will have  a function that will determine if the routes are public by using the values provided in the variable publicPages and the hooks from &lt;em&gt;next/navigation&lt;/em&gt; &lt;strong&gt;usePathname&lt;/strong&gt; and &lt;strong&gt;useRouter&lt;/strong&gt;. We are also using &lt;strong&gt;react-hot-toast&lt;/strong&gt; which is another third-party package to display toast success, error, warning toast messages throughout our application.&lt;/p&gt;

&lt;p&gt;To install it we use 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;npm i react-hot-toast
yarn add react-hot-toast
pnpm add react-hot-toast
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;​​'use client';

import { useAuth } from '@/app/contexts/auth';
import { usePathname, useRouter } from 'next/navigation';
import { useEffect } from 'react';
import { toast } from 'react-hot-toast';

interface ProtectRouteProps {
  children: React.ReactNode;
}

const publicPages = ['/', '/signup'];

function ProtectRoute({ children }: ProtectRouteProps) {
    const { isSignedIn, isLoading } = useAuth();
    const route = useRouter();
    const pathname = usePathname();

    useEffect(() =&amp;gt; {
        if (isSignedIn || isLoading || publicPages.includes(pathname)) return;

        route.replace('/');
        toast.error('User not authorized!');
    }, [isSignedIn, isLoading, pathname, route]);

    if(isLoading){
        return (
            &amp;lt;div&amp;gt;
                &amp;lt;center&amp;gt;
                    &amp;lt;span&amp;gt;Loading...&amp;lt;/span&amp;gt;
                &amp;lt;/center&amp;gt;
            &amp;lt;/div&amp;gt;
        );
    }

    if (isSignedIn || publicPages.includes(pathname)) {
        return children;
    }
    return null;
}

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

&lt;/div&gt;



&lt;p&gt;Well, I showed two ways of implementing the protection of routes, there are many more different ways, some simpler, some more verbose or performant, but the point here is to say that sooner or later you will end up needing to protect routes in your application due to the authentication flows that most application needs, the goal of this article is to share these two examples, so that you can make some tweakings to adapt and make it suitable for whatever need you may have.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://reactrouter.com/en/main" rel="noopener noreferrer"&gt;https://reactrouter.com/en/main&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://react.dev/reference/react" rel="noopener noreferrer"&gt;https://react.dev/reference/react&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nextjs.org/docs/pages/building-your-application/routing" rel="noopener noreferrer"&gt;https://nextjs.org/docs/pages/building-your-application/routing&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.w3schools.com/react/react_router.asp" rel="noopener noreferrer"&gt;https://www.w3schools.com/react/react_router.asp&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>nextjs</category>
      <category>reactjsdevelopment</category>
    </item>
    <item>
      <title>Deploying your application on AWS</title>
      <dc:creator>Hugo Ramon Pereira</dc:creator>
      <pubDate>Sat, 04 Nov 2023 00:30:02 +0000</pubDate>
      <link>https://forem.com/hramonpereira/deploying-your-application-on-aws-2dg</link>
      <guid>https://forem.com/hramonpereira/deploying-your-application-on-aws-2dg</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Lately, the usage of Cloud Computing has been rising a lot, so these skills are essential and required by companies. In this article, I will show you how to configure and deploy your application to &lt;strong&gt;AWS&lt;/strong&gt; which is the most used Cloud Provider. We will be using &lt;strong&gt;S3 (Simple Storage Service)&lt;/strong&gt;, &lt;strong&gt;CloudFront&lt;/strong&gt;, &lt;strong&gt;Route 53&lt;/strong&gt; and a &lt;strong&gt;React.js&lt;/strong&gt; application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating your AWS account or accessing your existing one
&lt;/h2&gt;

&lt;p&gt;The first thing we need to do is to create a new &lt;strong&gt;AWS account&lt;/strong&gt; if you don't have one, because we will need to use the &lt;strong&gt;AWS Management Console&lt;/strong&gt; to host and deploy our app. And it is necessary to add a valid credit card. &lt;strong&gt;AWS&lt;/strong&gt; offers many free tiers but the cost will be very low if there are any costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using a valid Domain- DNS
&lt;/h2&gt;

&lt;p&gt;A domain will be necessary for us to have a well-structured website and avoid having as the URL an AWS hash or a strange set of characters as the address of our application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Storing Static Files in S3
&lt;/h2&gt;

&lt;p&gt;The second thing we need to do is to generate the build of the application that we want to deploy and by doing that we will have the static files to be added to the bucket in &lt;strong&gt;Simple Storage Service - S3&lt;/strong&gt;. When a build is generated HTML, CSS, Javascript files, images and others are examples of static files that we will be storing in the &lt;strong&gt;S3&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Beware if you have a &lt;strong&gt;Next.js&lt;/strong&gt; application and you are using &lt;em&gt;Static Site Generation&lt;/em&gt;, in case you have &lt;em&gt;Server-Side Rendering&lt;/em&gt; you will not have these static files generated in the build.&lt;/p&gt;

&lt;p&gt;We are storing these static files to avoid the need of having a server serving static files, and users making requests to get those static files, if we were to follow this approach we would have to configure a load balancer, horizontal and vertical scaling, auto-scale and other things only to handle the serving of static files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating your bucket
&lt;/h2&gt;

&lt;p&gt;First, we need to give our bucket a name.&lt;/p&gt;

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

&lt;p&gt;First, we need to give our bucket a name.&lt;br&gt;
There are some naming conventions to be followed.&lt;/p&gt;

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

&lt;p&gt;When selecting the &lt;strong&gt;AWS Region&lt;/strong&gt; we have to be aware that the prices differ from region to region and also your location matters.&lt;br&gt;
Below the select for &lt;strong&gt;AWS Region&lt;/strong&gt;, we have the option to copy settings from an existing bucket but since we are creating our own we don't have to do anything there, it's optional by the way.&lt;br&gt;
Object Ownership we can leave &lt;strong&gt;ACLs (Access Control List)&lt;/strong&gt; disabled because the content of our bucket will be ours only, there will be no content that belongs to another &lt;strong&gt;AWS account&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxxpw63dvf0d1m7ech0hl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxxpw63dvf0d1m7ech0hl.png" alt="Block all public access" width="726" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our bucket is ready, now just click on the button to create the bucket and we are done in this part.&lt;/p&gt;

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

&lt;p&gt;After clicking on the Create Bucket button you will be redirected to the Buckets page and the bucket with the name you gave should appear there. Just click in the bucket to go to another page where we will be uploading our static files.&lt;/p&gt;

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

&lt;p&gt;Now we go to the Buckets page and there we can create or edit an existing bucket.&lt;/p&gt;

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

&lt;p&gt;Let's assume we are creating one bucket and it is empty of course, we can click on the upload button to add some static files to it.&lt;/p&gt;

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

&lt;p&gt;After doing this, you have to wait for the files to load and for now, we are done with the Buckets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating our Distribution using CloudFront&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once our files are uploaded in the bucket we need to make these files available to the world and that is when a CDN (Content Delivery Network) comes into play, CloudFront is the name of the service we are talking about. The PoP (Point of Presence) or Edge Locations are spread across the globe and they are responsible for providing faster access to the content by fetching them in the AWS Region we selected earlier, this reduces latency and stores the content in cache for faster access.&lt;/p&gt;

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

&lt;p&gt;Let's create our first distribution:&lt;/p&gt;

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

&lt;p&gt;The Origin domain is the source of data and our source of data is our S3 Bucket, AWS is intelligent enough to detect it for us, when you click the input a list of buckets and other assets you have in AWS will be listed for you. &lt;br&gt;
When you select a source of data it will fill the first and third inputs and the second which is the Origin path is optional we can skip that for now.&lt;br&gt;
The next part is the Origin access control settings and now we have 3 options:&lt;/p&gt;

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

&lt;p&gt;We will be selecting the second option which is the one recommended by AWS. Our bucket was configured to block all public access but by selecting this option we restrict it to CloudFront only.&lt;br&gt;
When you select the second option some fields will appear below:&lt;/p&gt;

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

&lt;p&gt;If this is your first contact with AWS you will not have an origin access control, you will have to create a control setting in the button.&lt;/p&gt;

&lt;p&gt;When the button is clicked a modal will appear with the following options. It will come with some options and you can leave it as it is and click on create.&lt;/p&gt;

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

&lt;p&gt;Now scrolling down the page we will have &lt;em&gt;Additional settings&lt;/em&gt; and we can also leave it as they are:&lt;/p&gt;

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

&lt;p&gt;Now we can configure the Default cache behavior:&lt;/p&gt;

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

&lt;p&gt;It is advisable to leave the compressed objects automatically selected. For the Viewer, I like to leave Redirect HTTP to HTTPS selected but you can restrict it to HTTPS only or as you wish.&lt;br&gt;
The allowed HTTP methods are selected GET and HEAD because this is a CDN configuration and we are only gonna be making requests to fetch data because our deployment is a simple one, but in case your project is a big one you must consider other options as well.&lt;br&gt;
The cache settings below can be left as it is, we have caching optimized which is recommended for S3.&lt;/p&gt;

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

&lt;p&gt;The next options are &lt;strong&gt;WAF (Web Application Firewall)&lt;/strong&gt; and in this case, we do not need it, if you enable some additional cost will come with it. Check the pricing below:&lt;/p&gt;

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

&lt;p&gt;For the other settings, we will be walking through all of them.&lt;/p&gt;

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

&lt;p&gt;We will be selecting the option to use all edge locations which will result in faster loading of the content, a few cents more expensive but if you have metrics that identify where most of your traffic comes from, feel free to check the Edge Locations closer to where you and your clients are.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding your own domain
&lt;/h2&gt;

&lt;p&gt;In case you don't associate your domain to it, &lt;strong&gt;AWS&lt;/strong&gt; will generate a hash to be used as your URL address which is not good to have a strange set of characters.&lt;/p&gt;

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

&lt;p&gt;To wrap up the creation of our &lt;strong&gt;CDN&lt;/strong&gt; in &lt;strong&gt;CloudFront&lt;/strong&gt; we should select &lt;em&gt;HTTP/2&lt;/em&gt; and &lt;em&gt;HTTP/3&lt;/em&gt;, &lt;em&gt;HTTP/3&lt;/em&gt; offers, a faster handshake and it is used by the most modern browsers.&lt;/p&gt;

&lt;p&gt;The default root object is the file that will be accessed in case one of our users accesses our &lt;em&gt;URL address&lt;/em&gt; with '/' we need to tell &lt;strong&gt;AWS&lt;/strong&gt; what file it must read to render the initial page.&lt;/p&gt;

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

&lt;p&gt;Now we have our &lt;strong&gt;CloudFront CDN&lt;/strong&gt; up and running, but we still need to make some configs, like adding the &lt;strong&gt;S3 bucket policy&lt;/strong&gt;.&lt;/p&gt;

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

&lt;p&gt;It is highlighted in the yellow section. When you click the button to copy the policy, if you paste it somewhere you will see that it is a &lt;strong&gt;JSON&lt;/strong&gt; file containing some info. &lt;/p&gt;

&lt;p&gt;What we need to do is to click on the link and it will redirect to the page where you need to add the &lt;strong&gt;JSON&lt;/strong&gt; file containing the policies.&lt;/p&gt;

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

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

&lt;p&gt;We just need to paste the &lt;strong&gt;JSON&lt;/strong&gt; and save the changes and that's it.&lt;/p&gt;

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

&lt;p&gt;After saving we will have our distribution ready to be used and our application can be accessed using the domain name provided by &lt;strong&gt;CloudFront&lt;/strong&gt;.&lt;/p&gt;

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

&lt;p&gt;Now your application is hosted in &lt;strong&gt;AWS&lt;/strong&gt;. But we need to use our domain and to do that we need to use &lt;strong&gt;Route 53&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a hosted zone with &lt;strong&gt;Route 53&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;First, let's access the &lt;strong&gt;Route 53&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Forasym4h6bemgkt5mjex.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Forasym4h6bemgkt5mjex.png" alt="Route 53 - Create hosted zones" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, all you have to do is enter your domain in the Domain name input, but first, you need to have a domain and remember not to add www, it's just the domain itself and after that click the button &lt;strong&gt;create hosted zone&lt;/strong&gt; and that is it.&lt;/p&gt;

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

&lt;p&gt;After the creation of your hosted zone, you need to add the Name servers to the website where you purchased your domain. AWS will give you 4 Name servers and in your website domain you might have only two servers to add, there must be a plus icon to add more and that is what you have to do in the &lt;strong&gt;Route 53 section&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now you have to wait a couple of hours for the propagation to happen and when it is finished you have to head back to &lt;strong&gt;CloudFront&lt;/strong&gt; to configure the &lt;em&gt;CNAME&lt;/em&gt;, because earlier we left it blank and now that we have our hosted zone.&lt;/p&gt;

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

&lt;p&gt;Now the final step is to go to the distribution we created earlier in &lt;em&gt;CloudFront&lt;/em&gt; and click on the settings edit button.&lt;/p&gt;

&lt;p&gt;We added 2 domain names so that our users can access it with or without the www at the beginning of the &lt;em&gt;URL address&lt;/em&gt;.&lt;/p&gt;

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

&lt;p&gt;Congratulations! You have successfully deployed your website to &lt;strong&gt;AWS&lt;/strong&gt; with a custom domain using an &lt;strong&gt;S3 bucket (Simple Storage Service)&lt;/strong&gt;, a &lt;strong&gt;CDN (Content Delivery Network) **&lt;/strong&gt;CloudFront** and &lt;strong&gt;Route 53&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  References:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/s3/#amazon-s3" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/s3/#amazon-s3&lt;/a&gt;&lt;br&gt;
&lt;a href="https://aws.amazon.com/cloudfront/getting-started/" rel="noopener noreferrer"&gt;https://aws.amazon.com/cloudfront/getting-started/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Introduction.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Introduction.html&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/Welcome.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/Welcome.html&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloudcomputing</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Setting up React Query in your React project</title>
      <dc:creator>Hugo Ramon Pereira</dc:creator>
      <pubDate>Thu, 26 Oct 2023 16:02:36 +0000</pubDate>
      <link>https://forem.com/hramonpereira/setting-up-react-query-in-your-react-project-12bj</link>
      <guid>https://forem.com/hramonpereira/setting-up-react-query-in-your-react-project-12bj</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Consuming data from an API or some sort of external source is always necessary throughout our applications and the traditional method using fetch API and the useEffect hook is a bit verbose, time-consuming and not advised. Axios emerged as a solution for that and currently, Axios is still dominant in use.&lt;/p&gt;

&lt;p&gt;This is where React Query comes into play, React Query is responsible for managing asynchronous operations between server and client and it gives us many advantages.&lt;/p&gt;

&lt;p&gt;So for this article, we will be talking about React Query v5 with Axios to provide an excellent combination of technologies, so that you can handle your requests, data fetching, asynchronous state handling, caching, garbage collection, memory management, refetching, loading states, react query dev tools and some examples.&lt;/p&gt;

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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i @tanstack/react-query
yarn add @tanstack/react-query
pnpm add @tanstack/react-query
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;React-Query setup&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;After installation, the first thing we need to do in our React.js application is to wrap our entire application with QueryClientProvider and pass a client prop to it. Now React-Query is ready to be used.&lt;br&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 ReactDOM from 'react-dom/client';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const queryClient = new QueryClient();

export function App() {
  return (
    &amp;lt;QueryClientProvider client={queryClient}&amp;gt;
      &amp;lt;App /&amp;gt;
    &amp;lt;/QueryClientProvider&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can also pass some initial properties to the Query Client:&lt;/p&gt;

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

&lt;h2&gt;
  
  
  &lt;strong&gt;React-Query DevTools - Optional&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;You can also install React-Query DevTools. React-Query Dev Tools will help you visualize data and everything that is going on and it is a tool that will give you important info to help you debug your application.&lt;/p&gt;

&lt;p&gt;We have to install it since it is a separate package provided by Tanstack.&lt;/p&gt;

&lt;p&gt;Here's how to install it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i @tanstack/react-query-devtools
yarn add @tanstack/react-query-devtools
pnpm add @tanstack/react-query-devtools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's configure React-Query DevTools in our application, we can pass it inside the QueryClientProvider as a sibling of the main component . We can also pass 3 properties to define the position of the Icon that triggers the panel and the DevTools Panel itself.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;initialIsOpen - If you pass this then DevTools is going to be open by default&lt;/li&gt;
&lt;li&gt;position - The panel position, top, bottom, left or right&lt;/li&gt;
&lt;li&gt;buttonPosition - The position of the button that opens the panel, possible values are: top-left, top-right, bottom-left, bottom-right.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import ReactDOM from 'react-dom/client';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';

const queryClient = new QueryClient();

export function App() {
  return (
    &amp;lt;QueryClientProvider client={queryClient}&amp;gt;
      &amp;lt;App /&amp;gt;
      &amp;lt;ReactQueryDevtools 
         initialIsOpen 
         position='right'     
         buttonPosition='bottom-right' 
      /&amp;gt;
    &amp;lt;/QueryClientProvider&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h2&gt;
  
  
  &lt;strong&gt;Implementation&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;With the initial configurations out of the way, we can now start using it for real.&lt;/p&gt;

&lt;p&gt;The basics of React Query are 2 things, query and mutation. Query is when we fetch data from somewhere and mutation is when data is changed, this change can happen for several reasons, an update, data has become stale, a post, a put, patch request and React-Query will handle that for us.&lt;/p&gt;

&lt;p&gt;To handle the requests to the API in this article we will be using Axios, to install it follow the steps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i axios
yarn add axios
pnpm add axios
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I created an API configuration file to make requests to jsonplaceholder api to bring a list of the posts.&lt;br&gt;
&lt;/p&gt;

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

const todosApi = axios.create({
  baseURL: 'https://jsonplaceholder.typicode.com'
});

export async function getTodos () {
  const response = await todosApi.get('/todos');
  return response.data;
}

export async function addTodo (todo) {
  const response = await todosApi.post('/todos', todo);
  return response.data;
}

export async function editTodo (todo) {
  const response = await todosApi.patch(`/todos/${todo.id}`, todo);
  return response.data;
}

export async function removeTodo ({ id }) {
  const response = await todosApi.delete(`/todos/${id}`, id);
  return response.data;
}

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

&lt;/div&gt;



&lt;p&gt;And I created a TodoList component where we will combine the code using Axios and React-Query.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query';
import { getTodos, addTodo } from '../../api/api';

export default function TodoList() {
  const queryClient = useQueryClient();

  const { data, isLoading,  } = useQuery({
    queryKey: ['todos'],
    queryFn: getTodos
  });

  const { mutateAsync } = useMutation({
    mutationFn: addTodo,
    onSuccess: () =&amp;gt; {
      queryClient.invalidateQueries({ queryKey: ['todos'] });
    }
  });

  if (isLoading) {
    return &amp;lt;p&amp;gt;Loading posts...&amp;lt;/p&amp;gt;;
  }
  return (
    &amp;lt;main&amp;gt;
      &amp;lt;h1&amp;gt;Todo List&amp;lt;/h1&amp;gt;
      &amp;lt;ul&amp;gt;
        {data.map((todo) =&amp;gt; (
          &amp;lt;li key={todo.id}&amp;gt;
            {todo.title}
          &amp;lt;/li&amp;gt;
        ))}
      &amp;lt;/ul&amp;gt;;

      &amp;lt;button onClick={() =&amp;gt; {
        mutateAsync({
          id: Math.random(),
          title: 'Finish article'
        });
      }}&amp;gt;
        Add todo
      &amp;lt;/button&amp;gt;
    &amp;lt;/main&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we weren't using React-Query we would have to create, loading states using useState, handle the errors, caching, as you can see in the image below:&lt;/p&gt;

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

&lt;p&gt;As said before React-Query works with 2 concepts query and mutation and React-Query provides the hooks &lt;strong&gt;useQuery( )&lt;/strong&gt; and &lt;strong&gt;useMutation( )&lt;/strong&gt; for us to handle our asynchronous operations between Frontend and Backend.&lt;/p&gt;

&lt;p&gt;The hook &lt;strong&gt;useQuery&lt;/strong&gt; is used to fetch data and to do that we import those functions created in the API code previously provided. We are importing both code from React-Query and also the API that is using &lt;strong&gt;Axios&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When we use the hook &lt;strong&gt;useQuery( )&lt;/strong&gt; is common to pass an object with a &lt;strong&gt;queryKey&lt;/strong&gt; which can be any name you want but it should be related to what sort of operation is being done to be more semantic, in our case we named it 'todos' because that is exactly what we are dealing with, we are fetching a list of todos. React-Query will handle cache, memory optimization, garbage collection and other things with this value.&lt;/p&gt;

&lt;p&gt;We also pass a &lt;strong&gt;queryFn&lt;/strong&gt; which is the function that will execute the request which in our case is being done by &lt;strong&gt;Axios&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { data, isLoading } = useQuery({
    queryKey: ['todos'],
    queryFn: getTodos
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above the getTodos function is in the api file and it was imported into this component to be used here with React-Query. And to have access to the posts fetched all we have to do is map through the data which is the first value destructured and now we have all the posts in a li tag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;&amp;gt;
  &amp;lt;h1&amp;gt;Todo List&amp;lt;/h1&amp;gt;
    &amp;lt;ul&amp;gt;
      {data.map((todo) =&amp;gt; (
         &amp;lt;li key={todo.id}&amp;gt;
            {todo.title}
         &amp;lt;/li&amp;gt;
      ))}
    &amp;lt;/ul&amp;gt;;
&amp;lt;/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We don't have to create states [isLoading, setIsLoading] because all of that and much more is already built-in and provided by React-Query.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (isLoading) {
  return &amp;lt;p&amp;gt;Loading posts...&amp;lt;/p&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As for the operations that will involve changes in the data, we will use the hook useMutation( ).&lt;/p&gt;

&lt;p&gt;We can destructure many props from useMutation( ) and pass an object to it as in the useQuery( ) hook. But now we pass a mutationDn which is the function that will change data, it can be a request to the api or something.&lt;/p&gt;

&lt;p&gt;We can also pass a callback function to onSuccess, onError to handle the success or error cases of the request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { mutateAsync } = useMutation({
    mutationFn: addTodo,
    onSuccess: () =&amp;gt; {
      queryClient.invalidateQueries({ queryKey: ['todos'] });
    }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can use the mutateAsync function that was destructured and use it in a button to be triggered via onClick( ) or something.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;button onClick={() =&amp;gt; {
   mutateAsync({
      id: Math.random(),
      title: 'Finish article'
   });
}}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Conclusion&lt;br&gt;
There are tons of other things that can be done with React-Query, we only scratched the surface here. To have more details and further info you can always turn to the official docs that will be provided below.&lt;/p&gt;

&lt;p&gt;React-Query is a very powerful technology and you should use it in your projects along with Axios, you will have a powerful combination of tools to handle a lot of things that you would have to do by yourself, many useStates and useEffects can be avoided by using React-Query properly.&lt;/p&gt;

&lt;p&gt;References&lt;br&gt;
&lt;a href="https://tanstack.com/query/v5/docs/react/overview" rel="noopener noreferrer"&gt;https://tanstack.com/query/v5/docs/react/overview&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://axios-http.com/" rel="noopener noreferrer"&gt;https://axios-http.com/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>reactquery</category>
      <category>restapi</category>
    </item>
    <item>
      <title>Server Components: React.js and Next.js</title>
      <dc:creator>Hugo Ramon Pereira</dc:creator>
      <pubDate>Thu, 19 Oct 2023 18:42:08 +0000</pubDate>
      <link>https://forem.com/hramonpereira/server-components-reactjs-and-nextjs-272a</link>
      <guid>https://forem.com/hramonpereira/server-components-reactjs-and-nextjs-272a</guid>
      <description>&lt;h2&gt;
  
  
  What are Server Components?
&lt;/h2&gt;

&lt;p&gt;RSC - React Server Components is an architecture model developed by the React team, this concept was introduced in December 2020 but this is nothing new, other programming languages like PHP, Python, Ruby and others already had content rendered on the server side, in summary, this is the main goal, to be able to render components on the server. There is a layer that pre-renders a large blob of static HTML content to avoid unnecessary usage of Javascript which is achieved by caching what needs to be rendered in the server. This happens using React Streaming which can be implemented using the new method renderToPipeableStream and React Suspense.&lt;/p&gt;

&lt;h2&gt;
  
  
  What benefits do they bring?
&lt;/h2&gt;

&lt;p&gt;In React applications, Server Components exclude your Javascript from the bundle which allows us to fetch static content during the build and also read data without having to build the API, this scenario favors users with slower devices or network connections. React introduced async / await as the main way to fetch data from the server discarding the need to use the hook useEffect( ) for example, check the code below to see a request being made to the still using  the hook useEffect( ) to fetch data from the API  jsonplaceholder.typicode.com:&lt;br&gt;
&lt;/p&gt;

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

import React, { useEffect, useState } from 'react';

export default function Home() {
  const [data, setData] = useState([]);

  useEffect(() =&amp;gt; {
    fetch('https://jsonplaceholder.typicode.com/posts/')
      .then((response) =&amp;gt; response.json())
      .then((data) =&amp;gt; {
        setData(data);
      })
  }, []);

  return (
    &amp;lt;div&amp;gt;
      {data.map(post =&amp;gt; (
        &amp;lt;div&amp;gt;
          &amp;lt;h1&amp;gt;{post.title}&amp;lt;/h1&amp;gt;
          &amp;lt;p&amp;gt;{post.body}&amp;lt;/p&amp;gt;
        &amp;lt;/div&amp;gt;
      ))}
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the case of a Next.js application, all components are server components by default, if we wish to turn a specific component into a client component we have to use the flag ‘use client’ at the top to indicate that it is a server component and also a client component and with the ‘use client’ directive we can use hooks in the component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default async function Home() {
  const response = await fetch('https://jsonplaceholder.typicode.com/posts')
  const posts = await response.json();

  return (
    &amp;lt;&amp;gt;
      &amp;lt;ul&amp;gt;
        {posts.map(post =&amp;gt; (
          &amp;lt;div&amp;gt;
             &amp;lt;h1&amp;gt;{post.title}&amp;lt;/h1&amp;gt;
             &amp;lt;p&amp;gt;{post.body}&amp;lt;/p&amp;gt;
          &amp;lt;/div&amp;gt;
        ))}
      &amp;lt;/ul&amp;gt;
    &amp;lt;/&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both codes displayed above will return the same content, a bunch of posts fetched from the API jsonplaceholder.typicode.com, but in the second example we have less lines of code and a code easier to read and grasp.&lt;/p&gt;

&lt;p&gt;React server components help improve the performance of applications with code splitting, with lazy loading that hydrates only what is needed and it results in a bundle size being zero size and the SEO is great due to the fast loading of the page.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the downsides?
&lt;/h2&gt;

&lt;p&gt;The server-only rendering on the server side is another environment and we will need to be more cautious about hydrations, what renders on the server must match what is hydrated on the client, if the content doesn't match then it will result in hydration errors.&lt;/p&gt;

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

&lt;p&gt;Seeing that we have faster page loading, SEO, bundle size reduced, Code splitting, Streaming, Lazy loading, Suspense and other benefits, it's fairly recommended to use server components throughout our applications, and knowing when to use them is key to having better applications always aiming to provide our clients with the best experience they can get.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://react.dev/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components" rel="noopener noreferrer"&gt;https://react.dev/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nextjs.org/docs/pages/building-your-application/rendering/server-side-rendering" rel="noopener noreferrer"&gt;https://nextjs.org/docs/pages/building-your-application/rendering/server-side-rendering&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.patterns.dev/posts/streaming-ssr" rel="noopener noreferrer"&gt;https://www.patterns.dev/posts/streaming-ssr&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Writing your own Custom Hooks</title>
      <dc:creator>Hugo Ramon Pereira</dc:creator>
      <pubDate>Tue, 17 Oct 2023 13:47:56 +0000</pubDate>
      <link>https://forem.com/hramonpereira/writing-your-own-custom-hook-24ch</link>
      <guid>https://forem.com/hramonpereira/writing-your-own-custom-hook-24ch</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Since 2019 when React.js core team launched the version 16.8 with the React Hooks, a lot has changed ever since. Hooks have significantly improved the way we write code with React.js.&lt;/p&gt;

&lt;p&gt;Now we can manage the state in a cleaner and leaner way, handle side effects, avoid unnecessary re-renders, improve performance and the list goes on and on…&lt;/p&gt;

&lt;h2&gt;
  
  
  But what are React Hooks?
&lt;/h2&gt;

&lt;p&gt;Hooks are functions that were built to help us manage the lifecycle of Functional Components. We still have the Class-based Components but we cannot use hooks with Class-based Components. All hooks have to start with the word use by the way.&lt;/p&gt;

&lt;p&gt;Now let’s take a look at 2 example of hooks before we write our own:&lt;/p&gt;

&lt;h2&gt;
  
  
  useState( )
&lt;/h2&gt;

&lt;p&gt;The useState Hook allows you to manage a state variable and a function to update the value of this variable and reflect in the component it is being used.&lt;/p&gt;

&lt;p&gt;States are data that is being used in our components and we need to keep track of the changes these data suffers so that React can update and re-render the component to display this new data.&lt;/p&gt;

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

&lt;p&gt;In the code above we have the name state variable having empty strings as default value, which is passed at the execution of useState and setName function.&lt;/p&gt;

&lt;p&gt;We created an auxiliary function to use setName and get the input value and we are using onChange to watch for that and the as the value of the input we used the name to bind it to our state.&lt;/p&gt;

&lt;h2&gt;
  
  
  useEffect( )
&lt;/h2&gt;

&lt;p&gt;The useEffect Hook allows you to execute actions we call side effects in your components manipulating the lifecycle of our components. We use the useEffect hook to fetch data from an API or some other source of data, update the DOM, and timed tasks, the effects will execute when the page is first loaded or when we specify a dependency in the dependency list.&lt;/p&gt;

&lt;p&gt;useEffect( ) takes 2 arguments: a function and a dependency as mentioned above. useEffect will be observing this dependency and when it does change then the actions we specified in the first argument, which is a function will execute.&lt;/p&gt;

&lt;p&gt;We can specify no dependency in the dependency list or array and if we do so, then the useEffect hook will be executed only once, when the page is loaded for the first time and this behavior is what the ComponentDidMount used to do in previous versions of React.js.&lt;/p&gt;

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

&lt;p&gt;In the example above the dependency list which is the empty array has no dependencies, we can add dependencies or not.&lt;/p&gt;

&lt;p&gt;useState and useEffect are the 2 most used React hooks and now I will introduce you to Custom Hooks:&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom Hooks
&lt;/h2&gt;

&lt;p&gt;Hooks are reusable functions. React.js provides a list of Hooks, you can make a research and see if one of them suits your needs, if not you can build your own and that is exactly what we are going to do.&lt;/p&gt;

&lt;p&gt;When you have component logic that needs to be used by multiple components, we can extract that logic to a custom hook.&lt;/p&gt;

&lt;p&gt;In the code below you can see a custom hook called useWindowWidth which was created using the hooks useState and useEffect to store the width of the window by using the window.innerWidth and we used the useEffect to watch for changes in the width of the window and when it does change useEffect will be triggered and the state updating function setWidth will be executed.&lt;/p&gt;

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

&lt;p&gt;useEffect will know the window changed its width because of the event listener ‘resize’ added inside of it.&lt;/p&gt;

&lt;p&gt;And after the window is resized it is wise to remove events from our code to avoid memory issues like memory leak. We call a cleanup function where we add a removeEventListener. Events take up memory space, and we don't want unnecessary memory being misused and wasted which can and might cause issues as your applications grows.&lt;/p&gt;

&lt;p&gt;In the code below we can see our Hook in action.&lt;/p&gt;

&lt;p&gt;The purpose of this hook was to extract some logic to manipulate the classes of TailwindCSS.&lt;/p&gt;

&lt;p&gt;In the classes of the Button component below we are using a ternary operator with windowWidth to add different background colors to our button when the width of the button changes for example, we can use our hook to manipulate the responsiveness of the app, it is acting like a breakpoint.&lt;/p&gt;

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

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

&lt;p&gt;React Hooks are amazing and they also give us room to create our own hooks which was the main purpose of this article, to show you that you can abstract your code by using hooks that can save us a lot of time and countless lines of code and please remember to start it with the name use and something.&lt;/p&gt;

&lt;p&gt;So whenever you feel the need to reuse code that is being repeated that is when the Hooks come in handy.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://react.dev/reference/react" rel="noopener noreferrer"&gt;React.js&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.w3schools.com/REACT/react_hooks.asp" rel="noopener noreferrer"&gt;W3 Schools&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
    </item>
    <item>
      <title>The importance of using Server-Side Rendering with Next.JS</title>
      <dc:creator>Hugo Ramon Pereira</dc:creator>
      <pubDate>Mon, 17 Jan 2022 18:30:34 +0000</pubDate>
      <link>https://forem.com/hramonpereira/the-importance-of-using-server-side-rendering-with-nextjs-16h</link>
      <guid>https://forem.com/hramonpereira/the-importance-of-using-server-side-rendering-with-nextjs-16h</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Server-Side Rendering (SSR) is a resource provided by Next.JS meaning that for each request made by the user, a server-side HTML will be generated and that content will be pre-rendered. So when a request for a specific page is made, the process of building that page done by the browser will be faster. This set of steps of requesting content from the database, building the page by the browsers and delivering it to the client is Client-Side Rendering.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What are the advantages of using Server-Side Rendering with Next.JS?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The main advantages are: the faster response in page loading, the SEO (Search Engine Optimization) and the Web Crawlers that are the bots responsible for improving the indexing in the search engines of browsers such as Google, Bing, thus providing a better experience for the user who will have less waiting time and your page or site will probably appear at the top of searches.&lt;/p&gt;

&lt;p&gt;Please have in mind that Next.JS also offers SSG (Static Site Generation) which is more recommended for smaller projects and that will not have that many components, which require so many specific requests to serve them, this can affect the performance of your application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does the SSR happen?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Using a function called getServerSideProps() by convention, Next.JS will understand that by using the above name in the function, server-side rendering should and will happen. The data of the function is passed via props that can be consumed in the function below in the same JS or JSX file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhj8m3p9hoews4fpl2so0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhj8m3p9hoews4fpl2so0.png" alt="Snippet of code showing how to implement Server-Side Rendering in Next.JS" width="800" height="618"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The content generated by the code above:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnjhx8mpveur6ut4sig54.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnjhx8mpveur6ut4sig54.JPG" alt="Result in the browser of the code above showing Server-Side Rendering in action" width="800" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Terminal in VSCode:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fglkf5xtos3gg9wzz6g3v.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fglkf5xtos3gg9wzz6g3v.JPG" alt="VSCode terminal showing Server-Side Rendering in the console" width="800" height="293"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is Search Engine Optimization (SEO)?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Taking into account that this is the main reason for using Server-Side Rendering with Next.JS, what is this Search Engine Optimization (SEO)? Well, that is a set of good practices that, if executed, make your page or WEB application better indexed in Google, Bing or other search engines, and that might lift your page or application to be in the first options to be shown for the user that makes the search for some content. The better structured, semantically organized with the correct tags, meta tags, titles, sections, alt attributes and ARIA (Accessible Rich Internet Applications) and that will provide a better experience when the subject is accessibility. The better your page is structured the better it will be evaluated by these browser search engines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lighthouse: How do I know if my page or site indexing is good?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Lighthouse is a tool developed by Google that analyzes web pages and applications providing metrics on performance, best practices, accessibility, SEO or if the application or page is a PWA (Progressive Web App) and even simulates a desktop and mobile application. It’s worth checking out the results. You can find Lighthouse in Chrome Dev Tools under one of the tabs, but not just in Google Chrome, in many browsers based on Google Chrome. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1m5kk7ts7swkgod3szu7.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1m5kk7ts7swkgod3szu7.JPG" alt="Image showing Lighthouse in Chrome Developer Tools" width="800" height="186"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After clicking on ‘Generate Report’, a page analysis process will be started and a report will be generated.&lt;br&gt;
We analyzed Vercel's website, which is the creator of the Next.JS framework, and these were the results:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbg4lagc9j5vuwd7bogdb.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbg4lagc9j5vuwd7bogdb.JPG" alt="Image showing results of the analysis made by Lighthouse on Vercel's website" width="800" height="321"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;References:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://vercel.com/blog/nextjs-server-side-rendering-vs-static-generation" rel="noopener noreferrer"&gt;https://vercel.com/blog/nextjs-server-side-rendering-vs-static-generation&lt;/a&gt; &lt;br&gt;
&lt;a href="https://blog.cod3r.com.br/server-side-rendering-x-client-side-rendering" rel="noopener noreferrer"&gt;https://blog.cod3r.com.br/server-side-rendering-x-client-side-rendering&lt;/a&gt; &lt;br&gt;
&lt;a href="https://medium.com/swlh/server-side-rendering-with-next-js-56f84f98f9bd" rel="noopener noreferrer"&gt;https://medium.com/swlh/server-side-rendering-with-next-js-56f84f98f9bd&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ramon Pereira&lt;br&gt;
Frontend Developer&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The importance of using Server-Side Rendering with Next.JS</title>
      <dc:creator>Hugo Ramon Pereira</dc:creator>
      <pubDate>Mon, 17 Jan 2022 18:19:47 +0000</pubDate>
      <link>https://forem.com/hramonpereira/the-importance-of-using-server-side-rendering-with-nextjs-1p0c</link>
      <guid>https://forem.com/hramonpereira/the-importance-of-using-server-side-rendering-with-nextjs-1p0c</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Server-Side Rendering (SSR) is a resource provided by Next.JS meaning that for each request made by the user, a server-side HTML will be generated and that content will be pre-rendered. So when a request for a specific page is made, the process of building that page done by the browser will be faster. This set of steps of requesting content from the database, building the page by the browsers and delivering it to the client is Client-Side Rendering.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What are the advantages of using Server-Side Rendering with Next.JS?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The main advantages are: the faster response in page loading, the SEO (Search Engine Optimization) and the Web Crawlers that are the bots responsible for improving the indexing in the search engines of browsers such as Google, Bing, thus providing a better experience for the user who will have less waiting time and your page or site will probably appear at the top of searches.&lt;/p&gt;

&lt;p&gt;Please have in mind that Next.JS also offers SSG (Static Site Generation) which is more recommended for smaller projects and that will not have that many components, which require so many specific requests to serve them, this can affect the performance of your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How does the SSR happen?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Using a function called getServerSideProps() by convention, Next.JS will understand that by using the above name in the function, server-side rendering should and will happen. The data of the function is passed via props that can be consumed in the function below in the same JS or JSX file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F571ghi67jjmlvk5i8rjw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F571ghi67jjmlvk5i8rjw.png" alt="Snippet of code showing how to use Next.JS Server-Side Rendering" width="800" height="618"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The content generated by the code above:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fla5ekloulvs251tfkyp7.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fla5ekloulvs251tfkyp7.JPG" alt="Result of the code above with Server-Side Rendering" width="800" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Terminal in VSCode:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsbpixmvyvd4t92de12o8.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsbpixmvyvd4t92de12o8.JPG" alt="VSCode terminal showing that we really used Server-Side Rendering" width="800" height="293"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;**&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Search Engine Optimization (SEO)?
&lt;/h2&gt;

&lt;p&gt;**&lt;/p&gt;

&lt;p&gt;Taking into account that this is the main reason for using Server-Side Rendering with Next.JS, what is this Search Engine Optimization (SEO)? Well, that is a set of good practices that, if executed, make your page or WEB application better indexed in Google, Bing or other search engines, and that might lift your page or application to be in the first options to be shown for the user that makes the search for some content. The better structured, semantically organized with the correct tags, meta tags, titles, sections, alt attributes and ARIA (Accessible Rich Internet Applications) and that will provide a better experience when the subject is accessibility. The better your page is structured the better it will be evaluated by these browser search engines.&lt;/p&gt;

&lt;p&gt;**&lt;/p&gt;

&lt;h2&gt;
  
  
  Lighthouse: How do I know if my page or site indexing is good?
&lt;/h2&gt;

&lt;p&gt;**&lt;/p&gt;

&lt;p&gt;Lighthouse is a tool developed by Google that analyzes web pages and applications providing metrics on performance, best practices, accessibility, SEO or if the application or page is a PWA (Progressive Web App) and even simulates a desktop and mobile application. It’s worth checking out the results. You can find Lighthouse in Chrome Dev Tools under one of the tabs, but not just in Google Chrome, in many browsers based on Google Chrome.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkcspnh7m6cin22ugzrnf.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkcspnh7m6cin22ugzrnf.JPG" alt="Image of Lighthouse in Chrome Dev Tools" width="800" height="186"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After clicking on ‘Generate Report’, a page analysis process will be started and a report will be generated.&lt;br&gt;
We analyzed Vercel's website, which is the creator of the Next.JS framework, and these were the results:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fghgh07e9w6vh4zm3x2a2.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fghgh07e9w6vh4zm3x2a2.JPG" alt="Result of the analysis of Vercel's website" width="800" height="321"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;References: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://vercel.com/blog/nextjs-server-side-rendering-vs-static-generation" rel="noopener noreferrer"&gt;https://vercel.com/blog/nextjs-server-side-rendering-vs-static-generation&lt;/a&gt; &lt;br&gt;
&lt;a href="https://blog.cod3r.com.br/server-side-rendering-x-client-side-rendering" rel="noopener noreferrer"&gt;https://blog.cod3r.com.br/server-side-rendering-x-client-side-rendering&lt;/a&gt; &lt;br&gt;
&lt;a href="https://medium.com/swlh/server-side-rendering-with-next-js-56f84f98f9bd" rel="noopener noreferrer"&gt;https://medium.com/swlh/server-side-rendering-with-next-js-56f84f98f9bd&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ramon Pereira&lt;br&gt;
Frontend Developer&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
