元エンジニアが初めてNext.jsとtailwindCSS(+DaisyUI)、GitHub Pagesを使ってサイトを作ってみた

当方元々Webエンジニアでしたが、今やもう現役を退き…気がついたら年齢も40を超えてしまい、技術の進歩には過去の知識ベースで勝負してましたが…長期休暇を頂いたので、ちょっと一念発起して最新な技術を触ってみるために格闘してみました。

正味2日フルで使ってた感じですが、なんとか理解深まった気がします。し、色々自分でこの後ハマりそうだから備忘録もかねて記事を書いてみます。

# 今回の目標
今回は結果的にタイトルに書いたようなものを活用することになりました。が、元々は以下の方針で進めていました。

- React系の何かでやりたい(ちょっとだけGatsbyを触った程度の知識しかない)
    - 会社の後輩がNext.jsがいいぞ！と言ってたのでそれを使おうとしてた
- 最近のCSSデザイン方法を勉強したいのでtailwindCSSを使いたいな
- もはやレンタルサーバーとかでのホスティングもダサいなと思ったので別の方法でサイトを動かしておきたい。でもVPSとかはめんどい。
    - 調べてたらVercelを使うとか出てきたけど、タダでできないかな...と思って調べてたらGitHub Pagesでいけそう？と判断

# 事前準備(環境構築)
まずは環境構築ですが、これはそんなに難しいことはしてないです。事前準備でやることはここらへんかなと。GitHubの環境周りぐらいは割愛しています。GitHub Desktopとか入れればいいと思います。

- ローカルでの動作環境
- エディタ環境


## ローカルでの動作環境
これはMacbookを使ってるので超簡単です。ちなみにターミナルアプリは[Warp](https://www.warp.dev)を使っています。

### ローカルのNode環境準備
これはnodebrewをhomebrew経由でインストールで終わり。

```
brew install nodebrew
```

インストール終わったら、最新のnode.jsのバージョンを調べてインストール

```terminal
# 最新のバージョンを調べる
nodebrew ls-remote

# インストール
nodebrew install v22.9.0

# 入れたやつを使う(これは正確に言うと入れたnode.jsの中で最新を使う)
nodebrew use latest
```

これで準備完了。

##　エディタ環境
これはVisual Studio Codeですね。今回用に入れたのはここらへん。

- Prettier
- ES7+ React/Redux/React-Native snippets
- GitLens

なんか本当は多分もっと便利なのありそうなんですが多すぎてわからん！誰かぜひアドバイスお願いします。


# 構築作業

## 初期コード一式準備
ということで、早速開発開始です。基本はnext.jsの公式ヘルプを見て勉強しながら進めました。

https://nextjs.org/docs/getting-started/installation

要はこれを実行したらOK。聞かれるやつは全部Recommend通りに進めちゃえばOK。
Recommend通りにやればTailwindCSSもAppRouterも設定されるので。


```terminal
npx create-next-app@latest
```

これを実行したら一通り生成されるのでこれでOK.
出来上がったら、以下を実行すればローカル環境が動きます。

```terminal
npm run dev
```

## 不要処理を取り除いてシンプルに
作った環境はいくつかテンプレートで色々と入ってるので、それがまず邪魔なので取り外します。

### global.css の修正
デフォルトのglobalCSS設定にフォント設定や色々な設定が入っちゃってるのでVanilaな環境にします。

```css:app/globals.css
@tailwind base;
@tailwind components;
@tailwind utilities;

// 後続のコードは全て削除
```

### layout.jsx の修正
Defaultはいくつかローカルフォント読み込みとか入れてるので不要なので取り外します。
個人的にはWeb Fontを使いたいので、一旦Noto Sans JPを設定したものを入れています。
Metadataの機能などはそのまま残しています。

```jsx:app/layout.jsx
import type { Metadata } from "next";
import "./globals.css";
// Google Font からNoto Sans JPを読み込み
import { Noto_Sans_JP } from 'next/font/google'

export const metadata: Metadata = {
  title: "(Default title tag)",
  description: "(Default description tag)",
};

const notoSansJP = Noto_Sans_JP({
  subsets: ['latin'],
  variable: '--font-noto-sans-jp'
})

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="ja">
      <head>
        <meta charSet="UTF-8"></meta>
      </head>
      <body className={notoSansJP.className}>
        {children}
      </body>
    </html>
  );
}
```

### 不要ファイルの削除
app/fonts とかのディレクトリにローカルフォントが入ってますが、使わないのでディレクトリごと削除。

## デフォルトで入れた方がいいファイルを追加

### not-found.tsxの追加
not-found.tsxは404エラー時に出るやつ。入れなくてもデフォルト処理は出ますけどね。以下はサンプル。

```jsx:app/not-found.tsx
export default function NotFound(){
  return (
    <h1> Not Found.</h1>
  )
}
```

### global-error.tsx（などのエラー処理）
詳しくはここを見た方がいいと思います。エラー時の処理ですね。

https://ja.next-community-docs.dev/docs/app-router/building-your-application/routing/error-handling

以下は私が入れた設定。実はあんまりよくわかってない。

```jsx:app/global-error.tsx
export default function GlobalError({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  return (
    <html>
      <body>
        <h2>Global Error</h2>
        <div>{error.message}</div>
        <button onClick={() => reset()}>Try again</button>
      </body>
    </html>
  )
}
```

## ページ作成作業
Next.jsがいいなと思ったのはディレクトリの名称でルーティングされるところ。

例）
/blog/ というディレクトリでアクセスさせたいなら
 -> app/blog/page.tsx を作ればOK。

 他にも色々機能ありますが、一旦これだけわかれば十分だとわかった。詳しくはここ。

 https://ja.next-community-docs.dev/docs/app-router/building-your-application/routing/defining-routes

 ここら辺の周辺ページを見れば色々機能がわかるかと。


 ### ページレイアウト構成を考える

ここからページのレイアウト構成をまずは考えました。layout.tsxに共通ヘッダーやフッターを読み込ませれば良いんじゃない？ということで、layout.tsxはこのように、HeaderとFooterというコンポーネントを読み込ませるような形にすればいいかなと。

```jsx:app/layout.tsx(最終的なイメージ)

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="ja">
      <head>
        <meta charSet="UTF-8"></meta>
      </head>
      <body className={notoSansJP.className}>
        <div>
          <Header /> 
          {children}
          <Footer />
        </div>
      </body>
    </html>
  );
}
```

### Header/Footerコンポーネントを作る
ということで、コンポーネントを作りましょう。
Next.jsのテンプレート自体にComponentというものは用意されてないので、自分で設定します。app配下にcomponentsというディレクトリを作成してこんな感じで２つ用意。

ちな、デザインは後で入れます。

```jsx:app/components/header.jsx
export default function Header() {
  return (
    <header>
      <div>
      </div>
    </header>
  )
}
```

```jsx:app/components/footer.jsx
export default function Footer() {
  return (
    <footer>
      <aside>
        <p>
          サイト名
        </p>
      </aside>
      <nav>
      </nav>
    </footer>
  )
}
```

これでさっきのlayout.tsxを修正したら使えます。
で、importを使って取り込みたいんですが、componentsみたいなパスをいい感じに設定したいのでTypeScriptの機能を利用します。

### Component読み込みパスをわかりやすくするためのTypeScriptのpath指定

全部設定書きましたが、要はcompilierOptions.pathsに"@components" というものを設定追加しています。これで設定わかりやすく。

```json:tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@components/*": ["app/components/*"]
    },
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "noEmit": true,
    "incremental": true,
    "module": "esnext",
    "esModuleInterop": true,
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "plugins": [
      {
        "name": "next"
      }
    ]
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules"]
}
```

上記のように書くと、例えばlayout.tsxでcomponentsディレクトリ先のファイルを読む場合はこうなります。

```tsx:app/layout.tsx
import Header from "@components/header";
import Footer from "@components/footer";
```

### 画像の取り扱いについて
なんか画像周りはこのあとGitHub Pagesでも悩まされるのですが、結論これでいいんじゃないかな。

nextのImageコンポーネントを読み込み
```
import Image from "next/image";
```

これで、Imageタグを使ってやればいい気がします。


## ページデザイン周り(TailwindCSS)
これは基本的にTailwindCSSと、DaisyUIを使ってやりました。
DaisyUIはTailwindCSSをさらにラッピングしてくれており、高速サイト構築には打って付け。

https://daisyui.com

Tailwindの基本の考え方が最初よくわからなかったけど、要は下手にClass名とか統一してつけると言うよりも、大量に用意されたClass名のルールを使って設定していけば、HTMLとクラス名だけ見てわかるようになるのでいいと言う考えということがわかりました。

### レイアウト関連

レイアウトをするために必要な知識はpadding/border/margin周りの設定方法ですが、このページがわかりやすかったです。これで大体わかりました。

https://skillhub.jp/courses/261/lessons/2082

### 角丸や影の付け方

こんな感じでbox要素を角丸にしたり影にしたいならshadowやroundedの設定でいけます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443/a901db9d-5422-d36a-6256-badf6e231eae.png)

