블로그 리뉴얼을 돌아보며
리디자인으로 시작해서 아예 처음부터 만들게 된 이야기
이번에 블로그(기존 dodaNote)를 새로 만들었다. 드디어 여러 작업을 완성하고 공개하게 되었는데, 이는 새로 구성한 블로그를 만들면서의 회고록을 적어볼까 한다.
왜 블로그를 새로 만들까요?
리디자인
이 리뉴얼 프로젝트는 사실은 리디자인을 위해 시작되었다. 2년 전에 짜놓은 디자인, 그것도 프로토타입 수준의 디자인을 가지고 코드로 바로 옮겼었다. 그렇다 보니 디자인적으로나 색상 조합으로나 여러 미숙한 점이 눈에 띄었고, 이는 내 개인적인 블로그 변경 욕구를 자극했다.
그렇기에 변경을 계획한 시기는 해당 디자인을 실제로 적용하고 얼마 지나지 않을 시점이었다.
새롭게 블로그 디자인할 때는 레이아웃 구조 외에는 모두 새로 만들었다.
먼저, 색상 모드(라이트,다크)에 따른 컬러 팔레트를 사전에 정의해놓고 Figma에서 제공하는 스타일 프리셋 기능을 이용하여 디자인 시 편리하게 가져다 쓸 수 있도록 했다.
스타일 프리셋을 변경하면, 해당 프리셋을 사용한 곳에 모두 반영되어 디자인 시스템을 간단하게 변경할 수 있다.
그다음엔 Figma의 Auto Layout 기능을 적극적으로 사용하여 레이아웃을 구성하였다.
나에게 이 기능이 정말 특별했던 이유는, CSS Flexbox Layout과 거의 모든 것이 동일하다. 그렇기에 Figma에서 이 기능을 이용하여 레이아웃을 구성하는 경우 웹에서 그대로 구현하면 된다. 그 말인즉슨 Figma에서 구현된 레이아웃 디자인을 그대로 코드로 옮길 수 있다는 것이기도 하다. (개발자가 디자인을 보고 레이아웃을 어떻게 나눌지 상상의 나라를 펼치지 않아도 된다)
사실 이 기능들은 Figma에 출시된 지 이미 오래된 기능이라, 어느 정도 Figma를 오래 사용한 사람의 경우 Auto Layout에 익숙할지도 모른다. 나에게 이 기능이 메리트였던 이유는, 디자인을 개발로 옮길 때 두 번 생각하지 않아도 된다는 것이다.
개발?
원래 개발의 경우에는 새로 만들 생각이 없었다. 기존 서비스에서도 실제 데이터와 View를 다루는 컴포넌트를 분리해두었기 때문에, 리디자인 초기에는 기존 소스에서 디자인만 수정하는 식으로 작업하려고 했었다.
하지만 갑자기 내가 모노레포를 접하게 되면서, 모노레포를 도입하면서 얻는 장점이 여러 귀찮은 작업보다 가치있다고 판단하여 모노레포 기반의 프론트엔드로 전면 수정하게 되었다(완전 새로 작업하게 되었다) 이에 대한 자세한 내용은 아래에서 더 이어가도록 하겠다. 물론 하단에 더 서술하겠지만, 단순 모노레포 때문에 완전 처음부터 작업한 것은 아니다.
Notion 기반
이전 블로그부터 도입했던 기능이다. 이전 블로그를 만들고 나서는 글을 작성하지 않아 블로그 글은 남아 있지 않더라…
최근 Headless CMS가 유행하면서 여러 블로그가 CMS를 도입하여 사용하는 추세다. 나도 블로그를 구성할 당시 많은 CMS를 찾아 돌아다녔지만, 대부분이 관리에 초점이 맞춰져 있고 컨텐츠 자체의 기능은 부실하다는 느낌을 받았다.
그러다 발견한 것이 바로 Notion & Next.js로 블로그 만들기 글이었다. 기존에도 나는 Note-taking 서비스로 Notion만을 애용하고 있었고, 모든 데이터 컬럼을 내가 관리할 수 있다는 점과 노션 데이터를 바로 활용할 수 있다는 점에 매력을 느껴 react-notion을 이용하여 블로그를 구축했었다. 지금 이 글도 특별한 문제가 있어 내가 옮기지 않는 한, 노션 데이터를 활용하여 작성된 것이다.
새롭게 도입한 기술들
이 문단부터는 조금 개발적인 관점에서 서술해볼까 한다. 리디자인을 위해 시작한 프로젝트가 왜 이렇게 규모가 커지게 되었는지에 대한 합리적인… 아니 어떻게 보면 자기 합리화 같은 내용을 적는다.
모노레포 (with Nx)
기존에는 Lerna, Yarn Workspace 등으로 모노레포의 사용 사례 정도만 들어봤었는데, 팀 활동을 하면서 모노레포로 구성된 프로젝트를 해 볼 경험이 생겼고 Nx를 통해 모노레포를 사용해보며 편리함을 느꼈다.
먼저 모노레포를 통해 얻을 수 있는 가장 큰 장점은 공통 유틸들의 공유이다. 기존에는 npm 패키지를 만들어 Private Repository에 올리고, 해당 패키지를 사용하는 곳에서는 버전이 변경될 때마다 업데이트하여 사용해야 됐다.
모노레포를 사용하게 되는 경우, 공통 유틸들을 모두 shared 라이브러리로 관리하고 해당 라이브러리를 수정하면 모든 패키지에 자동으로 반영되는 것이 만족스러웠다.
다만, 이는 각 프로젝트별 패키지 버전 관리가 필요하지 않은 내 개인 작업에 알맞는 특성이었다. 만일 레거시 프로젝트에는 반영되지 않아야 하는 변경 사항이 존재한다면… 많이 곤란해질 것 같다.
Nx가 주는 장점들
조금 뒤늦은 소개지만, 내가 모노레포를 관리하기 위해 사용한 도구인 Nx를 간단하게 알아보고, 내가 수많은 모노레포 관리 도구 중에 Nx를 선택한 이유도 적어본다.
Nx의 장점을 소개하기에 앞서, 많은 모노레포 관리 도구를 보고 싶다면 Monorepo.tools에서 시각화된 비교 자료를 보는 것을 추천한다. (다만 이 사이트는 Nx의 제작사 Nrwl에서 제공하는 사이트로, 어느 정도 편향된 설명이 있을 수 있음을 유의하며 보자)
먼저, 빠르다.
Nx가 어떻게 우리에게 빠른 경험을 제공해주는지 적어보자면
- 변경된 내용만 추적: 모노레포 도구의 기본적인 기능이다. 상세 비교(deep-diff)를 통해 변경 점을 찾고, 변경된 작업만 실행하여 불필요한 작업의 실행을 줄인다.
- 로컬 빌드 캐시: 모노레포는 특성상 공유(shared) 라이브러리가 변경되는 경우 모든 프로젝트의 빌드를 진행하게 되는데, 프로젝트별로 구별된 캐시를 통해 중복될 수 있는 작업을 줄여준다.
- Remote caching: 위의 로컬 빌드 캐시를 외부에서 사용할 수 있도록 도와주는 서비스. 다중 작업자가 많은 환경에서 유용할 것 같았다. 다만 이는 Nx Cloud라는 Nrwl에서 제공하는 서비스를 이용해야 가능했다.
- DTE: 작업을 여러 워커에서 병렬로 처리하여 더욱 빠른 CI 속도를 제공해주는 것으로 보인다. 나는 개인 사용 목적이라 사용하지 않았다.
편하다.
확장으로 설치할 수 있는 패키지에 Generator, Executor라는 개념이 있고, 이를 통해 기술 유형에 맞는 템플릿을 통해 모노레포 라이브러리를 간편하게 생성할 수 있다.
많이 사용하는 기술 스택들은 Nx에서 공식적으로 패키지로 제공되며, 이외의 패키지는 서드 파티를 통해 설치해 사용할 수 있다. (자주 쓰는 나만의 템플릿이 있다면, 직접 Generator를 만들어도 된다)
똑똑하다.
개발자가 의존성을 따로 명시해주지 않아도, import의 사용을 분석하여 의존성을 자동으로 파악한다.
이를 통해 영향을 받는 라이브러리를 자동으로 파악해주며, 만일 영향을 받는 라이브러리가 수정되었을 경우 자동으로 작업을 실행해주는 등의 기능도 가지고 있다.
styled-system
styled-system은 styled components나 emotion을 기반으로 하는 유틸 라이브러리로, 디자인 시스템을 기반으로 간단하게 컴포넌트를 구성할 수 있도록 도와준다.
백문이 불여일견, 직접 코드를 보면서 알아보자.
const Heading = styled.div` font-size: 2rem; color: #000;`
기본적으로 styled component를 만들게 되면 이렇게 각 컴포넌트마다 선언해주어야 하지만
const Box = styled('div')( { boxSizing: 'border-box', }, space, layout, color, typography,)
<Box fontSize="2rem" color="gray.1000" // Theming/>
메인 라이브러리에 Box를 만들고 어느 props를 사용할 것인지 지정해준다면, 굳이 컴포넌트를 만들지 않아도 간편하게 레이아웃을 구성할 수 있다.
다만 이는 스타일링을 편하게 도와줄 뿐, 당연하게도 사용되는 컴포넌트는 분리해주어야 한다. 이는 텍스트 같이 반복되어 사용되는 컴포넌트를 구성할 때 편하게 사용하기 좋다는 이야기다.
장기적으론 이를 기반으로 디자인 시스템을 구성하여, Theme만 변경해준다면 모든 서비스에 적합한 스타일을 제공할 수 있도록 할 계획이다.
Next.js
블로그의 핵심 기능은 Next.js에 의존하고 있다. 사실 리빌딩 전의 블로그도 Next.js를 사용했고, Next.js의 SSG에 의존하도록 제작되었어서, 새로운 기능이라고 부르기에는 애매한 감이 있다. (Next.js에 ISR이 도입된 초기에 바로 적용했었다)
Next.js의 기능 중 블로그의 핵심을 책임지는 기능은 다음과 같다.
- Incremental Static Regeneration - Notion API의 데이터가 변경되었을 때 정적으로 생성된 페이지의 데이터를 변경해준다. 이를 통해 글 작성 시 블로그를 다시 빌드 하지 않아도 블로그 글이 웹에 바로 반영된다.
- next/image - 이미지 최적화를 제공한다. Vercel과 함께 사용 시 귀찮은 과정 없이 간단하게 최적화 된 이미지를 유저에게 제공할 수 있다. 또한, 자바스크립트에 의존하지 않고도 사용 가능한 이미지 placeholder 기능을 기본으로 제공한다. 이미지가 로딩되지 않았을 때의 값만 넣어주면, 자연스럽게 이미지가 로딩되는 것처럼 보이도록 만들 수 있다.
- Next.js Compiler - Babel의 역할을 대신해주는 Next.js만의 코드 컴파일러. Rust로 작성된 SWC를 이용하도록 개발되어, Vercel의 주장대로라면 최대 17배 빠른 코드 컴파일링 속도를 제공한다고 한다. 실제로 emotion을 이용하는 페이지에서 Babel을 사용했을 때보다 SSR 속도가 체감될 정도로 빨라진 것을 느꼈다. 이외에도 기존에는 babel 구성과 플러그인을 따로 설치하여 관리하여야 했다면, Next.js Compiler의 경우 기본적으로 많은 기능들을 내장하고 있어 따로 관리하지 않아도 된다는 점이 장점이다. 다만 같은 맥락의 단점이라면 Babel 플러그인으로 존재하는 일부 기능들을 사용할 수 없다는 점 정도.
그 이외에도, 추후에 Edge Runtime이 Stable해진다면 Edge Runtime으로 바꿔 볼 계획을 가지고 있다.
Notion 데이터 렌더링
이것 또한 기존에도 Notion 기반의 컨텐츠 렌더링을 사용했기 때문에, react-notion을 동일하게 사용한다.
react-notion vs react-notion-x
리빌딩을 기획할 초기에는 원래 react-notion-x를 사용하려고 했었다. react-notion-x는 react-notion을 포크 하여 발전시킨 버전으로, 현재로썬 거의 다른 프로젝트라고 봐도 될 정도로 react-notion-x이 발전하여 더는 호환성을 찾아보기 어렵다.
react-notion-x의 장점이라면 서버 쪽 API를 다루는 notion-client
, 사용하는 타입들을 모아놓은 notion-types
, 실제 렌더러인 react-notion-x
로 패키지별로 하는 역할이 명확하게 나누어져 있고, 기존의 react-notion보다 명확하게 나누어져 있어 편리한 개발이 가능하다는 점이 있다.
다만 내가 이를 사용하지 않은 이유는, react-notion-x는 노션의 기능들(예를 들자면 컬렉션, 테이블)을 구현하는 데에 초점이 맞춰져 있어, 내가 원하는 블럭 별 커스터마이징을 지원하지 않았다.
나의 경우에는 노션 컨텐츠를 렌더링하는 용도로만 사용할 예정이었기에, 많은 기능이 들어가 있고 커스텀이 불가능한 react-notion-x을 사용하는 계획을 철회했다.
결국엔 포크
기존에는 react-notion을 설치하여 진행하고 있었는데, react-notion이 더는 유지보수가 되지 않아 일부 기능들이 지원되지 않았다. 그중에서 제일 아쉬웠던 기능이 표와 이미지 정렬 기능이었다.
이러한 기능들은 react-notion에서 제공하는 Custom Block Components로 처리하기에는 점점 한계가 있어, 결국엔 모노레포 안에 shared 라이브러리로 react-notion을 포크하여 가져왔다. (react-notion은 MIT 라이선스를 사용하고 있어 개인 저장소에 포크해도 문제가 없다)
포크 후에 많은 것들을 수정하였지만, 크게 수정된 것은 다음과 같다:
- 제일 먼저 개선한 것은 react-notion에서 사용하는 컨텐츠 구조를 notion-types에서 사용하는 타입 구조로 변경하였다. 원래부터 TypeScript였던 타입을 굳이 바꾸는 이유가 있느냐고 물어볼 수 있는데, 굳이 바꾸는 이유가 있다.
기존에 사용하던 데이터는 Cloudflare Worker에서 구동되는 것을 가정으로 한 notion-api-worker라는 오픈소스를 통해서 가져와야 사용할 수 있었는데, Next.js에서 SSG를 사용하는 경우 Next.js
→ Cloudflare Worker
→ Notion 내부 API
순서로 요청하게 된다. 비효율적인 구조를 개선하기 위해 notion-client를 이용해 데이터를 받아와 Next.js
→ Notion 내부 API
로 요청하도록 구성하였다.
- 다음으로 수정한 것은 블럭 컴포넌트들을 렌더하는 부분을 각 블럭마다 분리하고, 각 블럭에서 emotion을 사용하여 렌더링할 수 있도록 구성하였다. 나는 기본적으로 emotion에 의존하여 서비스를 구성하기에 CSS를 굳이 사용할 이유가 없었다.
- Next.js의 Image 컴포넌트를 사용할 수 있도록 대응했다. 나중에 Next.js 이외의 장소에서도 사용할 가능성이 있기 때문에, Next.js에 의존적이지 않도록 구성했다.
- 이미지 블럭을 대폭 수정했다. 이미지 정렬 기능을 구현했다.
- 표는 아직 대응하지 못했다. 추후 표가 필요해질 때가 오면 추가할 계획이다.
생각보다 구현이 깔끔하지 못해 난제가 많았지만, 문제에 대응해가며 앞으로도 개선할 계획이다.
앞으로는?
포트폴리오
아직 포트폴리오 페이지를 완성하지 못했다. 아마 포트폴리오를 완성하게 된다면, MDX를 사용해보지 않을까 싶다.
글 섬네일
커뮤니티에서 넷플릭스의 섬네일도 유저마다 맞춤화되어 제공된다는 사실을 다룬 글을 본 적이 있다. 넷플릭스뿐만 아니라 우리에게 익숙한 유튜버들도 영상의 유입을 끌어들이기 위해 시청자에게 짧고 강한 인상을 줄 수 있는 섬네일을 거는 일, 즉 ‘섬네일 어그로’ 또한 기본 스킬이 되어버렸다.
10마디의 말보다 사진 한 개가 임팩트가 크다는 것이 증명되어버린 지금에 블로그에 섬네일은 커녕 이미지조차 없다는 것은 내 블로그의 문제점이라고 생각한다.
프론트엔드 호스팅 SaaS로 유명한 Vercel에서는 브라우저를 기반으로 렌더링하여 코드로 OpenGraph 섬네일 이미지를 렌더링해주는 오픈소스인 satori를 공개했다. 이를 바탕으로 섬네일이 있는 글에는 그 섬네일을 노출하고, 없는 글에는 자동으로 생성하여 보여 줄 생각이다.
블로그 시리즈 기능
velog의 시리즈 기능를 모방하여 시리즈를 만들어 볼 계획이다.
Notion의 데이터베이스는 ‘관계형 페이지’를 설정할 수 있다. 이를 통해 모든 컨텐츠를 Notion을 통해 관리할 수 있는 시리즈 기능을 만들어 볼 계획이다.
여담
- dodaNote (일명 블로그 v1)을 개발했을 때도 블로그 글을 적으려고 계획했었는데, 여차여차 미뤄지다 결국 못 적고 블로그를 개편해버렸다. 또 게을러서 못 적을까 봐 블로그 개편 후에 바로 회고 글을 적어본다.
- 글을 작성하며 내가 얼마나 맞춤법에 약한지 깨닫게 되었다. 외국어 공부 전에 한국어 공부부터 다시 해야 될 것 같다…