src――lib | |―postblog.ts // ファイルをやり取りをする | |―pages |―main |―blog.tsx // ブログの一覧が表示されているページ |―blog |―[article].tsx // 任意のページに対して行う
ファイルを読み込んだりとデータを扱う役割
import path from 'path' import fs from 'fs' import matter from 'gray-matter' interface BlogInfo { readonly article: string, readonly title: string, readonly date: string, readonly thumbnail: string, readonly content: string, } const blogDirectory = path.join(process.cwd(), 'assets/blog') const getAllArticleId = async () => { const blogList = fs.readdirSync(blogDirectory) return blogList.map(el => { return { params: { article: el.replace(/\.md$/, '') } } }) } const getAllArticleInfo = async () => { const blogList = fs.readdirSync(blogDirectory) let articleDataList = Array<BlogInfo>(blogList.length) blogList.forEach((el, index) => { const article = el.replace(/\.md$/, '') const fullPath = path.join(blogDirectory, el) const blogData = fs.readFileSync(fullPath, 'utf-8') const { data, content } = matter(blogData) articleDataList[index] = { article : article, title : data.title, date : data.date, thumbnail: data.thumbnail, content : content, } }) sortBlogList(articleDataList) return articleDataList } const getArticleData = async (slug: string) => { const fullPath = path.join(blogDirectory, `${slug}.md`) const blogData = fs.readFileSync(fullPath, 'utf-8') const { data, content } = matter(blogData) const articleData: BlogInfo = { article : slug, title : data.title, date : data.date, thumbnail: data.thumbnail, content : content, } return articleData } export const sortBlogList = (blogList: Array<BlogInfo>) => { const blgLen = blogList.length - 1 for(let i = 0; i < blgLen; i++) { for(let j = blgLen; i < j; j--) { if(blogList[j].date > blogList[j - 1].date) { let tmp = blogList[j] blogList[j] = blogList[j - 1] blogList[j - 1] = tmp } } } } export { getAllArticleId, getAllArticleInfo, getArticleData }
サムネなど表示して、クリックすると各ブログ記事へ飛ぶリンクなどが書いてある。
ここにもSSGの実装がある
import Head from 'next/head' import Link from 'next/link' import { InferGetStaticPropsType } from 'next' import type { ReactElement } from 'react' import { getAllArticleInfo } from '@/lib/postblog' import NavBar from '@/components/layouts/navbar' import MikuFooter from '@/components/layouts/mikufooter' import Sakura from '@/components/layouts/sakura' import styles from '@/styles/pages/Blog.module.sass' type Props = InferGetStaticPropsType<typeof getStaticProps> export const getStaticProps = async () => { const articleDataList = await getAllArticleInfo() return { props: { articleDataList }, } } const Blog = ({ articleDataList }: Props) => { const editDate = (date: string) => { // date : YYYYMMDD const year = date.slice(0, 4) const month = date.slice(4, 6) const day = date.slice(6, 8) return year + '-' + month + '-' + day } return ( <div className="mt-28"> <Head> <title>Blog | Next/React</title> <meta name='discription' content='SSG Blog Page created by NextJs' /> </Head> <Sakura/> <section className="text-center mb-12"> <p className="text-8xl font-bold underline decoration-4">BLOG</p> <p className="text-xl italic pt-4"> This page is for my blog and writing down what learned self learning<br/> I'm sorry, if I made a mistake... pls go easy on me... </p> </section> <section className="mb-12"> <div className={styles.grid}> {articleDataList.map(el => <article key={el.article}> <Link href={'./blog/'+`${el.article}`}> <img src={el.thumbnail} alt={el.thumbnail} /> </Link> <Link href={'./blog/'+`${el.article}`}> <p className="text-2xl font-bold pt-4 hover:underline">{el.title}</p> </Link> <small className="text-base text-gray-400">{editDate(el.date)}</small> </article> )} </div> </section> </div> ) } Blog.getLayout = (Blog: ReactElement) => { return ( <> <NavBar> { Blog } </NavBar> <MikuFooter/> </> ) } export default Blog
任意のページについて処理を行う、SSGの実装におけるメインの話はここで行われている
import Head from 'next/head' import ReactMarkdown from 'react-markdown' import { getAllArticleId, getArticleData } from '@/lib/postblog' import { InferGetStaticPropsType, GetStaticPaths, GetStaticPropsContext } from 'next' import styles from '@/styles/pages/BlogArticle.module.sass' import CodeBlock from '@/components/codeblock' import Sakura from '@/components/layouts/sakura' export const getStaticPaths: GetStaticPaths = async () => { const paths = await getAllArticleId() return { paths, fallback: false, } } export const getStaticProps = async (context: GetStaticPropsContext<{article: string}>) => { const articleData = await getArticleData(context.params!.article) return { props: { articleData, } } } type Props = InferGetStaticPropsType<typeof getStaticProps> const BlogArticle = ({articleData}: Props) => { return ( <div> <Head> <title>Blog | {articleData.title}</title> <meta name='discription' content='This page for writing down what learned self learning' /> </Head> <Sakura/> <ReactMarkdown className={styles.markdown} children={articleData.content} components={{ code: CodeBlock }} /> </div> ) } export default BlogArticle