Open13

cather開発メモ

cryptoboxcryptobox

書籍レビューサイトの開発記録
目的:記録
方針:記述は頑張らない。しかし、途中でやめない

cryptoboxcryptobox

https://www.udemy.com/course/nextjs-supabase-app-directory/learn/lecture/35088344#content
これ見ながらセットアップ

cssフレームワークは馴染みのあるzero-runtimeってことでtailwindを選択
ディレクトリ構成に悩む
Twitterで誰かの例が載ってたのでパクりたいのだがいいねしてなくて追えない・・・。
とりあえず微かな記憶を頼りに探る。

cryptoboxcryptobox

作る理由

  • ポートフォリオとして
  • 自分が使いたい
  • アイデアの検証
  • 技術の検証
  • 趣味
  • 副業
  • 表現の手段
cryptoboxcryptobox

tailwind intelisenseが聞かない

settings.json
"editor.quickSuggestions": {
    "strings": true
  }
cryptoboxcryptobox

Prisma

PlanescaleでDB立ててnpx prisma studiでポチポチデータ操作していく感じ

cryptoboxcryptobox

chakrauiだとsuspenseを使っているコンポーネントでhydration error

Hydration failed because the initial UI does not match what was rendered on the server.

上記エラーが出る
client componentをserver componentで呼び出しているのが原因?
このあたりよくわからない
コンポーネントでデータをfetchするのをやめるとエラーが出なくなることから恐らくこれが原因だと推測

解決策

ChakraUIをやめてzero-runtimeなpandacssを試す?

cryptoboxcryptobox

pandacss検証

https://zenn.dev/azukiazusa/articles/next-js-app-dir-tutorial#server-component-と-client-component-を使い分ける

これをpandacssで作ってみる

headerコンポーネントは以下のようになる。

import { css } from "@/styled-system/css";
import NextLink from "next/link";

export default function Header() {
  return (
    <header>
      <div
        className={css({
          bg: "white",
          color: "gray.600",
          minH: "60px",
          py: 2,
          px: 2,
          borderBottom: 1,
          borderStyle: "solid",
          borderColor: "gray.200",
          alignItems: "center",
        })}
      >
        <div
          className={css({
            display: "flex",
            justifyContent: "space-between",
            maxW: "5xl",
            mx: "auto",
          })}
        >
          <h1 className={css({ fontSize: "lg" })}>
            <NextLink href="/">Blog App</NextLink>
          </h1>
          <NextLink
            className={css({
              fontSize: "sm",
              fontWeight: 600,
              color: "white",
              bg: "orange.400",
              _hover: { bg: "orange.300" },
            })}
            href="/articles/new"
          >
            記事を書く
          </NextLink>
        </div>
      </div>
    </header>
  );
}

Chakra製だけあって書き味はほぼ同じ

cryptoboxcryptobox

route handlers

https://nextjs.org/docs/app/building-your-application/routing/router-handlers

app routerを使っている場合Api routesではなくRoute handlersなるものが使えるらしい。Api routesと書き味が少し違う。if (method === "GET")とかしてハンドリングしないのでこちらのほうが可読性は高い印象。api/route.tsのようにしないと認識されない。この場合/apiに対してリクエストするとレスポンスが返る。

api/route.ts
import fs from "fs";
import { randomUUID } from "crypto";
import { NextRequest } from "next/server";

const delay = (ms: number) => new Promise((res) => setTimeout(res, ms));

export async function GET() {
  await delay(1500);
  const articles = JSON.parse(fs.readFileSync("articles.json", "utf8"));
  articles.articles.sort((a: any, b: any) => {
    return new Date(b.createdAt).valueOf() - new Date(a.createdAt).valueOf();
  });
  return new Response(JSON.stringify(articles), {
    status: 200,
    headers: {
      "content-type": "application/json",
    },
  });
}

export async function POST(req: NextRequest) {
  await delay(1000);
  const { title, content } = await req.json();
  const articles = JSON.parse(fs.readFileSync("articles.json", "utf8"));
  const id = articles.articles.length + 1;
  const date = new Date();
  const slug = randomUUID();
  const newArticle = {
    id,
    title,
    slug,
    content,
    createdAt: date,
    updatedAt: date,
  };
  articles.articles.push(newArticle);
  fs.writeFileSync("articles.json", JSON.stringify(articles));
  return new Response(JSON.stringify(newArticle), {
    status: 200,
    headers: {
      "content-type": "application/json",
    },
  });
}