2

I have an CLS issue with this landing site. The landing site is statically generated in Next.js(SSG) as seen on this photo /.

enter image description here

I must be missing something regarding Next.js SSG. When I open the generated index.html file, not all HTML content is present. When page loads it looks like Next.js is injecting these missing sections on the page load... Shouldn't the entire HTML be statically generated and available in the index.html site? What am I missing or not understanding here?

Here is the data fetching for the page:

import Head from "next/head"
import { 
  Box,
  Center,
  Container,
  Heading,
  Tag,
} from "@chakra-ui/react";
import { request } from "/lib/datocms";
import {
  MAIN_MENU_QUERY,
  BLOG_POSTS_QUERY,
  BLOG_CATEGORIES_QUERY,
  HOME_PAGE_QUERY,
} from "/lib/queries";
import BlockRender from "/components/blocks/BlockRender";
import ChakraNextLink from "/components/atoms/ChakraNextLink";
import BlogGrid from "/components/blog/BlogGrid"
import { renderMetaTags } from "react-datocms";

...

export const getStaticProps = async ({ preview }) => {
  const graphqlRequest = {
    query: MAIN_MENU_QUERY,
    preview
  }
  const data = await request(graphqlRequest);

  const homePageGraphqlRequest = {
    query: HOME_PAGE_QUERY,
    preview
  }
  const homePage = await request(homePageGraphqlRequest);
  const pageData = homePage?.homePage;

  const blogPostsGraphqlRequest = {
    query: BLOG_POSTS_QUERY,
    preview,
    variables: {
      count: homePage.homePage.blogPostCount ?? 0
    }
  }
  const blogPosts = await request(blogPostsGraphqlRequest);

  const blogCategoriesGraphqlRequest = {
    query: BLOG_CATEGORIES_QUERY,
    preview
  }
  const blogCategories = await request(blogCategoriesGraphqlRequest);

  return {
    props: {
      data,
      pageData,
      blogPosts,
      blogCategories
    },
  };
};

Here is the code of my index page:

export default function Home({ data, pageData, blogPosts, blogCategories }) {
  const metaTags = pageData.seo.concat(data.site.favicon);

  return (
    <>
      <Head>
        {renderMetaTags(metaTags)}
      </Head>

      # all this content is not in the generated Index.html file and causes CLS issue
      {pageData.content && 
        pageData.content.map((block, key) => <BlockRender key={key} block={block} />)
      }

      # this is in the generated index.html file
      <Box w="full" py="12">
        {pageData.showBlogSection && (
          <BlogSection posts={blogPosts} categories={blogCategories}>
        )}
      </Box>
    </>
  )
}
Primoz Rome
  • 10,379
  • 17
  • 76
  • 108
  • This site does not open for me (perhaps geoblocked?) - Can you add it to something like codesandbox or stackblitz? CLS is caused by elements that _shift_ so any work the browser does for rendering maybe affecting the outcome as well - your hunch around injected scripts might very well cause it. – Ramakay May 09 '22 at 17:52
  • @Ramakay this does not open for you? -http://gostinskaoprema.eu/. It is hosted on Vercel, so it should work I guess. Works from here. I know what CLS is, but I just don't get it why the page renders as it is currently. All the content should be statically generated and I have heights of element setup. The problem is that the HTML generated in the .map is somehow append to the HTML on page load and I don't know why. – Primoz Rome May 09 '22 at 18:50
  • 1
    @juliomalves pageData comes from a headless CMS via GraphQL request... – Primoz Rome May 11 '22 at 18:35
  • @juliomalves I have updated the code in my answer to see where data is fetched. It is fetched in the same `/pages/index.js` file in the `getStaticProps` ... – Primoz Rome May 13 '22 at 08:50
  • Can you add your imports from your index page? Which `BlockRender` are you using? – zoltankundi May 30 '22 at 15:07
  • @zoltankundi BlockRender is my component that renders blocks to HTML from my headless CMS. I have added imports to my original post. – Primoz Rome May 30 '22 at 17:08

1 Answers1

2

