nextjs 블로그만들기과정 -1 mdx 파일 꺼내기

슬로그·2023년 12월 14일

nextjs

목록 보기
1/4
post-thumbnail

블로그를 만들어보고있는데 혼자 해보려니 장장 4일동안 삽질을 해버렷다..!
결론은 알고쓰자.....................😥plz!

https://bepyan.github.io/blog/nextjs-blog/3-mdx-plugin
이분의 블로그를 많이 참고 했다. (계신쪽으로 큰절중)

그래서 내가하려던건
1. mdx 파일의 경로를 읽어와서
2. nextjs를 이용해 페이지를 정적생성 해준뒤,
3. 생성된 slug와 맞는 mdx 파일을 보여주게했던 과정
을 적어보려 한다.

먼저 기본적으로 되어있어야하는건 nextjs를 설치하고 , src 폴더안에 app 안에 페이지들을 생성해주도록 했다.

아그리고 정확한 방법인진모르지만 nextjs 최신버전에 최대한 맞게 프로그래밍 했다.

디렉토리 경로는 아래를 참고하시면 됩니다.

src
ㅤ └─ app
	ㅤ  └─ posts
    ㅤㅤㅤㅤㅤ   └─ [...slugs]
                           └─ page.tsx

최신 nextjs 버전은 더이상 getStaticProps를 지원해주지않는 것 같다.
그래서 Dynamic Routes 해주려는 페이지에 비동기로 된 generateStaticParams을 작성해서 내 slug는 이거할거야 ! 라고 말을해주면 된단다 ..

[...slugs]파일안에 프로그래밍한 모든 포스트들을 담아두는건 비효율 이라서 따로 나는 service라는 폴더를 만들고 안에 컴포넌트를 생성해준다.

src
ㅤ└─ app
ㅤㅤㅤㅤ└─ service 
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ└─ getPosts.tsx

그리고 test할 mdx 파일을 미리 만들어둔다.
나는 최상위 폴더에 posts 디렉토리안에 만들어줬다.
년도와 월별로 정리해놓는게 좋을거같아서 posts/2023/11/test.mdx 일단 이렇게 만들어줬다.

posts
	└─ 2023
    ㅤㅤㅤㅤ└─ 11 
    ㅤㅤㅤㅤㅤㅤㅤ└─ blog.mdx
	---
    title: blogTitle
    date: 23th june 2023
    description: welcomne to my first blog
    ---

일단 mdx 파일이 나오는걸 확인해줘야하니까 대강 이렇게 만들어둔다.

다시 getPosts로 돌아와서 먼저 getAllPosts 라는 함수안에 프로그래밍해야할건
1. mdx 파일들의 경로를 읽어오고
2. mdx 파일이 여러개 있을꺼니까 map 메서드를 이용해 .mdx 파일의 이름을 없애줘야한다.

난 sync 메서드를 사용했는데 sync 메서드에 대해서 알아보자면

sync ?
node.js에서 제공되는 glob 패키지의 동기적인 버전이다. 파일 패턴을 사용해 파일 경로들을 매칭시키는데 사용된다 주로 파일을 읽어오거나 특정 패턴에 맞는 파일을 조작할때 유용하게 사용된다.

라고 써있다. ㅎ !

내가 원했던건 mdx 파일의 경로를 읽어와야하니까 readFile보다는 sync를 사용해줬다.

그래서 결론은 getAllPosts에서는 이렇게 작성해줬다.

	export async function getAllPosts():Promise<Slugs[]>{
    const postPaths = sync(`${POST_PATH}/**/*.mdx`);
    const paths = postPaths.map((postPath) => {
        return{
            slug: postPath.replace(/\\/g, '/').replace('.mdx','')
        }
    })
    return paths;
    //{ slug: '/posts/2023/11/test' },
    //{ slug: '/posts/2023/11/blog' }
}

왜때문인진 모르겠는데 난 자꾸 역슬래시로 나와서 / 로 바꿔줬고 마지막엔 mdx파일을 없애줬다.
test.mdx 과 blog.mdx 파일이 있어서 .mdx가 없앤 경로만 반환된다.

이제 mdx파일 경로를 읽어와서 .mdx를 없애줬고 그다음은 다이나믹 라우터 페이지에서 getAllPosts가 내 경로다!! 라는걸 말해줘야한다.

