tag , series Identifier 만들기
개발 블로그 개발 여정
reactnextjsmdx
Mon Jun 03 2024
이 글은 개발 블로그 개발 여정의 게시글이예요
해당 포스트는 NextJS를 이용하여 개발 블로그를 만들며 작성한 포스트입니다.
기술 블로그의 전체 코드는 📖 yonglog github 에서 확인 하실 수 있습니다.
- 1 . 개발블로그 제작을 시작하며
- 2 . CI/CD 파이프라인 구성하기
- 3 . tailwind 환경 설정 및 디자인 레퍼런스 찾기
- 4 . / 경로 레이아웃 , 페이지 디자인 생성하기
- 5 . [BUG] Build 시 발생하는 typeError 해결하기
- 6 . MDX를 사용하기 위한 라이브러리들 설치 및 환경 설정
- 7 . Post들이 저장된 FileSystem 파싱하기
- 8 . PageNavigation UI 만들기
- 9 . tag , series Identifier 만들기
- 10 . / 경로 UI 디자인 하기
- 11 . 서버 컴포넌트에 Dynamic Routing 추가하기
- 12 . Post/page.tsx 생성하기
- 13 . 마크다운 파일 코드블록 꾸미기
- 14 . [BUG] Vercel 에 환경 변수 추가하기
- 15 . Loading Suspense 구현하기
- 16 . generateStaticParams 이용해 SSR 에서 SSG로 넘어가자
- 17 . SSG를 이용한 블로그에서 테마 변경하기
- 18 . 인터렉티브한 사이드바 만들기
- 19 . 기술블로그에 giscus를 이용하여 댓글 기능을 추가하기
- 20 . 기술 블로그의 SEO를 최적화 하기 위한 방법 Part1
- 21 . 기술 블로그의 SEO를 최적화 하기 위한 방법 Part2
- 22 . 바닐라 자바스크립트로 깃허브 OAuth 를 구현해보자
- 23 . 라이브러리 없이 깃허브 API를 이용해 댓글창을 구현해보자
- 24 . 리팩토링 : Promise 패턴을 이용하여 비동기 처리중인 전역 객체에 접근하기
- 25 . NextJS로 만든 기술블로그에서 검색 기능 구현하기

tag , seriese 인디게이터 만들기
예전 프로토타입의 모습을 보기 위해 tag , series
에 들어갈 내용들을 단순히 목업 데이터로 만들었었다.
예전 단계에서 posts
폴더에 존재하는 md
파일들을 읽기 위해 getAllPosts
메소드를 생성해줬었다.
이제 getAllPosts
메소드를 이용해 tag , series
에 사용 할 데이터를 생성해주도록 하자
getAllTags , getAllSeries
// types/global.d.ts
type Key = string;
type Count = number;
export type CountObject = Record<Key, Count>;
export type CountArray = Array<[Key, Count]>;
우선 해당 메소드에 사용 할 타입을 선언해주자
CountObject
는 배열과 같은 자료구조의 Key
값의 빈도수를 value
로 갖는 객체의 타입이며 CountArray
는 배열 안에 Key , Count
가 담긴 배열이 존재하는 이중 중첩 배열 객체의 타입이다.
import { getAllPosts } from './post';
import type { CountObject, CountArray } from '@/types/global';
const incrementCount = (collection: CountObject, key: string) => {
if (!collection[key]) {
collection[key] = 0;
} else {
collection[key] += 1;
}
};
export const getAllTags = (): CountArray => {
const Posts = getAllPosts();
const TagInfo: CountObject = {};
Posts.forEach(({ meta: { tag } }) => {
tag?.forEach((tagName) => incrementCount(TagInfo, tagName));
});
return Object.entries(TagInfo).toSorted((prev, cur) => cur[1] - prev[1]);
};
export const getAllSeries = (): CountArray => {
const Posts = getAllPosts();
const SeriesInfo: CountObject = {};
Posts.forEach(({ meta: { series } }) => {
incrementCount(SeriesInfo, series);
});
return Object.entries(SeriesInfo).toSorted((prev, cur) => cur[1] - prev[1]);
};
이후 getallTags , getAllSeries
메소드를 정의해주었다. 두 메소드들은 Posts
들의 meta
에 존재하는 tag,series
들의 빈도를 센 후
빈도에 따라 값을 내림차순으로 정렬하여 값과 빈도를 담은 CountArray
를 반환한다.
Cateogory 컴포넌트에 적용하기
import { getAllTags } from '@/app/lib/identifer';
// TODO Route 하는 Link 컴포넌트로 구성하기
// TODO Active 한 상태에 따라 뭐 어쩌구 저쩌구 하기
const Category = ({ name, to }: { name: string; to?: string }) => {
return (
<button className='border border-gray-300 rounded-l-3xl rounded-r-3xl text-center px-4 py-2 focus:outline-none font-light text-sm'>
{name}
</button>
);
};
const tagList = getAllTags();
// TODO 태그 별 라우팅 하는 로직 추가하기
const CategoryList = () => {
return (
<section className='px-4 sm:px-8 md:px-16 lg:px-32 mt-24 sm:mt-24 md:mt-24 lg:mt-24 mb-12 sm:mb-12 md:mb-6 lg:mb-24'>
<ul className='flex flex-wrap gap-2.5'>
{tagList.map(([tagName, _], id) => (
<li key={id}>
<Category name={tagName} />
</li>
))}
</ul>
</section>
);
};
export default CategoryList;
// components/Sidebar
// TODO MDX 의 시리즈 이름 가져와서 하기
import { getAllSeries } from '@/app/lib/identifer';
// TODO 라우팅 기능 넣기
// TODO 경로에 따라 활성 비활성화 상태 넣기
const Seriese = ({ title }: { title: string }) => (
<li className='mb-2'>{title}</li>
);
const SideBar = () => {
const serieseList = getAllSeries();
return (
<section className='sticky flex-2 top-[5rem] right-0'>
<h2 className='text-indigo-200 font-bold text-xl mb-2'>시리즈</h2>
<ul>
{serieseList.map(([seriesName, count], id) => (
<Seriese title={`${seriesName} (${count})`} key={id} />
))}
</ul>
</section>
);
};
export default SideBar;
아직 미완성인 컴포넌트이지만 tagList , seriesList
를 getAllTags , getAllSeries
를 이용해 생성해주었다.
아 굿 ~~
getAllPosts
메소드만 만들어두니 할 수 있는게 무진장 많아졌다.