Next.js에서 RSS 피드 및 사이트맵 생성

Next.js로 새 사이트를 구축하면서 MDX 파일을 소스로 사용하여 RSS 피드와 사이트맵을 계속 제공하는 방법을 찾아야 했습니다. 내 MDX 파일의 구문 분석 및 렌더링에 Hashicorp의 next-mdx-remote 을 사용하고 최신 주 버전인 v3에서는 약간 까다로웠으므로 이것이 도움이 되기를 바랍니다!

RSS 피드



내 Next.js 사이트에 대한 RSS 피드를 생성하기 위해 적절하게 명명된 feed 패키지를 사용하고 이를 dev 종속성으로 설치했습니다.

설치




# Using yarn
yarn add feed -D

# or using NPM
npm install feed --save-dev


구현



그런 다음 내 feeds.tsx 디렉토리에 utils라는 파일을 만들었습니다. 그리고 우리는 이것으로 시작할 것입니다:

import fs from 'fs';
import { Feed } from 'feed';
import { serialize } from 'next-mdx-remote/serialize';
import { MDXRemote } from 'next-mdx-remote';
import { renderToStaticMarkup } from 'react-dom/server';
import { MDXComponents } from '@components/MDX';
import { getPosts } from '@utils/mdx';

const generateFeeds = async () => {

}


거기에서 날짜, 내 이름 및 작성자 정보는 물론 사이트 URL과 같은 몇 가지 기본 데이터로 시작하고 data 디렉토리의 로컬 MDX 파일인 게시물도 가져옵니다.

// ...

const generateFeeds = async () => {
  const domain = process.env.NEXT_PUBLIC_MAIN_DOMAIN || process.env.VERCEL_URL;
  const posts = await getPosts();
  const siteURL = `https://${domain}`;
  const date = new Date();

  const author = {
    name: 'Kevin Langley Jr.',
    email: '[email protected]',
    link: 'https://kevinlangleyjr.dev',
  };
}

// ...


그런 다음 새 Feed 개체를 만들었습니다.

// ...

const feed = new Feed( {
  title: 'Kevin Langley | Web Engineer',
  description: '',
  id: siteURL,
  link: siteURL,
  image: `${siteURL}/kevinlangleyjr.jpg`,
  copyright: `All rights reserved ${date.getFullYear()}, Kevin Langley Jr.`,
  updated: date,
  generator: 'Next.js',
  feedLinks: {
    rss2: `${siteURL}/rss/feed.xml`,
    json: `${siteURL}/rss/feed.json`,
    atom: `${siteURL}/rss/atom.xml`,
  },
  author,
} );

// ...


그런 다음 마침내 피드에 추가하기 위해 게시물을 반복할 수 있습니다. next-mdx-remote 패키지에 대한 최신 변경 사항과 더 이상 v3에서 renderToString 메서드가 없기 때문에 renderToStaticMarkupreact-dom/server를 사용하여 피드에 추가할 마크업을 생성하고 있습니다.

// ...

for ( const post of posts ) {
  const url = `${siteURL}/blog/${post.slug}`;
  const { content, ...postData } = post;
  const mdxSource = await serialize( content, {
    scope: postData as Record<string, any>, // Scope expects a <Record> here.
    mdxOptions: {
      remarkPlugins: [
        // I use a few different remark plugins, check out my "How I built my blog" article for more information!
      ],
    },
  } );

  const markup = renderToStaticMarkup(
    <MDXRemote components={ MDXComponents } { ...mdxSource } />
  );

  feed.addItem(
    {
      title: post.title,
      guid: post.slug,
      id: url,
      link: url,
      description: post.excerpt,
      content: markup,
      author: [author],
 contributor: [author],
 date: new Date( post.published_date ),
    }
);

}

// ...


그런 다음 마침내 해당 피드를 적절한 파일에 쓸 수 있습니다.

// ...

fs.mkdirSync( './public/rss', { recursive: true } );
fs.writeFileSync( './public/rss/feed.xml', feed.rss2() );
fs.writeFileSync( './public/rss/atom.xml', feed.atom1() );
fs.writeFileSync( './public/rss/feed.json', feed.json1() );

// ...


이제 이러한 피드가 빌드 시 자동으로 실행되도록 하려면 어떻게 해야 할까요?

