웹사이트 검색

Ghost 및 Next.js로 블로그를 구축하는 방법


저자는 Write for DOnations 프로그램을 선택했습니다.

소개

블로그는 지식, 경험 또는 뉴스를 다른 사람과 공유하는 매체입니다. Ghost는 최신 블로그 또는 출판물을 만들고 실행할 수 있는 오픈 소스 플랫폼입니다.

Ghost는 프런트엔드에 사용할 수 있는 템플릿을 제공하지만 사용자 지정 기능을 디자인하고 추가하는 데는 유연성이 제한적입니다. 생산 최적화, 성능 및 SEO와 같은 문제에 대한 솔루션을 제공하는 React 프레임워크입니다. Next.js는 React로 애플리케이션을 구축할 때 개발자 경험보다 이점을 제공합니다. Ghost와 함께 Next.js를 사용하여 더 나은 성능과 SEO로 정적으로 생성된 블로그를 구축할 수 있습니다. 디자인을 사용자 정의하고 원하는 기능을 추가할 수도 있습니다.

이 튜토리얼에서는 Ghost를 사용하여 기사를 관리하고 Next.js를 사용하여 블로그의 프런트엔드를 구축합니다. 이 접근 방식을 사용하면 블로그의 콘텐츠, 디자인 및 기능을 제어할 수 있습니다. DigitalOcean Marketplace를 사용하여 배포할 수 있는 Ubuntu 서버에서 Ghost를 자체 호스팅하게 됩니다.

전제 조건

이 자습서를 완료하려면 다음이 필요합니다.

  • DigitalOcean 계정. 계정이 없으면 새 계정에 가입하세요.
  • 메모리가 1GB 이상인 Ubuntu 서버에 설치된 Ghost. 수동 설정을 위해 Ghost 설명서를 사용할 수 있습니다.
  • Ghost 블로그를 가리키는 등록된 도메인 이름. 일반 도메인 등록 기관에서 DigitalOcean 이름 서버를 가리키는 방법 가이드에서 DigitalOcean 이름 서버에서 도메인을 설정하는 방법에 대한 지침을 찾을 수 있습니다.
  • Node.js용 로컬 개발 환경입니다. Node.js 설치 및 로컬 개발 환경 생성 방법을 따르십시오.
  • 로컬 컴퓨터의 Next.js 프로젝트. create-next-app에서 라이브러리의 설정 단계를 통해 Next.js 프로젝트를 만들고 구성 기본값을 수락할 수 있습니다.

참고: TypeScript 또는 JavaScript를 사용하여 Next.js 프로젝트를 만들 수 있습니다. 이 자습서는 JavaScript를 사용하지만 둘 중 하나가 작동합니다.

  • Tailwind가 로컬 시스템에 설치되고 Next.js용으로 구성되었습니다. Next.js를 설치한 후 Install Tailwind CSS with Next.js 가이드의 지침을 따르세요.
  • nano와 같은 텍스트 편집기.
  • React.js 시리즈 코딩 방법을 통해 얻을 수 있는 React에 대한 지식

1단계 - Ghost에 게시물 게시

이 단계에서는 Ghost에서 계정을 만들고 다음 단계에서 렌더링할 콘텐츠가 있도록 몇 가지 샘플 기사를 게시합니다.

Ghost를 설치하고 설정하면 블로그를 관리하려면 관리자 계정이 필요합니다. YOUR_DOMAIN/ghost로 이동합니다. 여기서 YOUR_DOMAIN은 Ghost 설치 과정에서 입력한 URL입니다.

계정을 만들도록 초대되는 Ghost 페이지에 오신 것을 환영합니다. 사이트 제목, 이름, 이메일 주소, 비밀번호를 입력하세요. 그런 다음 계정 만들기 및 게시 시작을 누릅니다.

왼쪽 사이드바의 먼저 무엇을 하시겠습니까? 아래에서 첫 게시물 작성 옵션을 선택합니다. 블로그 게시물의 제목과 본문을 입력하고 오른쪽 상단 모서리에 있는 게시를 클릭합니다. 계속, 최종 검토를 누른 다음 바로 지금 게시물 게시 버튼을 클릭합니다.

