<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Aswanth Raveendran EK</title>
    <description>The latest articles on DEV Community by Aswanth Raveendran EK (@aswanth_raveendranek_a2a).</description>
    <link>https://dev.to/aswanth_raveendranek_a2a</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%2F1954628%2F116a96b8-35da-40d2-a1e3-add801a015bd.jpg</url>
      <title>DEV Community: Aswanth Raveendran EK</title>
      <link>https://dev.to/aswanth_raveendranek_a2a</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aswanth_raveendranek_a2a"/>
    <language>en</language>
    <item>
      <title>Render Block component in Next JS and Headless CMS</title>
      <dc:creator>Aswanth Raveendran EK</dc:creator>
      <pubDate>Sat, 26 Oct 2024 07:33:58 +0000</pubDate>
      <link>https://dev.to/aswanth_raveendranek_a2a/render-block-component-in-next-js-and-headless-cms-24f3</link>
      <guid>https://dev.to/aswanth_raveendranek_a2a/render-block-component-in-next-js-and-headless-cms-24f3</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In modern web development, creating dynamic and scalable websites is essential for delivering personalized user experiences. One of the most effective ways to achieve this is by integrating a headless CMS with a frontend framework like Next.js. A headless CMS allows developers to separate the content management layer from the presentation layer, enabling seamless content updates without touching the codebase. This setup is ideal for sites that require frequent content changes, like blogs, portfolios, and e-commerce sites.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Role of Headless CMS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A headless CMS (Content Management System) is a backend-only system that manages content independently of the frontend. This approach allows developers to select or build a frontend framework without being constrained by the CMS’s native capabilities. Popular headless CMS options includes Strapi, Payload etc.&lt;br&gt;
With a headless CMS, content creators and developers can work in parallel: editors manage content, and developers focus on the presentation layer using tools like Next.js.&lt;br&gt;
NB: You don't need to know more about CMS to create this. Just understand about the APIs your CMS framework provides.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Set Up&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create a component called renderBlocks in your Next JS src folder.&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%2F17jx8frzp1544n4yrfwd.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%2F17jx8frzp1544n4yrfwd.png" alt="Folder structure" width="318" height="359"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now create a functional component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import type { Page } from "@/types/block-types/types";
import React, { Fragment } from "react";
import HeroBanner from "./blocks/HeroBanner";
import FormBlock from "./blocks/FormBlock";

const blockComponents = {
    banner: HeroBanner,
    formBlock: FormBlock
};

interface RenderBlocksProps {
  blocks: Page["layout"];
}

