Applying SSG to a Next.js Project

Bumgu

2024/02/11

Tags: next.js ssg typescript

My website is built with Next.js. Although the Project and Career tabs here are small web pages, I wanted to try pre-rendering them with SSG, so I gave it a try.

I’ll apply it to this page.


1. Existing code

import thumbnailLively from '../public/images/works/Lively_main.png';
import thumbnailWhatCandy from '../public/images/works/whatCandy.png';
import thumbnailSpotify from '../public/images/works/know-your-spotify.png';


const Projects = () => {
  return (
    <Container>
      <Heading as="h3" fontSize={20} mb={4}>
        Projects
      </Heading>
      <Layout title="works">
        <Section>
          <ProjectGridItem title="Lively" thumbnail={thumbnailLively} gitRepo="Lively">
              Description...
          </ProjectGridItem>
        </Section>
        <Section>
          <ProjectGridItem title="what candy" thumbnail={thumbnailWhatCandy} gitRepo="what-candy">
              Description...
          </ProjectGridItem>
        </Section>
        <Section>
          <ProjectGridItem title="know your Spotify" thumbnail={thumbnailSpotify} gitRepo="know-your-spotify">
              Description...
          </ProjectGridItem>
        </Section>
      </Layout>
    </Container>
  );
};

Previously, I passed prop values to components and rendered them as shown above.

To apply SSG, we need to:

First, let’s prepare the data.

2. Define the types

I’ll create a types folder and define the types in it. The ProjectGridItem component needs these properties: title: Project title thumbnail: Project thumbnail description: Project description (below the thumbnail) gitRepo: The GitHub address to navigate to when clicked

type GridItemProps = {
  title: string;
  thumbnail: StaticImageData;
  description: string;
};

export type WorkGridItemProps = GridItemProps & {
  gitRepo: string;
};

There is also a Career page, but it doesn’t need the gitRepo property, so I defined the WorkGridItemProps type by declaring and extending GridItemProps.

3. Prepare the data

I’ll separate the values that were originally placed on the Project page and manage them as an array.

import { WorkGridItemProps } from '../../types/types';

import thumbnailLively from '../../public/images/works/Lively_main.png';
import thumbnailWhatCandy from '../../public/images/works/whatCandy.png';
import thumbnailSpotify from '../../public/images/works/know-your-spotify.png';

export const projectGridItemData: WorkGridItemProps[] = [
  {
    title: 'Lively',
    thumbnail: thumbnailLively,
    gitRepo: 'Lively',
    description: 'Description...'
  },
  {
    title: 'what candy',
    thumbnail: thumbnailWhatCandy,
    gitRepo: 'what-candy',
    description: 'Description...'
  },
  {
    title: 'know your spotify',
    thumbnail: thumbnailSpotify,
    gitRepo: 'know-your-spotify',
    description: 'Description...'
  },
];

Import the WorkGridItemProps type defined in step 2 and declare that this is an array of WorkGridItemProps.

4. Fetch data with getStaticProps()

Now that the type is defined and the data is ready, let’s use getStaticProps() to retrieve the data.

import { projectGridItemData } from '../data/projects/projectData';
import { WorkGridItemProps } from '../types/types';

export const getStaticProps: GetStaticProps = () => {
  return {
    props: { projectGridItemData },
  };
};

There’s no need to communicate using fetch or axios; since we’re retrieving static data from a folder, we import it and pass it as the return value of getStaticProps(). This runs getStaticProps() at build time.

5. Render using the return value of getStaticProps()

Now that we’ve received the data as props, we can render it.

const Projects = ({ projectGridItemData }) => {
  return (
    <Container>
      <Heading as="h3" fontSize={20} mb={4}>
        Projects
      </Heading>
      <Layout title="works">
        {projectGridItemData.map((item: WorkGridItemProps, index: number) => (
          <Section key={index}>
            <ProjectGridItem
              title={item.title}
              thumbnail={item.thumbnail}
              gitRepo={item.gitRepo}
              description={item.description}
            />
          </Section>
        ))}
      </Layout>
    </Container>
  );
};

Since the data is declared as an array of objects, I used Array.map() to render each project and reduce repeated component markup. The Project page now has SSG applied using getStaticProps().

6. Comparing the code before and after

Before

const Projects = () => {
  return (
    <Container>
      <Heading as="h3" fontSize={20} mb={4}>
        Projects
      </Heading>
      <Layout title="works">
        <Section>
          <ProjectGridItem title="Lively" thumbnail={thumbnailLively} gitRepo="Lively">
            Description...
          </ProjectGridItem>
        </Section>
        <Section>
          <ProjectGridItem title="what candy" thumbnail={thumbnailWhatCandy} gitRepo="what-candy">
            Description...
          </ProjectGridItem>
        </Section>
        <Section>
          <ProjectGridItem title="know your Spotify" thumbnail={thumbnailSpotify} gitRepo="know-your-spotify">
            Description...
          </ProjectGridItem>
        </Section>
      </Layout>
    </Container>
  );
};
export default Projects;

After

export const getStaticProps: GetStaticProps = () => {
  return {
    props: { projectGridItemData},
  };
};

const Projects = ({ projectGridItemData }) => {
  return (
    <Container>
      <Heading as="h3" fontSize={20} mb={4}>
        Projects
      </Heading>
      <Layout title="works">
        {projectGridItemData.map((item: WorkGridItemProps, index: number) => (
          <Section key={index}>
            <ProjectGridItem
              title={item.title}
              thumbnail={item.thumbnail}
              gitRepo={item.gitRepo}
              description={item.description}
            />
          </Section>
        ))}
      </Layout>
    </Container>
  );
};

export default Projects;

Closing thoughts

In my case, I only have three components to place on the page, but if there were 10 or 20, there would be a lot of repeated code. SSG provides pre-rendered HTML for fast initial loading and SEO, while keeping the data in an array lets us replace repeated component markup with a single map() call. That’s all for today’s post. Thank you.

>> Home