쉬운! 블로그 인덱스의 getStaticProps 메서드에서 호출하기만 하면 빌드 시 생성됩니다. Vercel 플랫폼에서 빌드할 때만 실행되거나 로컬에서 빌드할 때 환경 변수를 전달하는 경우에만 실행되는 VERCEL 환경 변수에 대한 검사로 래핑하고 싶습니다.

// ...

export const getStaticProps: GetStaticProps = async () => {
  const { posts, hasNextPage } = getPostsForPage();

  if ( process.env?.VERCEL ) {
    await generateFeeds();
  }

  return {
    props: {
      posts,
      hasNextPage,
    },
  };
};
// ...


다음은 모든 단계가 완료된 전체feed.tsx 파일입니다.

import fs from 'fs';
import { Feed } from 'feed';
import { serialize } from 'next-mdx-remote/serialize';
import { MDXRemote } from 'next-mdx-remote';
import { renderToStaticMarkup } from 'react-dom/server';
import { MDXComponents } from '@components/MDX';
import { getPosts } from '@utils/mdx';

const generateFeeds = async () => {

  const domain = process.env.NEXT_PUBLIC_MAIN_DOMAIN || process.env.VERCEL_URL;
  const posts = await getPosts();
  const siteURL = `https://${domain}`;
  const date = new Date();
  const author = {
    name: 'Kevin Langley Jr.',
    email: '[email protected]',
    link: 'https://kevinlangleyjr.dev',
  };

  const feed = new Feed( {
    title: 'Kevin Langley | Web Engineer',
    description: '',
    id: siteURL,
    link: siteURL,
    image: `${siteURL}/kevinlangleyjr.jpg`,
    copyright: `All rights reserved ${date.getFullYear()}, Kevin Langley Jr.`,
    updated: date,
    generator: 'Next.js',
    feedLinks: {
      rss2: `${siteURL}/rss/feed.xml`,
      json: `${siteURL}/rss/feed.json`,
      atom: `${siteURL}/rss/atom.xml`,
    },
    author,
} );

for ( const post of posts ) {
  const url = `${siteURL}/blog/${post.slug}`;
  const { content, ...postData } = post;
  const mdxSource = await serialize( content, {
    scope: postData as Record<string, any>, // Scope expects a <Record> here.
    mdxOptions: {
      remarkPlugins: [
        // I use a few different remark plugins, check out my "How I built my blog" article for more information!
      ],
    },
  } );

  const markup = renderToStaticMarkup(
    <MDXRemote components={ MDXComponents } { ...mdxSource } />
  );

  feed.addItem(
    {
      title: post.title,
      guid: post.slug,
      id: url,
      link: url,
      description: post.excerpt,
      content: markup,
      author: [author],
 contributor: [author],
 date: new Date( post.published_date ),
    }
  );

  fs.mkdirSync( './public/rss', { recursive: true } );
  fs.writeFileSync( './public/rss/feed.xml', feed.rss2() );
  fs.writeFileSync( './public/rss/atom.xml', feed.atom1() );
  fs.writeFileSync( './public/rss/feed.json', feed.json1() );
}


사이트맵



사이트맵 기능의 경우 Next.js의 정적, 동적 및 서버 측 페이지에서 사이트맵을 생성하는 간단한 API를 제공하는 next-sitemap를 사용하기로 결정했습니다.

내 사이트에서는 정적 페이지만 사용하고 있지만 동적 또는 서버 측 사이트맵 생성에 관심이 있는 경우 README을 확인할 수 있습니다.

설치




# Using yarn
yarn add next-sitemap -D

# or using NPM
npm install -D next-sitemap


구현



거기에서 next-sitemap.js라는 프로젝트의 루트에 새 파일을 만들고 기본 구성을 제공했습니다. README에서 지원되는 다양한 구성 옵션을 찾을 수 있습니다.

module.exports = {
 siteUrl: `https://${ process.env.VERCEL\_URL }`,
 generateRobotsTxt: true,
};


그런 다음 내 package.json 에서 next-sitemap 스크립트에 postbuild를 추가했습니다.

{
  "build": "next build",
  "postbuild": "next-sitemap"
}


거기에서 프로젝트를 빌드할 때마다 sitemap.xml가 있고 구성에서 generateRobotsTxttrue로 설정하면 robots.txtpublic 디렉토리에 생성됩니다.

이익! 🎉🎉🎉

좋은 웹페이지 즐겨찾기