NextJSのチュートリアルをやってみる

NextJSのチュートリアルをやってみる

目次

まずはチュートリアルをやってみる

チュートリアルは npx だったけど、yarn を使ってやってみる

yarn create next-app nextjs-blog
cd nextjs-blog
yarn dev

Link

GatsbyJS の時は、URL の指定は to="/posts/1"とかだったけど、NextJS は href="/posts/1"になる。

import Link from "next/link";

export default function Home() {
  return (
    <Layout>
      <section>
        (略)
        <Link href={`/posts/${id}`}>
          <a>{title}</a>
        </Link>
        (略)
      </section>
    </Layout>
  );
}

Image

public フォルダ内に images フォルダを作り、そこに画像を入れておく。

import Image from "next/image";

const Hoge = () => (
  <Image src="/images/hoge.png" height={144} width={144} alt="XXXXXXXX" />
);

Metadata

Layout.js ファイル内に Head コンポーネントを配置し、meta データの設定を行う。

import Head from "next/head";

export default function Layout({ children }) {
  return (
    <Head>
      <title>タイトル</title>
      <link rel="icon" href="/favicon.ico" />
      <meta name="description" content="説明文" />
    </Head>
  );
}

CSS(Global Style)の設定

CSS の Global Style を設定したい場合は、pages 以下に_app.js ファイルを作成する。

styles フォルダを(プロジェクトの)トップレベルに作成し、そのフォルダ内に global.css を作成し、_app.js 内で読み込む。

import "../styles/global.css";

export default function App({ Component, pageProps }) {
  return <Component {...pageProps} />;
}

固定ページの作成

固定ページ(About、404 など)を作成する時は、pages フォルダ内に配置する。

// pages/404.js
export default function Custom404() {
  return <h1>404 - Page Not Found</h1>;
}

md ファイルの作成

posts フォルダを(プロジェクトの)トップレベルに作成し、そのフォルダ内に md ファイルを作成する。

---
title: "NextJSのチュートリアルをやってみる"
date: "2022-06-21"
---

Markdown ファイルから meta 情報をパースするために、gray-matter ライブラリ をインストールする。

yarn add gray-matter

lib フォルダを(プロジェクトの)トップレベルに作成し、そのフォルダ内に posts.js ファイルを作成する。

import fs from 'fs';
import path from 'path';
import matter from 'gray-matter';

const postsDirectory = path.join(process.cwd(), 'posts');

export function getSortedPostsData() {
  // Get file names under /posts
  const fileNames = fs.readdirSync(postsDirectory);
  const allPostsData = fileNames.map((fileName) => {
    // Remove ".md" from file name to get id
    const id = fileName.replace(/\.md$/, '');

    (略)

index.js ファイルに、以下を追記する。

import { getSortedPostsData } from "../lib/posts";

export async function getStaticProps() {
  const allPostsData = getSortedPostsData();
  return {
    props: {
      allPostsData,
    },
  };
}

allPostsData を受け取って、map で展開する。

export default function Home({ allPostsData }) {
  return (
    <Layout>
      <section>
        <h2>Blog</h2>
        <ul>
          {allPostsData.map(({ id, date, title }) => (
            <li key={id}>
              {title}
              <br />
              {id}
              <br />
              {date}
            </li>
          ))}
        </ul>
      </section>
    </Layout>
  );
}

動的ファイルの作成

動的にページを作成する時は、pages ディレクトリ内に posts フォルダを作成し、そこに[id].js ファイルを配置する。

Markdown に書かれた内容を読み込む為に、remark ライブラリをインストールする。

yarn add remark remark-html

lib/posts.js ファイルに以下を追記する。

import { remark } from "remark";
import html from "remark-html";

export function getAllPostIds() {
  const fileNames = fs.readdirSync(postsDirectory);

  return fileNames.map((fileName) => {
    return {
      params: {
        id: fileName.replace(/\.md$/, ""),
      },
    };
  });
}

export async function getPostData(id) {
  const fullPath = path.join(postsDirectory, `${id}.md`);
  const fileContents = fs.readFileSync(fullPath, "utf8");

  // Use gray-matter to parse the post metadata section
  const matterResult = matter(fileContents);

  // Use remark to convert markdown into HTML string
  const processedContent = await remark()
    .use(html)
    .process(matterResult.content);
  const contentHtml = processedContent.toString();

  // Combine the data with the id and contentHtml
  return {
    id,
    contentHtml,
    ...matterResult.data,
  };
}

pages/posts/[id].js ファイルに、以下を追記。

import { getAllPostIds, getPostData } from "../../lib/posts";

export default function Post({ postData }) {
  return (
    <Layout>
      {postData.title}
      <br />
      {postData.id}
      <br />
      {postData.date}
      <br />
      <div dangerouslySetInnerHTML={{ __html: postData.contentHtml }} />
    </Layout>
  );
}

export async function getStaticPaths() {
  const paths = getAllPostIds();
  return {
    paths,
    fallback: false,
  };
}

export async function getStaticProps({ params }) {
  const postData = await getPostData(params.id);
  return {
    props: {
      postData,
    },
  };
}

markdown ファイルのファイル名から.md の拡張子を削除したものを URL のパス名として取り出し、それを使って個別記事にアクセス可能にしている。

getStaticPaths と getStaticProps については、以下に詳しく書かれています。

Date Format

日付のフォーマットを行うので、date-fns ライブラリをインストールする。

yarn add date-fns

components フォルダ内に、date.js ファイルを作成し、以下を記述する。

import { parseISO, format } from "date-fns";

export default function Date({ dateString }) {
  const date = parseISO(dateString);
  return <time dateTime={dateString}>{format(date, "LLLL d, yyyy")}</time>;
}

pages/posts/[id].js ファイルの記述を変更する。

import Date from "../../components/date";

export default function Post({ postData }) {
  return (
    <Layout>
      {/* Replace {postData.date} with this */}
      <Date dateString={postData.date} />
    </Layout>
  );
}

日付のフォーマットを変更したい場合は、以下を参考にする。