Next.js + Notion 포트폴리오 사이트

Next.js + Notion 포트폴리오 사이트

Tags
WebDev
Node.js
React.js
Projects
Next.js
TypeScript
NAS
Published
2021년 11월 13일
Next.js와 NotionX를 이용하여 Notion을 CMS로 사용하는 내용을 담고 있습니다.

소개

이것은 Notion을 CMS로 사용하는 프로젝트입니다. 트래비스 피셔씨가 제작한 nextjs-notion-starter-kit을 클론하여 구현했습니다. 이 스타터 킷은 노션에서 사이트 루트로 사용할 페이지를 지정하면 Next.jsreact-notion-x 모듈이 모든 것을 렌더링합니다.
이후 Vercel에 쉽게 배포할 수 있다고 하는데요 저는 개인용 NAS에서 돌리고 있습니다. 이와 관련된 내용은 이전 포스트 이전전 포스트 를 참고해 주세요.

스타터 킷 특징

  • 설정은 몇 분 밖에 걸리지 않습니다 (단일 구성 파일) 💪
  • Next.js / TS / React / Notion
  • 우수한 페이지 속도
  • LQIP 이미지 미리보기
  • GitHub 연결 포함
  • 자동으로 생성되는 오픈 그래픽 이미지
  • 자동으로 생성되는 읽기쉬운 접근 URL
  • 자동으로 생성되는 목차
  • 다크 모드 지원
  • 노션과 마찬가지로 CMD+P를 통한 빠른 검색
  • 데스크톱 / 타블렛 / 모바일 반응형
  • Next.js 및 Vercel에 최적화
 
데스크탑 아티클 페이지
데스크탑 아티클 페이지
모바일 아티클 페이지
모바일 아티클 페이지
 
데스크탑 홈 페이지
데스크탑 홈 페이지
데스크탑 홈 페이지(다크 모드)
데스크탑 홈 페이지(다크 모드)

커스토마이즈

설치 및 실행 그리고 설정에 대한 내용은 깃헙의 것을 참고하시기 바랍니다. 정말로 아주 손쉽게 특정 노션페이지를 웹사이트로 만들어 줍니다. 하지만 바로 사용하기에는 무리가 있어 보였습니다.
  • 한글 URL 미지원
  • 한국 날짜 형식 미지원
  • 이전/앞으로 이동시 스크롤 포지션 유지 안됨
  • 루트 Notion Page ID 노출 문제
  • 기존 firejune.io에서 수행 중이었던 서버기능 추가
 
이러한 이슈들을 고치려고 보니 프로젝트가 모노레포 형식으로 구성되었고 각각 NPM 모듈로 존재한다는 것을 알 수 있었습니다. 그리고 제가 수정을 희망하는 많은 부분이 서브-모듈에 있음을 확인할 수 있었죠. 그래서 프로젝트 구조부터 제 스타일로 변경하고 모노레포 구성을 복원했습니다.
  • 프로젝트 소스 파일을 src 디렉토리로 몰아넣기
  • packages 디렉토리에 모노레포 구성 복원
    • 노션 관련 모듈 패키지: react-notion-x, notion-client, notion-types, notion-utils
    • 트윗 관련 모듈 패키지: react-static-tweets, static-tweets
  • 최신 버전의 Node 모듈로 업그레이드

한글 URL 미지원

노션X 모듈은 노션 문서의 제목에서 URL을 추출하는 기능을 제공합니다. 아쉽게도 URL로 추출할 수 있는 문자는 영문 대/소문자 그리고 숫자뿐입니다. 제목에 한글을 쓰면 링크가 올바로 동작하지 않는 현상이 발생하더군요. notion-utils/src/get-canonical-page-id.ts 를 아래처럼 다른 문자들도 모두 URL로 처리되도록 수정했습니다.
export const normalizeTitle = (title: string | null): string => {
  return (
    (title || '')
      .replace(/ /g, '-')
      // [한글주소지원] 대/소문자 영문/숫자가 아닌 경우 문자열 제거됨
      // .replace(/[^a-zA-Z0-9-]/g, '')
      .replace(/--/g, '-')
      .replace(/-$/, '')
      .replace(/^-/, '')
      .trim()
      // [한글주소지원] 소문자화 불필요
      // .toLowerCase()
  )
}

