やかんです。
「お気づきだろうか」と生意気な書き出しをしてしまいすみません。
※今回の記事はやや専門的な内容になります。
ブログの動作をちょっと速くした。
言葉の通りでございますが、今までブログの動き遅かったですよね。すみません。

具体的には、
- キャッシュを利用するようにした
 - 取得するデータを小分けにした
 
という2点で、速度の改善を図りました。

実際どのくらい違いが出ているのかは分かりません
実装
今回リファクタしたのは投稿の取得周りです。一言で言うと、「今までは1つの投稿につき『前後の投稿』も同時に取得していたが、リファクタによって、『前後の投稿』を後回しにするようにした」となります。
「前後の投稿」とは、

↑これのことです。1つの投稿につき、次の投稿の情報、前の投稿の情報を取得したいというモチベでした。で、今までは「表示している投稿、その次の投稿、その前の投稿」を1度に取得していたから処理に時間がかかっていたんですが、それを「まず表示している投稿を取得して、それが終わったらその次の投稿、その前の投稿を取得する」というように処理を分けることで1つあたりの処理を軽くしました。
具体的な実装を以下に貼ります。wordpressとnextjsを利用したブログ作成などの参考になれば。
まずこれが投稿自体のコード。
import { format } from "date-fns";
import { Suspense } from "react";
import { MdCalendarMonth } from "react-icons/md";
import { AroundPostNav } from "@/components/around-post-nav";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { BeatLoader } from "@/components/ui/loader";
import { Separator } from "@/components/ui/separator";
import { WidthWrapper } from "@/components/width-wrapper";
import { getPost } from "@/lib/get-post";
type Props = {
  slug: string;
};
export async function PostContent({ slug }: Props) {
  const post = await getPost({ slug });
  return (
    <WidthWrapper>
      <div className="flex flex-col space-y-8">
        <h1 className="my-4 text-3xl">{post.title}</h1>
        <div className="flex items-center justify-between">
          <div className="flex items-center">
            <div>
              <Avatar>
                <AvatarImage
                  src="/yakan.png"
                  width={400}
                  height={400}
                  alt="yakan"
                />
                <AvatarFallback>やかん</AvatarFallback>
              </Avatar>
            </div>
            <p>やかん</p>
          </div>
          <div className="flex items-center">
            <MdCalendarMonth className="inline-block h-4 w-4" />
            <p>{format(new Date(post.date), "yyyy/MM/dd")}</p>
          </div>
        </div>
        <Separator className="my-4 bg-slate-400" />
        <div
          className="post-content"
          dangerouslySetInnerHTML={{ __html: post.content }}
        />
        <Separator className="my-4 bg-slate-400" />
        <Suspense
          fallback={
            <div className="mt-[20vh] flex min-h-screen justify-center">
              <BeatLoader color="#475569" />
            </div>
          }
        >
          <AroundPostNav post={post} />
        </Suspense>
      </div>
    </WidthWrapper>
  );
}
で、AroudPostNavというのが、「次の投稿」「前の投稿」のボタンの部分。コードは以下。
import { BsCaretLeftFill, BsCaretRightFill } from "react-icons/bs";
import { ButtonLink } from "@/components/ui/button-link";
import { getAroundPost } from "@/lib/get-post";
import { Post } from "@/lib/type";
type Props = {
  post: Post;
};
export async function AroundPostNav({ post }: Props) {
  const nextPost = await getAroundPost({ post, direction: "next" });
  const prevPost = await getAroundPost({ post, direction: "prev" });
  return (
    <div className="flex justify-between">
      {nextPost ? (
        <ButtonLink href={`/${nextPost.slug}`}>
          <BsCaretLeftFill className="inline-block h-4 w-4" />
          次の投稿
        </ButtonLink>
      ) : (
        <div />
      )}
      {prevPost ? (
        <ButtonLink href={`/${prevPost.slug}`}>
          前の投稿
          <BsCaretRightFill className="inline-block h-4 w-4" />
        </ButtonLink>
      ) : (
        <div />
      )}
    </div>
  );
}
で、ちょいちょい登場しているgetPost関数、getAroundPost関数は以下。コメントとか雑ですが。
import { notFound } from "next/navigation";
import { z } from "zod";
import { getPostsPrimitive } from "@/lib/get-posts";
import { postSchema } from "@/lib/schemas";
import type { Post } from "@/lib/type";
import { wpPrefix } from "@/lib/utils";
/**
 * 記事によってfetchリクエストの詳細を変える必要がある
 */
const pageSlugs = ["about-yakan", "about-blog", "privacy-policy"];
const fetchPost = ({ slug }: { slug: string }) => {
  if (pageSlugs.includes(slug)) {
    return fetch(`${wpPrefix()}/pages?slug=${slug}`);
  } else {
    return fetch(`${wpPrefix()}/posts?slug=${slug}`, {
      // next: { revalidate: 3600 },
      // NOTE: 現状、投稿した記事を編集することってあまりないから、キャッシュを使うようにする。
    });
  }
};
const getPostArgumentSchema = z.object({
  slug: z.string(),
});
type GetPostArgument = z.infer<typeof getPostArgumentSchema>;
async function getPostPrimitive({ slug }: GetPostArgument) {
  const res = await fetchPost({ slug })
    .then((res) => res.json())
    .catch((err) => {
      console.error(err);
      throw new Error("Failed to fetch data");
    });
  if (res.length === 0) {
    notFound();
  }
  const post: Post = {
    id: res[0].id,
    date: res[0].date,
    title: res[0].title.rendered,
    slug: res[0].slug,
    content: res[0].content.rendered,
  };
  return post;
}
/**
 * 前後の記事の取得
 */
const getAroundPostArgumentSchema = z.object({
  post: postSchema,
  direction: z.union([z.literal("prev"), z.literal("next")]),
});
type GetAroundPostArgument = z.infer<typeof getAroundPostArgumentSchema>;
export async function getAroundPost({
  post,
  direction,
}: GetAroundPostArgument) {
  const params =
    direction === "prev"
      ? `before=${post.date}&order=desc`
      : `after=${post.date}&order=asc`;
  const aroundPost = await getPostsPrimitive({
    params,
  });
  if (aroundPost.length === 0) {
    return null;
  }
  return aroundPost[0];
}
/**
 * getPost
 */
export async function getPost({ slug }: GetPostArgument) {
  const post = await getPostPrimitive({ slug });
  return post;
}
wordpressから記事を取得する場合の参考になれば嬉しいですが、なかなか曲者ですよねー。zod使ってサーバーサイドでバリデーションをかけたいところですが、wordpress rest apiの返り値がいつまでも同じスキーマを使ってくれるとも限りませんし、そもそも外部依存のスキーマを自分で実装したくはないです。壊れやすくなるので。
あ、あとキャッシュもためるようにしました。
ということで、こちらの記事は以上となります。最後までお読みいただき、ありがとうございます。