The problem was in the component that dynamically loads components for data from my backend headless CMS. I changed this:

import dynamic from "next/dynamic";

export default function BlockRender({block}) {
  switch(block.__typename) {
    case "ContactSectionRecord":
      const ContactSection = dynamic(() => import("../page/ContactSection"));
      return <ContactSection block={block} />;
    case "StructuredTextSectionRecord":
      const StructuredTextSection = dynamic(() => import("../page/StructuredTextSection"));
      return <StructuredTextSection block={block} />;
    case "VirtualShowroomSectionRecord":
      const VirtualShowroomSection = dynamic(() => import("../page/VirtualShowroomSection"));
      return <VirtualShowroomSection block={block} />;
    case "HeroSectionOneRecord":
      const HeroOneSection = dynamic(() => import("../page/HeroOneSection"));
      return <HeroOneSection block={block} />;  
    case "HeroSectionTwoRecord":
      const HeroTwoSection = dynamic(() => import("../page/HeroTwoSection"));
      return <HeroTwoSection block={block} />;    
    case "PanogaSectionRecord":
      const PanogaSection = dynamic(() => import("../page/PanogaSection"));
      return <PanogaSection block={block} />;    
    case "VirtualShowroomLandingSectionRecord":
      const VirtualShowroomLandingSection = dynamic(() => import("../page/VirtualShowroomLandingSection"));
      return <VirtualShowroomLandingSection block={block} />;    
    case "AktualnaPonudbaSectionRecord":
      const AktualnaPonudbaSection = dynamic(() => import("../page/AktualnaPonudbaSection"));
      return <AktualnaPonudbaSection block={block} />;    
    case "ParalaxSectionRecord":
      const ParalaxSection = dynamic(() => import("../page/ParalaxSection"));
      return <ParalaxSection block={block} />;    
    case "ColumnBlockRecord":
      const ColumnBlockSection = dynamic(() => import("../page/ColumnBlockSection"));
      return <ColumnBlockSection block={block} />;    
    default:
      return <></>
  }
}

into this:

import dynamic from "next/dynamic";

const ContactSection = dynamic(() => import("../page/ContactSection"));
const StructuredTextSection = dynamic(() => import("../page/StructuredTextSection"));
const VirtualShowroomSection = dynamic(() => import("../page/VirtualShowroomSection"));
const HeroOneSection = dynamic(() => import("../page/HeroOneSection"));
const HeroTwoSection = dynamic(() => import("../page/HeroTwoSection"));
const PanogaSection = dynamic(() => import("../page/PanogaSection"));
const VirtualShowroomLandingSection = dynamic(() => import("../page/VirtualShowroomLandingSection"));
const AktualnaPonudbaSection = dynamic(() => import("../page/AktualnaPonudbaSection"));
const ParalaxSection = dynamic(() => import("../page/ParalaxSection"));
const ColumnBlockSection = dynamic(() => import("../page/ColumnBlockSection"));

export default function BlockRender({block}) {
  switch(block.__typename) {
    case "ContactSectionRecord":
      return <ContactSection block={block} />;
    case "StructuredTextSectionRecord":
      return <StructuredTextSection block={block} />;
    case "VirtualShowroomSectionRecord":
      return <VirtualShowroomSection block={block} />;
    case "HeroSectionOneRecord":
      return <HeroOneSection block={block} />;  
    case "HeroSectionTwoRecord":
      return <HeroTwoSection block={block} />;    
    case "PanogaSectionRecord":
      return <PanogaSection block={block} />;    
    case "VirtualShowroomLandingSectionRecord":
      return <VirtualShowroomLandingSection block={block} />;    
    case "AktualnaPonudbaSectionRecord":
      return <AktualnaPonudbaSection block={block} />;    
    case "ParalaxSectionRecord":
      return <ParalaxSection block={block} />;    
    case "ColumnBlockRecord":
      return <ColumnBlockSection block={block} />;    
    default:
      return <></>
  }
}

The CLS droped from 0.85 to 0.1.

I hope this answers helps someone with similar issue.

Primoz Rome
  • 10,379
  • 17
  • 76
  • 108