대시보드를 보려면 YOUR_DOMAIN/ghost로 이동하세요. 왼쪽 사이드바에서 사이트 보기를 선택하여 사이트의 실시간 미리보기를 확인합니다.

이 자습서의 뒷부분에서 웹 사이트에 여러 블로그 게시물을 렌더링합니다. 대시보드에서 왼쪽 사이드바의 게시물을 선택하여 블로그 게시물을 두 개 더 만듭니다. 나중에 알아볼 수 있도록 고유한 이름을 지정하십시오.

이 단계에서는 Ghost 및 게시된 블로그 게시물에 관리자 페이지를 설정합니다. 귀하의 블로그는 현재 Ghost에서 제공하는 기본 템플릿을 사용하고 있습니다. 다음 단계에서는 더 많은 디자인 유연성을 제공하는 Next.js 프로젝트를 생성합니다. Ghost를 콘텐츠 관리 시스템(CMS)으로 사용하고 Next.js를 사용하여 프런트엔드를 구축합니다.

2단계 — Next.js 프로젝트 만들기

이제 블로그에 Ghost가 준비되었습니다. 이 단계에서는 Next.js를 사용하여 블로그의 프런트엔드를 만들고 Tailwind CSS를 사용하여 스타일을 추가합니다.

선호하는 코드 편집기에서 생성한 Next.js 프로젝트를 엽니다. pages/index.js 파일을 엽니다.

  1. nano pages/index.js

파일에서 기존 코드를 삭제하고 다음을 추가하여 next/head에서 Head 구성 요소를 가져오고 React 구성 요소를 만듭니다.

import Head from 'next/head';

export default function Home() {
	return (
	);
}

Head 구성 요소를 사용하면 HTML 내에서 사용하는 <title><meta>와 같은 태그를 추가할 수 있습니다.

Head 구성 요소를 기반으로 빌드하려면 <div> 태그가 포함된 return 문을 추가합니다. <div> 태그 내에 <title> 태그를 추가합니다. 코드> 태그:

...
return (
	<div>
	     <Head>
	            <title>My First Blog</title>
	            <meta name="description" content="My personal blog created with Next.js and Ghost" />
            </Head>
	</div>
);
...

<title> 태그는 웹 페이지의 제목을 My First Blog로 설정합니다. <meta> 태그는 name 속성이 description으로 설정되고 content 속성이 <로 설정됩니다.Next.js와 Ghost로 만든 내 개인 블로그. 이 제목과 설명은 웹사이트 미리보기에 표시됩니다.

이제 제목과 설명을 설정했으므로 기사 목록이 표시됩니다. 이 코드 스니펫은 당분간 모의 데이터를 사용합니다. 다음 섹션에서는 Ghost에서 블로그 게시물을 가져옵니다. 태그 아래에 <li> 태그를 사용하여 기사 목록을 추가합니다.

...
<div>
	<Head>
	...
	</Head>
	<main className="container mx-auto py-10">
		<h1 className="text-center text-3xl">My Personal Blog</h1>
		<div className="flex justify-center mt-10 ">
			<ul className="text-xl">
				<li>How to build and deploy your blog on DigitalOcean</li>
				<li>How to style a Next.js website</li>
				<li>How to cross-post your articles automatically</li>
			</ul>
		</div>
	</main>
</div>
...

이제 헤더와 <div> 태그가 포함된 <main> 태그를 추가했습니다. <div> 태그에는 여러 모의 기사 제목이 있는 정렬되지 않은 목록이 포함되어 있습니다. <main>, <h1>, <div><ul> 태그에는 각각 className 속성. 여기에는 Tailwind 스타일 클래스가 포함됩니다.

index.js 파일은 이제 다음과 같아야 합니다.

import Head from 'next/head';

export default function Home() {
	return (
		<div>
			<Head>
				<title>My First Blogp</title>
				<meta
					name="description"
					content="My personal blog created with Next.js and Ghost"
				/>
			</Head>
			<main className="container mx-auto py-10">
				<h1 className="text-center text-3xl">My Personal Blog</h1>
				<div className="flex justify-center mt-10 ">
					<ul className="text-xl">
						<li>How to build and deploy your blog on DigitalOcean</li>
						<li>How to style a Next.js website</li>
						<li>How to cross-post your articles automatically</li>
					</ul>
				</div>
			</main>
		</div>
	);
}

