추석동안 oopy.io 결제하기 싫어서 직접 만든 노션 연동 웹사이트
우피는 웹사이트 빌더중에 단언컨대 최고입니다. 하지만 최대한 돈을 아껴쓰고 싶은 저에게 oopy 도메인을 사서 결제까지 하는건 사치라고 생각했습니다.
추석 한 주 내내 10X AI University 런칭을 위해 웹사이트를 빌딩했는데, 각 커리큘럼 챕터 별로 방대한 양의 컨텐츠 내용들을 직접 Next js와 Tailwind 프론트엔드 개발을 해서 올릴 걸 생각하니 머릿속이 하얘지더라구요.
어떻게 하면 oopy를 사용하지 않고 노션에 올린 내용을 바로 내 웹사이트 도메인에 올릴 수 있을까?
oopy에 웹사이트 연동을 하기 위해서는 무조건 Notion 사이트를 공개로 돌려야 하는데 저 같은 경우에는 유료 회원들만 내용을 접하게 하고 싶었기 때문에 공개로 돌릴 수 없었습니다.
그래서 인터넷을 뒤지다가 몇일동안 할 일을 하루만에 단축시켜준 개발 package를 발견했습니다.
바로 이겁니다: https://github.com/kerwanp/notion-render
노션 데이터베이스에 작성하는 모든 컨텐츠들을 바로 노션 스타일 형식처럼 렌더링해서 Next js 앱에 보여지게 하는 툴입니다.
이 글에서 직접 활용하는 것까지 개발 과정을 공유해드리겠습니다!
1. 노션 데이터베이스 만들기
먼저 노션에 이런식으로 테이블을 하나 만들어주세요.
여기서 중요하고 필요한 column 값들은 Status와 Slug 입니다.
그 다음 이 데이터베이스의 ID를 찾아줍니다. ID를 찾기 위해서는 상단의 오른쪽 코너에 있는 ... 점 세개 버튼을 누르고 Copy Link를 눌러주세요.
notion.so/5k314fze586d45639eild48951afba89?v=4ca2463b53614a5691bd
그럼 이런식으로 링크가 보여지는데 여기서 데이터베이스의 ID는 www.notion.so/ 다음부터 ? 물음표 전까지의 값입니다. 즉 이 예시에서 ID는 "5k314fze586d45639eild48951afba89" 입니다.
2. 노션 개발자 토큰 얻기
https://www.notion.so/my-integrations 이 링크로 간다음에 새로운 프로젝트를 만들어주세요.
그 다음 Secret key를 복사해서 저장합니다.
환경 설정에서는 데이터베이스의 컨텐츠들을 읽어올 수 있게 허용을 해줍니다.
3. 프로젝트 셋업하기
이미 기존의 Next JS 앱이 있다면 터미널에 다음의 패키지들을 다운받아주세요.
$ yarn add @notionhq/client @notion-render/client @notion-render/hljs-plugin @notion-render/bookmark-plugin
# Or
$ npm install @notionhq/client @notion-render/client @notion-render/hljs-plugin @notion-render/bookmark-plugin그 다음에 로컬 .env 파일에 다음 값들을 저장해주세요. 여기서 NOTION_TOKEN은 위에서 저장한 notion secret key이고, NOTION_DATABSE_ID는 데이터베이스 ID 입니다.
NOTION_TOKEN="secret_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
NOTION_DATABASE_ID="xxxxxxxxxxxxxxxxxxxxxxx"4. 노션 데이터베이스 불러오기
그 다음 Next JS 앱 환경에서 lib 폴더에 notion.ts라는 파일을 만들어줍니다.
import "server-only";
import { Client } from "@notionhq/client";
import React from "react";
import {
BlockObjectResponse,
PageObjectResponse,
} from "@notionhq/client/build/src/api-endpoints";
export const notion = new Client({
auth: process.env.NOTION_TOKEN,
});
export const fetchPages = React.cache(() => {
return notion.databases.query({
database_id: process.env.NOTION_DATABASE_ID!,
filter: {
property: "Status",
select: {
equals: "Published",
},
},
});
});
export const fetchPageBySlug = React.cache((slug: string) => {
return notion.databases
.query({
database_id: process.env.NOTION_DATABASE_ID!,
filter: {
property: "Slug",
rich_text: {
equals: slug,
},
},
})
.then((res) => res.results[0] as PageObjectResponse | undefined);
});
export const fetchPageBlocks = React.cache((pageId: string) => {
return notion.blocks.children
.list({ block_id: pageId })
.then((res) => res.results as BlockObjectResponse[]);
});
fetchPages() 함수는 노션 데이터베이스 ID를 사용해서 데이터베이스를 불러온 다음, 데이터베이스의 column 값들 중에서 Status가 "Published"로 돼있는 컨텐츠들만 불러온다는 뜻
fetchPageBySlug() 함수는 마찬가지로 데이터베이스를 불러오지만 데이터베이스의 column 값 중에서 Slug에 있는 텍스트를 바탕으로 내용을 불러온다는 뜻
5. page.tsx에서 데이터베이스 컨텐츠 렌더링하기
그 다음 app/blog/[slug]/page.tsx와 같은 파일 내에서 아래의 코드를 사용합니다.
여기서 const post = await fetchPageBySlug("week2-employee") 줄은 맨 위에 제 데이터베이스 사진에서 Slug column 값들 중에 "week2-employee"로 돼있는 페이지 컨텐츠를 불러온다는 뜻입니다.
import { fetchPageBlocks, fetchPageBySlug, notion } from "@/lib/notion";
import { NotionRenderer } from "@notion-render/client";
import { notFound } from "next/navigation";
import { Client } from "@notionhq/client"
import "@notion-render/client/sass/theme.scss"
export default async function Page() {
const post = await fetchPageBySlug("week2-employee");
if (!post) notFound();
const blocks = await fetchPageBlocks(post.id);
const client = new Client({ auth: process.env.NOTION_TOKEN })
const renderer = new NotionRenderer({ client })
const html = await renderer.render(...blocks);
return <div className="notion-render" dangerouslySetInnerHTML={{ __html: html }}></div>;
}그리고 className = "notion-render"를 통해 노션 스타일링 형식에 맞게 페이지 컨텐츠를 불러오도록 합니다.
그럼 노션에 작성한 컨텐츠 스타일링 그대로 Next JS 웹사이트에 컨텐츠가 뜹니다.
Code block부터 이미지, Header, inline code, bullet list 등이 다 렌더링됩니다. (렌더링 되지 않는 블록들도 있습니다! 깃헙 페이지에서 확인하세요.)
이런식으로 노션에서 작성한 스타일링 대로 그대로 뜹니다!!
마무리..
혹시 하면서 안되는 부분 있으면 댓글 달아주세요! 저도 겨우겨우 우여곡절에 성공한거라 모든 방법들은 다 해봤던 것 같네요.
댓글
로그인 후 댓글을 남길 수 있습니다.
대단해요~~~
감사합니다!!
대박~ 능력자시네여
Next JS 앱을 사용하신건 이용자 권한 때문인가요?
처음에 next auth 쓸려고 next js 사용했는데 supabase에서도 지원을 해줘서 굳이 next를 쓸 필요는 없는 것 같아요! 근데 프론트엔드는 계속 이걸 써왔어서 익숙해서 썼습니다 :)
공유 감사합니다!