한국 날짜 형식 미지원

날짜 노출 역시 노선X 모듈에서 처리합니다. date-fns 라이브러리가 사용되고 있으며 'MMM d, YYY hh:mm aa' 문자열을 찾아 한국 날짜 형식에 맞도록 수정합니다. 저는 'YYY년 M월 d일 a h:mm'로 일괄 수정하고 오전/오후가 한글로 나타나도록 { locale: ko } 옵션을 추가 했습니다. 그 외 date-fns 모듈의 기능이 사용되고 있는 모든 곳에서 이와 유사한 수정을 진행했습니다. 수정이 진행된 파일들:
  • react-notion-x/src/components/google-drive.tsx
  • react-notion-x/src/components/property.tsx
  • react-notion-x/src/eval-formula.ts
  • react-notion-x/src/utils.ts
  • react-static-tweets/src/twitter-layout/components/tweet/tweet-info.tsx

스크롤 포지션 유지

보통 이 기능은 브라우저가 알아서 수행하지만, SPA 또는 이와 유사하게 구현하는 경우 브라우저에서 동작을 보장하지 않기 때문에 이를 직접 구현해야 할 필요가 있습니다. useKeepScrollPosition이라는 간단한 리액트 훅을 작성하고 _app.ts에 훅을 사용하여 이 문제를 해결했습니다. 훅의 내용은 아래 깃헙 Gist에서 확인할 수 있어요.

그 외

몇몇 스타일을 수정했고 site.config.js에 기록되는 일부 개인정보를 .env 파일에서 참조되도록 변경하는 등의 자잘한 작업을 이어갔습니다. 설정 파일로 국가별 날짜 형식이나 URL 사용 분기를 처리해도 좋았을 것 같지만 제가 직접 이 프로젝트를 사용하고 실험하기 위한 목적이어서 다음에 마음내키면 진행하기로 했습니다. 그러고 보니 구조를 많이 바꿔놔서 오리진에 기여하는 것도 어려울 것 같긴 하네요. ☹️

Notion을 CMS로 활용

노션에서 내용을 추가하거나 갱신하면 추가적인 퍼블리싱 과정없이 서비스에 반영되며, 해당 페이지는 정적인 페이지로 비동기 빌드됩니다. 이는 NotionX에서 채용한 데이터 요청 캐시 전략인 SWR(stale-while-revalidate)과 후속 조치로 Next.js의 정적 페이지 생성 옵션인 revalidate에 의해 가능한 것으로 보여집니다. 예전엔 정적 페이지들로 구성된 서비스(SSG)를 운영할 때는 항상 손으로 퍼블리시하는 노고가 수반되었는데 알아서 척척 해주니 아주 신세계네요.
사실상 동적 컨텐츠 이지만 정적 컨텐츠로 취급되어 페이지 로딩 속도가 미친듯 빠릅니다. 첫 페이지 진입시 DOMContentLoaded가 0.4초 대입니다. 이후 링크 이동은 manifest에 의해 캐시되어 있던 컨텐츠가 fatch되는 것이어서 0.1초 수준의 응답 속도를 보입니다.
프로젝트를 개인용 NAS 장비에 올려서 약 한 달 정도 운영 중인데 지금까지는 안정적으로 잘 동작하고 있는 것 같아요. 이후 SNS와 연결성을 강화하거나 제 개인 인프라를 활용하여 트래픽을 더욱 확보하고 웹 애널리틱스, 서버-사이드 액세스 통계 등 각종 분석 도구를 추가해서 수치화를 통해 이 실험을 구체화해 나갈 예정입니다.
참고로, 제가 구축한 요런 컨셉의 서비스를 유료로 만들어 비교적 싼 값에 사용할 수 있도록 제공하는 곳도 있는 것 같습니다.

리소스