파일을 저장하고 닫습니다.

웹 서버를 로컬에서 시작합니다. Yarn을 사용하는 경우 다음 명령을 실행합니다.

  1. yarn dev

npm을 사용하는 경우 다음 명령을 실행합니다.

  1. npm run dev

브라우저에서 https://localhost:3000으로 이동하면 모의 데이터에서 블로그 기사 목록을 찾을 수 있습니다. 홈페이지는 다음과 유사하게 표시됩니다.

이 단계에서는 블로그의 페이지를 만들고 모의 기사 목록을 추가했습니다. 다음 단계에서는 Ghost에서 블로그 게시물을 가져옵니다.

3단계 - Ghost에서 모든 블로그 게시물 가져오기

이 단계에서는 Ghost에서 만든 블로그 게시물을 가져와서 브라우저에서 렌더링합니다.

Ghost에서 기사를 가져오려면 먼저 Ghost Content API용 JavaScript 라이브러리를 설치해야 합니다. 바로 가기 키 CTRL+C를 사용하여 서버를 중지합니다. 터미널에서 다음 명령을 실행하여 라이브러리를 설치합니다.

Yarn을 사용하는 경우 다음 명령을 실행합니다.

  1. yarn add @tryghost/content-api

npm을 사용하는 경우 다음 명령을 실행합니다.

  1. npm i @tryghost/content-api

라이브러리가 성공적으로 설치되면 이제 블로그 게시물을 가져오는 로직을 저장할 파일을 생성합니다. pages 디렉터리에서 utils라는 새 폴더를 만듭니다.

  1. mkdir utils

해당 폴더 내에 ghost.js라는 새 파일을 만듭니다.

  1. nano pages/utils/ghost.js

ghost.js 파일에서 Ghost Content API 라이브러리의 GhostContentAPI 모듈을 가져옵니다. GhostContentAPI에 대한 새 개체를 초기화하고 값을 상수 변수 api에 저장합니다. 호스트, API 키 및 버전에 대한 값을 전달해야 합니다. 코드는 다음과 같습니다.

import GhostContentAPI from "@tryghost/content-api";

const api = new GhostContentAPI({
	url: `YOUR_URL`,
	key: `YOUR_API_KEY`,
	version: 'v5.0'
});

YOUR_URL의 값은 프로토콜을 포함하여 Ghost를 설치할 때 구성한 도메인 이름이며 대부분 https://입니다.

Ghost API 키를 찾으려면 다음 단계를 따르십시오.

  1. YOUR_DOMAIN/ghost(여기서 YOUR_DOMAIN는 구성한 URL임)로 이동하고 관리자 자격 증명.
  2. 왼쪽 사이드바 하단에 있는 톱니바퀴 아이콘을 눌러 설정 페이지에 액세스합니다.
  3. 고급 카테고리의 왼쪽 사이드바에서 통합을 클릭합니다. 통합 페이지가 나타나고 가능한 통합 목록과 하단에 맞춤 통합이 표시됩니다.
  4. + 사용자 지정 통합 추가를 누릅니다. 통합 이름을 지정하라는 팝업이 나타납니다.
  5. 이름 필드에 통합 이름을 입력하고 만들기를 클릭합니다. 이렇게 하면 맞춤 통합을 구성할 수 있는 페이지로 이동합니다.
  6. 표시된 Content API 키(Admin API 키 아님)를 복사합니다.
  7. 저장을 눌러 사용자 지정 통합을 저장합니다.

ghost.js 파일에서 YOUR_API_KEY를 복사한 API 키로 바꿉니다.

이제 GhostContentAPI를 초기화했으므로 Ghost 설치에서 모든 기사를 가져오는 비동기 함수를 작성합니다. 이 기능은 태그에 관계없이 블로그 게시물을 가져옵니다. 다음 코드를 복사하여 ghost.js 파일에 붙여넣습니다.