[...slugs] 안에 page.tsx 에 generateStaticParams 함수를 만들고 작성해주면 된다. getStaticProps에서 바뀐거같다. generateStaticParams 참고

	export async function generateStaticParams() {
    const posts = await getAllPosts(); 
    const slugs =  posts.map((post)=>({
        slug: post.slug 
    }));
    return slugs;
}

generateStaticParams를 설명해보자면 만들어둔 getAllPosts의 slug들을 가져와서 이 [...slugs]의 페이지는 getAllPosts에서 나온 slug로 할거야 ! 라는 의미정도?

그다음 할일은 getPosts파일로 돌아가서 내가 있는 페이지에 slug 와 내가 만든 mdx파일들이 들어있는 getAllPosts의 slug와 맞는 slug를 보여줘야한다.
getPosts라고 함수를 만들고 [...slugs] 에 slug랑 비교해야되니까 매개변수도 넣어줘야함 !

export async function getPosts(params:any):Promise<Slugs | undefined>{
    const filePaths = await getAllPosts();
    const {slugs}  = params ;
    const slug = `posts/${slugs.join('/')}`
    const postsFind = filePaths.find((filePath) => filePath.slug === slug);
    return postsFind;
}

마지막?으로는 해당 slugs랑 같은 mdx파일을 가져왓지만 이 mdx을 파싱해줘야 페이지에 보인다! gray-matter를 사용했는데 gray-matter 요기 한번 보시면 됩니당


export async function parsePosts(fileName:string){
    try{
        const postPath = await getPosts(fileName); 
      // {slug: 'posts/2023/11/test'}
        const postPathFileSlug = postPath.slug
        const markdownFile = fs.readFileSync(`${postPathFileSlug}.mdx`, "utf-8");
        const {data:fontMatter,content} = matter(markdownFile);
        return{
            fontMatter,
            fileName,
            content
        }
    }catch(e){
        console.error(e)
    }

}

이것도 getPosts컴포넌트에 넣어줫다. 내가 있는 경로 slug들과 같은 경로의 mdx파일만 보여줘야하니까 getPosts를 가져와서 파싱해주면된다. fs.readFileSync를 사용해서 파일을 읽어아야하는데 fs.readFile란 !

fs.readFileSync ?
node.js에서 제공하는 동기적인 파일읽기 메서드 이다.
이 메서드는 동기적 이기 때문에 파일을 읽어올때까지 다음 코드의 실행을 차단한다. 만약 비동기적인 방식을 선호하면 fs.readFile을 사용하거나 콜백함수를 사용하면 된다.

라고 한다 !!! ㅎ
동기적으로 가져오게 사용한이유는 (내생각) 순차적으로 파일을 읽어와야하기에 readFileSync를 사용했다.
뒤에는 경로만 가져왔기때문에 뒤에 .mdx를 붙여줘야한다.

그리고 나서 gray-matter에 문서를 보고 matter에서 fontMatter와 content를 가져와 반환해주면 된다.

마지막?으로 는 [...slugs]페이지에 와서
default인 Page 컴포넌트에 이제 내가 파싱한 parsePosts를 가져와서 보여주면 된다.
slugs를 뽑아주질 않아서 params를 인자로 넣어주었다.

export default async function Page({params}:any){
    const {slugs}:Slugs = params;
    const markdownFile = await parsePosts(params);
    return(
        <article className="prose prose-sm md:prose-base lg:prose-lg prose-slate">
            <h1>{markdownFile?.fontMatter.title}</h1>
            {slugs}
        </article>
    )
}

이렇게 하면 두둥 - !!!!!!!!!!!!!!!!!!! 드디어 보인다 !!!!!!!

후기

버전이 업그레이드된 nextjs로 사용하고 싶었는데 구글링 했을때 이전 버전의 내용이 많아 내가 생각한대로 적용하는게 많이 어려웠다ㅠㅠ 역시 혼자하려니 힘듦....

참고
https://bepyan.github.io/blog/nextjs-blog/2-blog-listInfo
https://www.youtube.com/watch?v=pqmij7wTgqc&t=901s

profile
빨리가는 유일한 방법은 제대로 가는것

1개의 댓글

comment-user-thumbnail
2024년 5월 27일

하루종일 헤메다가 싹 날리고 천천히 해보니까 되네요 ㅜㅜ 좋은글 감사합니다.

답글 달기