こんな感じ。
```
<div className="bg-white shadow shadow-2xl rounded-lg">
     text
</div>
```

# GitHub Pagesリリース用の設定

## GitHub Pagesの設定
とりあえず、WorkflowでこれをインストールすればOK。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443/f4f4b63c-f302-647d-21bb-f77b4417195d.png)

で、SettingsでGitHub Pagesの設定ではこのようにGitHub Actionsで実行するように。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443/4638a6f0-233f-3587-2dcd-166dac22d8b4.png)

さらに、その下にあるCustom Domainを設定すれば独自ドメインで設定可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443/9b26ff28-0399-aa54-f34d-0ad49e73d621.png)

なお、設定する場合はDNS設定をしましょう。（CNAME設定）

## GitHub Pages独自ドメインリリース用の設定
独自ドメインに切り替えると今度は画像パスの問題が起きます。
そこで、今度はこのように設定することで回避可能。



```js:next.config.mjs
/** @type {import('next').NextConfig} */
const nextConfig = {
  output: "export",
  // github Pages の本番リリース時に独自ドメインを使う場合、ディレクトリが減るので意図的に減らす必要あり(package.json側も修正)
  assetPrefix: process.env.NODE_ENV === "production" ? "" : "",
  images: { unoptimized: true },
};

export default nextConfig;
```


scripts.build のところで設定したNODE_ENVのバージョンを指定するように。（これで毎度GitHub上でbuildした時にこの設定が）

```json:package.json（一部)
{
  "name": "packageName",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "env NODE_ENV='production' next build",
    "start": "next start",
    "lint": "next lint"
  },
}
```


これで大体一通り設定完了です！
色々設定試行錯誤しながら上手く動かせました。