...
export async function getPosts() {
  return await api.posts
    .browse({
        include:"tags",
        limit: "all"
    })
    .catch(err => {
      console.error(err);
    });
}

Promise가 해결된 후 getPosts() 비동기 함수는 블로그 게시물을 반환합니다. GhostContentAPIposts.browse() 메서드를 사용하고 includelimit 매개변수를 사용합니다. 콘텐츠와 함께 태그를 가져오도록 include 값을 tags로 설정했습니다. limit 값은 all로 설정되어 모든 블로그 게시물을 가져옵니다. 오류가 발생하면 브라우저 콘솔에 기록됩니다.

이 시점에서 api/ghost.js 파일에는 다음 코드가 포함되어 있습니다.

import GhostContentAPI from '@tryghost/content-api';

const api = new GhostContentAPI({
	url: `YOUR_URL`,
	key: `YOUR_API_KEY`,
	version: 'v5.0',
});

export async function getPosts() {
	return await api.posts
		.browse({
			include: 'tags',
			limit: 'all',
		})
		.catch((err) => {
			console.error(err);
		});
}

파일을 저장하고 닫습니다.

게시물 목록을 표시하려면 index.js 파일을 엽니다. 다음 강조 표시된 줄을 추가하여 Head 가져오기 위에 getPosts 함수를 가져옵니다.

import { getPosts } from './utils/ghost';
import Head from 'next/head';

…

이제 Next.js가 빌드 시 페이지를 사전 렌더링할 수 있도록 하는 비동기 함수(getStaticProps())를 생성합니다. 이 기능은 정적 생성을 활용하려는 경우에 유용합니다.

Home 구성 요소 다음에 비동기 함수 getStaticProps()를 만들고 함수 본문 내에서 getPosts() 메서드를 호출합니다. getPosts() 메서드에서 props 값을 반환합니다. 코드는 다음과 같아야 합니다.

...
export async function getStaticProps() {
	const posts = await getPosts();
	return { props: { posts } };
}

파일을 저장합니다.

이제 getStaticProps() 메서드가 정의되었으므로 Yarn을 사용하는 경우 npm run dev 또는 yarn dev를 사용하여 서버를 다시 시작합니다.

브라우저에서 페이지는 여전히 정적 데이터를 표시합니다. 이 페이지는 Ghost에서 가져온 데이터를 표시하지 않습니다. 값을 가져오지만 렌더링하지는 않기 때문입니다.

Home 구성 요소가 Ghost에서 검색한 값을 사용할 수 있도록 index.js를 일부 변경합니다.

CTRL-C를 눌러 서버를 중지한 다음 편집을 위해 index.js를 엽니다.

  1. nano pages/index.js

index.js에 다음과 같이 강조 표시된 변경 사항을 적용합니다.

export default function Home({posts}) {
	return (
		<div>
			<Head>
				<title>My First Blog</title>
				<meta
					name="description"
					content="My personal blog created with Next.js and Ghost"
				/>
			</Head>
			<main className="container mx-auto py-10">
				<h1 className="text-center text-3xl">My Personal Blog</h1>
				<div className="flex justify-center mt-10 ">
					<ul className="text-xl">
						{posts.map((post) => (
							<li key={post.title}>{post.title}</li>
						))}
					</ul>
				</div>
			</main>
		</div>
	);
}

이 코드에서는 먼저 posts를 분해하고 매개변수로 Home 구성 요소에 전달합니다. 그런 다음 조롱에 사용한 정적 콘텐츠가 포함된 <li> 태그를 블로그 게시물 제목을 가져오는 함수로 바꿉니다.

array.map() 메서드를 사용하여 제목props에서 검색한 posts 컬렉션을 반복합니다. 코드> 각 게시물의. 마지막으로 게시물 제목이 포함된 <li> 태그를 반환합니다.

파일을 저장하고 닫습니다. Yarn을 사용하는 경우 npm run dev 또는 yarn dev를 사용하여 서버를 다시 시작합니다.

localhost:3000으로 다시 이동합니다. 이제 블로그가 Ghost의 기사 목록을 렌더링합니다.