export const RenderBlocks: React.FC&amp;lt;RenderBlocksProps&amp;gt; = (props) =&amp;gt; {

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

&lt;/div&gt;



&lt;p&gt;The blockComponents object contain the Components that we created in our project.&lt;/p&gt;

&lt;p&gt;The component will accept a prop called blocks which is the API response of the CMS which includes all the data that needs to show in the page.&lt;/p&gt;

&lt;p&gt;Below is an example type of blocks&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export interface Page {
    layout: (BannerBlock | FormBlock)[];
}

export interface BannerBlock {
    media: {
        src: string;
        alt: string;
    };
    title: string;
    blockType: "banner"
}

export interface FormBlock {
    title: string;
    blockType: "formblock"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can create a file called block-types.ts in the utils folder and create your types for blocks there. &lt;br&gt;
NB: This types can be changed according to the CMS you use and also it depends on the field name that you use in your CMS.&lt;/p&gt;

&lt;p&gt;In the blocks props you will have array of objects each object is the data that you want to show in your page. And each object contain a unique property. I mentioned it here as blockType. This blockType should be the same key of the blockComponents object.&lt;/p&gt;

&lt;p&gt;Below is a mock data that you are going to get from your CMS API. This will have changes from an actual response. I am just showing it here for better understanding.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  layout: [
    {
      image: {
        src: "image.png",
        alt: "Alt text",
      },
      title: "Banner Title",
      blockType: "banner",
    },
    {
      title: "Contact Form",
      blockType: "formBlock"
    }
  ]
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Below is the complete code for your renderBlocks component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import type { Page } from "@/types/block-types/types";
import React, { Fragment } from "react";
import HeroBanner from "./blocks/HeroBanner";
import FormBlock from "./blocks/FormBlock";

const blockComponents = {
    banner: HeroBanner,
    formBlock: FormBlock
};

interface RenderBlocksProps {
  blocks: Page["layout"];
}

export const RenderBlocks: React.FC&amp;lt;RenderBlocksProps&amp;gt; = (props) =&amp;gt; {
  const { blocks } = props;

  const hasBlocks = blocks &amp;amp;&amp;amp; Array.isArray(blocks) &amp;amp;&amp;amp; blocks.length &amp;gt; 0;

  if (hasBlocks) {
    return (
      &amp;lt;Fragment&amp;gt;
        {blocks.map((block, index) =&amp;gt; {
          const { blockType } = block;

          if (blockType &amp;amp;&amp;amp; blockType in blockComponents) {
            const Block = blockComponents[blockType];

            if (Block) {
              return (
                &amp;lt;div key={index}&amp;gt;
                  {/* @ts-expect-error: has no properties in common with type 'IntrinsicAttributes' */}
                  &amp;lt;Block {...block} /&amp;gt;
                &amp;lt;/div&amp;gt;
              );
            }
          }
          return null;
        })}
      &amp;lt;/Fragment&amp;gt;
    );
  }

  return null;
};

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;How to use this?&lt;/strong&gt;&lt;br&gt;
Create a page in your app directory and call the render blocks components there with data you fetched from the CMS API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Page } from "@/types/block-types/types";
import { RenderBlocks } from "@/component/RenderBlocks";

const HomePage= async() =&amp;gt; {
cons page:Page = await CallToPageDataAPI()
  return (
    &amp;lt;div className="bg-background"&amp;gt;
      &amp;lt;RenderBlocks blocks={page.layout} /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

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

&lt;/div&gt;



&lt;p&gt;The logic presented here is tailored to my specific use case, but feel free to adapt it as needed. If you encounter any issues or have suggestions, please don't hesitate to leave a comment. I'm always open to feedback and improvement. Thank you for taking the time to read this!&lt;/p&gt;

&lt;p&gt;NB: A CMS API response will be more complex than what is referred to here. Please make necessary changes to the types according to your use case.&lt;/p&gt;

</description>
      <category>headlesscms</category>
      <category>nextjs</category>
      <category>jsx</category>
    </item>
    <item>
      <title>Generate Dynamic Sitemap in Next js</title>
      <dc:creator>Aswanth Raveendran EK</dc:creator>
      <pubDate>Fri, 11 Oct 2024 18:03:05 +0000</pubDate>
      <link>https://dev.to/aswanth_raveendranek_a2a/generate-dynamic-sitemap-in-next-js-27m9</link>
      <guid>https://dev.to/aswanth_raveendranek_a2a/generate-dynamic-sitemap-in-next-js-27m9</guid>
      <description>&lt;p&gt;&lt;strong&gt;Indroduction&lt;/strong&gt;&lt;br&gt;
In this blog, we'll explore how to dynamically generate a sitemap in Next.js to enhance your website’s SEO and keep the sitemap updated as your content changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next JS&lt;/strong&gt;&lt;br&gt;
Next.js is a powerful React framework that offers developers several key features for building scalable and optimized web applications. With features like server-side rendering (SSR), static site generation (SSG), and API routes, Next.js allows developers to create high-performance websites with ease. The framework is also known for its file-based routing system and easy integration with popular tools, making it a popular choice for modern web development.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is a sitemap and why?&lt;/strong&gt;&lt;br&gt;
A sitemap is a file that lists all the important URLs of your website, making it easier for search engines like Google to crawl and understand the structure of your site. Sitemaps can also include additional metadata like when a page was last updated, how frequently it changes, and its importance relative to other pages on the site. By generating a dynamic sitemap in Next.js, you ensure that your sitemap automatically reflects any new content, such as blog posts or dynamic routes, keeping search engines up to date and boosting your website's SEO.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to create?&lt;/strong&gt;&lt;br&gt;
Create a sitemap.ts or js file in your next js app directory.&lt;/p&gt;

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

&lt;p&gt;Create and export a function named sitemap.&lt;br&gt;
&lt;/p&gt;

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

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

&lt;/div&gt;



&lt;p&gt;Create one more function to fetch all routes created in your project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fs from "fs";
import { MetadataRoute } from "next";
import path from "path";

const baseUrl = process.env.SITE_URL || "http:localhost:3000";
const baseDir = "src/app";
const excludeDirs = ["api", "fonts"];

export const revalidate = 3600 // revalidate at most every hour


async function getRoutes(): Promise&amp;lt;MetadataRoute.Sitemap&amp;gt; {
  const fullPath = path.join(process.cwd(), baseDir);
  const entries = fs.readdirSync(fullPath, { withFileTypes: true });
  let routes: string[] = ["/"];

  entries.forEach((entry) =&amp;gt; {
    if (entry.isDirectory() &amp;amp;&amp;amp; !excludeDirs.includes(entry.name)) {
      routes.push(`/${entry.name}`);
    }
  });

  return routes.map((route) =&amp;gt; ({
    url: `${baseUrl}${route}`,
    lastModified: new Date(),
    changeFrequency: "weekly",
    priority: 1.0,
  }));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code block &lt;strong&gt;&lt;em&gt;baseDir&lt;/em&gt;&lt;/strong&gt; is the directory where your routes are created that will be mostly &lt;strong&gt;app/src&lt;/strong&gt;. &lt;strong&gt;&lt;em&gt;excludeDirs&lt;/em&gt;&lt;/strong&gt; are used to specify which are the directories that need to be excluded while creating our routes array. &lt;strong&gt;&lt;em&gt;routes&lt;/em&gt;&lt;/strong&gt; array is the array that includes all our route's names. For eg: ["about", "blog"]&lt;/p&gt;

&lt;p&gt;This code will create a sitemap for all static pages. But what if we have dynamic pages like todo/:id? For this, we need to fetch our dynamic data and make its route here, and append it to the routes array. The below function will do that job.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  // to create dynamic routes.
  async function getBlogs() {
    const data = await fetch("https://jsonplaceholder.typicode.com/todos");
    const todos = await data.json();
    console.log(todos, "todos");
    const todoRoutes: string[] = todos.map(
      (todo: any) =&amp;gt; `/todo/${todo.id}`
    );
    routes = [...routes, ...todoRoutes];
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we need to call the getRoutes function from the sitemap function that we created in the beginning. Below is the entire code for the process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fs from "fs";
import { MetadataRoute } from "next";
import path from "path";

const baseUrl = process.env.SITE_URL || "http:localhost:3000";
const baseDir = "src/app";
const excludeDirs = ["api", "fonts"];

export const revalidate = 3600 // revalidate at most every hour


async function getRoutes(): Promise&amp;lt;MetadataRoute.Sitemap&amp;gt; {
  const fullPath = path.join(process.cwd(), baseDir);
  const entries = fs.readdirSync(fullPath, { withFileTypes: true });
  let routes: string[] = ["/"];

  entries.forEach((entry) =&amp;gt; {
    if (entry.isDirectory() &amp;amp;&amp;amp; !excludeDirs.includes(entry.name)) {
      routes.push(`/${entry.name}`);
    }
  });

  // to create dynamic routes.
  async function getBlogs() {
    const data = await fetch("https://jsonplaceholder.typicode.com/todos");
    const todos = await data.json();
    console.log(todos, "todos");
    const todoRoutes: string[] = todos.map(
      (todo: any) =&amp;gt; `/todo/${todo.id}`
    );
    routes = [...routes, ...todoRoutes];
  }

  await getBlogs();

  return routes.map((route) =&amp;gt; ({
    url: `${baseUrl}${route}`,
    lastModified: new Date(),
    changeFrequency: "weekly",
    priority: 1.0,
  }));
}

export default function sitemap() {
  return getRoutes();
}

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

&lt;/div&gt;



&lt;p&gt;Now run the project using&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;and go to *&lt;em&gt;&lt;a href="http://localhost:3000/sitemap.xml" rel="noopener noreferrer"&gt;http://localhost:3000/sitemap.xml&lt;/a&gt; *&lt;/em&gt; There you can see a XML file that includes the the route names and other options that you set for generating the sitemap.&lt;/p&gt;

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

&lt;p&gt;This post will guide you through creating a dynamic sitemap in Next.js. The logic presented here is tailored to my specific use case, but feel free to adapt it as needed. If you encounter any issues or have suggestions, please don't hesitate to leave a comment. I'm always open to feedback and improvement. Thank you for taking the time to read this!&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>sitemap</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