index.js 파일의 코드는 다음과 일치합니다.

import { getPosts } from './utils/ghost';
import Head from 'next/head';

export default function Home({ posts }) {
	return (
		<div>
			<Head>
				<title>My First Blog</title>
				<meta
					name="description"
					content="My personal blog created with Next.js and Ghost"
				/>
			</Head>
			<main className="container mx-auto py-10">
				<h1 className="text-center text-3xl">My Personal Blog</h1>
				<div className="flex justify-center mt-10 ">
					<ul className="text-xl">
						{posts.map((post) => (
							<li key={post.title}>{post.title}</li>
						))}
					</ul>
				</div>
			</main>
		</div>
	);
}

export async function getStaticProps() {
	const posts = await getPosts();
	return { props: { posts } };
}

홈페이지는 다음과 유사하게 나타납니다.

이제 블로그가 CMS에서 게시물 제목을 검색하여 표시했습니다. 그러나 여전히 개별 게시물을 표시하지 않습니다. 다음 섹션에서는 동적 경로를 만들고 게시물의 콘텐츠를 렌더링합니다.

4단계 - 각 개별 게시물 렌더링

이 단계에서는 Ghost에서 각 블로그 게시물의 내용을 가져오고, 동적 경로를 만들고, 게시물 제목을 홈 페이지의 링크로 추가하는 코드를 작성합니다.

Next.js에서 동일한 레이아웃으로 페이지를 렌더링할 수 있는 동적 경로를 만들 수 있습니다. 동적 경로는 구성 요소를 재사용하여 코드 중복을 줄이는 데 도움이 됩니다. 동적 경로를 생성하면 모든 게시물이 렌더링에 동일한 파일을 사용합니다. 모든 게시물에 대해 페이지를 만들 필요는 없습니다.

동적 경로를 만들고 개별 게시물을 렌더링하려면 다음을 수행해야 합니다.

  1. 블로그 게시물의 내용을 가져오는 함수를 작성합니다.
  2. 동적 경로를 만듭니다.
  3. 항목 목록에 블로그 링크를 추가합니다.

ghost.js 파일에서 getPosts() 함수를 작성하여 모든 블로그 게시물 목록을 가져왔습니다. 이제 슬러그를 기반으로 게시물의 콘텐츠를 가져오는 getSinglePost() 함수를 작성합니다.

Ghost는 제목을 사용하여 기사에 대한 슬러그를 자동으로 생성합니다. 예를 들어 기사 제목이 "My First Post\인 경우 Ghost는 my-first-post를 슬러그로 생성합니다. 이 슬러그는 기사를 식별하는 데 도움이 되며 다음을 위해 도메인 URL에 추가할 수 있습니다. 내용을 표시합니다.

getSinglePost() 함수는 postSlug를 매개변수로 사용하고 해당 블로그 게시물의 내용을 반환합니다.

아직 실행 중인 경우 서버를 중지한 다음 편집을 위해 pages/utils/ghost.js를 엽니다.

ghost.js 파일의 getPosts() 함수 아래에서 async 함수 getSinglePost()를 추가하고 내보냅니다. .

...
export async function getSinglePost(postSlug) {
    return await api.posts
      .read({
        slug: postSlug
      })
      .catch(err => {
        console.error(err);
      });
  }

getSinglePost() 함수는 GhostContentAPIposts.read() 메서드를 사용하고 postSlug 매개변수를 posts.read() 메소드.

최종 /utils/ghost.js 파일에는 다음 코드가 포함되어 있습니다.

import GhostContentAPI from '@tryghost/content-api';

const api = new GhostContentAPI({
	url: `YOUR_URL`,
	key: `YOUR_API_KEY`,
	version: 'v5.0',
});

export async function getPosts() {
	return await api.posts
		.browse({
			include: 'tags',
			limit: 'all',
		})
		.catch((err) => {
			console.error(err);
		});
}

export async function getSinglePost(postSlug) {
    return await api.posts
      .read({
        slug: postSlug
      })
      .catch(err => {
        console.error(err);
      });
  }

파일을 저장하고 닫습니다.

Next.js에서 파일 이름([param])에 대괄호를 추가하여 동적 경로를 만들 수 있습니다. 예를 들어 /post/[slug].js는 동적 경로를 생성합니다.

pages 디렉토리 내에서 /post/[slug].js라는 새 파일을 만듭니다.

nano pages/post/\[slug\].js

참고: nano 명령은 bash가 이름에 대괄호가 있는 파일을 생성하는 데 필요한 백슬래시(\\)로 이스케이프된 대괄호를 표시합니다.

파일 이름 [slug].js/post/ 경로 뒤의 문자열과 일치합니다. Next.js는 빌드 시간 동안 모든 게시물에 대한 페이지를 생성합니다.

/post/[slug].js 파일에서 getPosts()getSinglePost() 함수를 모두 가져옵니다. ./utils/ghost.js 파일.

/post/[slug].js 파일에는 게시물에 대한 템플릿도 포함되어 있습니다. /post/[slug].js 파일에 다음 코드를 추가합니다.

import { getPosts, getSinglePost } from '../utils/ghost';

export default function PostTemplate(props) {
	const { post } = props;
	const { title, html, feature_image } = post;
	return (
		<main className="container mx-auto py-10">
			<h1 className="text-center text-3xl">{title}</h1>
			<article
				className="mt-10 leading-7 text-justify"
				dangerouslySetInnerHTML={{ __html: html }}
			/>
		</main>
	);
}

export const getStaticProps = async ({ params }) => {
	const post = await getSinglePost(params.slug);
	return {
		props: { post },
	};
};

PostTemplate() 함수는 기능적 구성요소를 생성합니다. 함수에서 props에서 post 개체를 추출하고 title, htmlfeature_image를 post 개체에서 가져옵니다. 구성 요소는 페이지를 만드는 데 사용되는 HTML을 반환합니다.

Ghost API는 블로그 콘텐츠를 HTML로 반환하기 때문에 <article> 태그에는 post 객체에서 추출한 HTML 값과 함께 dangerouslySetInnerHTML 속성이 포함됩니다. . dangerouslySetInnerHTML 속성은 브라우저 DOM에서 innerHTML을 사용하기 위한 React의 대체물입니다. HTML이 신뢰할 수 없는 출처에서 오는 경우 HTML을 dangerouslySetInnerHTML 속성에 전달하기 전에 삭제해야 합니다.

getStaticProps() 비동기 함수는 슬러그에 해당하는 블로그 게시물의 콘텐츠를 가져옵니다.

콘텐츠를 URL과 올바르게 매핑하려면 Next.js가 경로 값을 알아야 합니다(귀하의 경우 slug). getStaticPaths() 함수를 사용하여 이 작업을 수행할 수 있습니다. getStaticProps() 함수와 유사하게 getStaticPaths()라는 비동기 함수를 작성하여 슬러그 목록을 반환합니다. [slug].js 파일 끝에 다음 함수를 추가합니다.

...
export const getStaticPaths = async () => {
	const allPosts = await getPosts();
	return {
		paths: allPosts.map(({ slug }) => {
			return {
				params: { slug },
			};
		}),
		fallback: false,
	};
};

참고: fallback 값을 false로 설정하면 getStaticPaths()에서 반환되지 않는 모든 경로는 404 페이지가 됩니다.

/post/[slug].js 파일은 다음과 같아야 합니다.

import { getPosts, getSinglePost } from '../utils/ghost';

export default function PostTemplate(props) {
	const { post } = props;
	const { title, html, feature_image } = post;
	return (
		<main className="container mx-auto py-10">
			<h1 className="text-center text-3xl">{title}</h1>
			<article
				className="mt-10 leading-7 text-justify"
				dangerouslySetInnerHTML={{ __html: html }}
			/>
		</main>
	);
}

export const getStaticProps = async ({ params }) => {
	const post = await getSinglePost(params.slug);
	return {
		props: { post },
	};
};

export const getStaticPaths = async () => {
	const allPosts = await getPosts();
	return {
		paths: allPosts.map(({ slug }) => {
			return {
				params: { slug },
			};
		}),
		fallback: false,
	};
};

파일을 저장하고 닫습니다. Yarn을 사용하는 경우 npm run dev 또는 yarn dev를 사용하여 서버를 다시 시작합니다.

localhost:3000/post/SLUG로 이동하여 SLUG를 블로그 게시물 중 하나에 해당하는 슬러그로 바꿉니다. . 이제 브라우저에서 렌더링된 <^에 해당하는 게시물의 블로그 콘텐츠에 액세스할 수 있습니다.

지금은 게시물에 접근하기 위해 URL을 수동으로 입력해야 하는 불편함이 있습니다. 홈 페이지에서 게시물로 이동할 수 있는 항목 목록에 하이퍼링크를 추가하여 문제를 해결할 수 있습니다.

아직 실행 중인 경우 서버를 중지하고 편집을 위해 pages/index.js를 다시 엽니다.

다음과 같이 index.js의 강조 표시된 섹션을 편집하여 가져오기 및 링크 구성 요소를 추가합니다.

import { getPosts } from './utils/ghost';
import Head from 'next/head';
import Link from 'next/link';

export default function Home(props) {
	return (
		<div>
			<Head>
				<title>My First Blog</title>
				<meta
					name="description"
					content="My personal blog created with Next.js and Ghost"
				/>
			</Head>
			<main className="container mx-auto py-10">
				<h1 className="text-center text-3xl">My Personal Blog</h1>
				<div className="flex justify-center mt-10 ">
				<ul className="text-xl">
					{props.posts.map((post) => (
						<li key={post.title}>
							<Link href={`post/${post.slug}`}>{post.title}</Link>
						</li>
					))}
				</ul>
				</div>
			</main>
		</div>
	);
}

export async function getStaticProps() {
	const posts = await getPosts();
	return { props: { posts } };
}

Next.js는 클라이언트 쪽 라우팅을 허용하는 Link 구성 요소를 제공합니다. index.js 파일에서 next/link에서 Link 구성 요소를 가져옵니다. <li> 태그 내에서 Link 구성 요소에 게시물 제목을 중첩합니다. HTML의 앵커 태그와 마찬가지로 Link 태그도 href 속성을 사용합니다. 슬러그를 href 속성 값으로 전달합니다.

파일을 저장하고 npm run dev 또는 yarn dev 명령을 실행하여 개발 서버를 다시 시작합니다.

브라우저에서 localhost:3000으로 이동합니다. 이제 게시물 제목을 클릭하면 해당 블로그 게시물로 이동합니다. 블로그 페이지는 다음과 같이 표시됩니다.

1단계에서 제공한 제목 및 본문 콘텐츠와 함께 게시물 페이지가 나타납니다. 여기에 표시된 샘플의 제목은 이 튜토리얼의 소개 콘텐츠와 함께 "DigitalOcean에서 블로그를 구축 및 배포하는 방법\입니다.

이 단계에서는 Ghost CMS에서 개별 게시물 콘텐츠를 검색하고 개별 페이지로 렌더링하고 색인 페이지에서 각 게시물에 연결하는 기능을 추가했습니다. 이제 Ghost에서 기사를 가져오는 완전한 블로그를 만들었습니다.

결론

이 기사에서는 Ghost를 DigitalOcean Droplet에 CMS로 배포했습니다. Next.js를 사용하여 정적으로 생성된 사이트를 만들고 Ghost CMS를 연결하여 Next.js 웹 사이트에 대한 콘텐츠를 제공했습니다. 정적으로 생성된 웹사이트이기 때문에 클라이언트 측에 더 적은 JavaScript를 제공하여 더 나은 성능과 SEO를 얻을 수 있습니다. 또한 TailwindCSS를 사용하여 블로그에 맞춤 디자인을 추가했습니다.

현재 귀하의 블로그는 귀하의 컴퓨터에서 로컬로 실행되고 있습니다. 다음 단계로 Next.js 앱을 앱 플랫폼에 배포할 수 있습니다.

블로그에 더 많은 기능을 추가할 수도 있습니다. 예를 들어 태그를 사용하여 검색 기능을 구현할 수 있습니다.