👻

Next.jsのAppruterを使ってみて困った小さなことたち

2024/01/27に公開
6

今回、初めてReact × Next.jsを使って個人開発をしたので、開発中に困った些細なことをまとめてみました。初学者なのでつよつよエンジニアの方たちには参考にはならないと思いますが、興味ある方は最後までお読みいただけると嬉しいです!

画像の配置

Next.jsのver.12などでは、srcフォルダの中に画像フォルダを作成して、使用したい画像を格納していたと思います。

しかし、Approuterになるとsrc(app)フォルダと同じ階層に[public]フォルダを作成する必要があります。(これをしないと画像の読み込み時にエラーになります)
例を以下に載せておきます。

--2024/1/29追記--
コメントで教えていただいたのですが、画像ファイルに関してはImageタグを使用してローカルファイルをsrcに直接渡すことも可能っぽいです!

widthやheightなどはimport元のファイルをベースにNext.jsが自動で設定してくれます。
詳細知りたい方はこちらも読んでみてください!

アイコンの設定方法

HTMLのHead部分に記載しているアイコン情報をどこに書きゃいいんだ?という話です。
Reactも関係してくる部分なので、この記事で書こうか迷いましたがまとめちゃいます。

Next.jsの大きな特徴であるファイルベースルーティング機能のせい(?)で、初学者の僕はどこに書けばいいかわかりませんでした。

結論からいうと、各pageの冒頭部分に記載しても表示できます
(なんかどこかでまとめられてるんじゃね?っていう甘い考えのせいで、逆に混乱してましたw)

アイコンとかfaviconの設定などで使うこともあるかと思いますので、何かの参考になれば幸いです!

--2024/1/29追記--
アイコンやfaviconの設定はもっと楽な方法があるとコメントで教えていただきました!
favicon, icon, apple-iconとそれぞれ設定したい画像ファイルの名前を変更して、/appフォルダの中に置くだけだそうです、、!(めちゃくちゃ便利)

例えば、私は今回iphoneのホーム画面にブックマークした時のアイコンを設定したかったのですが、その場合は以下のようなファイル名になります。
apple-icon.jpg

拡張子は例です。
それぞれアイコンの種類で設定できる拡張子などは決まっているっぽいので、詳しく知りたい方は公式Docを参考にしてみてくださいmm

supabaseとの連携方法

supabaseというDBサービスがあるのですが、今回の開発ではそちらを利用させていただきました。

そこでsupabaseとプロダクトを連携する際の手順を以下に記載します。

  1. .env.localファイルをsrc/appフォルダに作成
  2. 自身のsupabaseへのURLやANON KEYなどを定義
NEXT_PUBLIC_SUPABASE_URL=ご自身のURL
NEXT_PUBLIC_SUPABASE_ANON_KEY=ご自身のANON KEY

命名に関してはsupabaseの公式ドキュメントで決められていたはずなので、これに従いましょう
3. utilsなどの名前のフォルダを作成
4. さらにその配下に、定義したURL/ANON KEYを宣言して、exportする

import { createClient } from "@supabase/supabase-js";

const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;

export const supabase = createClient(supabaseUrl, supabaseAnonKey);

上記のような感じで宣言してあげます。基本的にはコピペでいけるはずです(はず)
事前準備などは公式ドキュメントに載っているので、確認してみてくださいmm

という流れになります。
exportしたモノたちは、DBからデータ取得する際や逆にデータを入れる際に扱うので、importするのを忘れずに!!

Discussion

Honey32Honey32

失礼します。僕の手元で確認はしていませんが、

「画像の配置」については「画像ファイルを import してそのまま src に渡す」ことが可能なはずです。

import Image from 'next/image'
import profilePic from './me.png'
 
export default function Page() {
  return (
    <Image
      src={profilePic}
      alt="Picture of the author"
      // width={500} automatically provided
      // height={500} automatically provided
      // blurDataURL="data:..." automatically provided
      // placeholder="blur" // Optional blur-up while loading
    />
  )
}

Next.js のドキュメントの該当部分です。

https://nextjs.org/docs/app/building-your-application/optimizing/images#local-images


「Headerに記載する際の書き方」については、自力で head の中身を書く必要のあるケースは少ないはずです。

favicon であれば、ファイルベースのルーティングで、所定の名前のファイルを置けば Next.js が勝手に設定してくれます。

https://nextjs.org/docs/app/api-reference/file-conventions/metadata/app-icons

そのように所定の名前のファイルが設定できないものでも、page.tsxlayout.tsx から export する metadatagenerateMetadata で出来るはずです。(すでにご存知であれば恐縮ですが、この記事の文章からは窺い知れなかったので)

https://nextjs.org/docs/app/building-your-application/optimizing/metadata

Choko KakiChoko Kaki

ありがとうございます!
どちらも私が把握しきれていなかった部分になりますので、非常に参考になりました。

画像に関しては、今回の私の実装では、配列にsrcを組み込んでmapを使って並べて表示させるという方法をとっていました。逆に私のようなケースでない限りは、Honeyさんにご教示していただいた方法のほうが良さそうですね!

またfaviconやアイコンに関しては、教えていただいた方法の方が圧倒的に楽だったので、すぐ切り替えました!wありがとうございます!

独学でやっていたので、至らぬ点が多く申し訳ございません。記事も適宜修正します。

Honey32Honey32

いえいえ、少しでもお助けできて幸いです!


追加になりますが、

配列にsrcを組み込んでmapを使って並べて表示させる

というところも、もしかしたら import で書くことができるかもしれません。

「ビルドしたときに(画像の width, height のようなデータを使って)画像の最適な扱いをNext.jsにやってもらう」ことのほうが、目先の「コードの短さ」よりも利益が大きいと思うので、可能ならそちらに寄せたほうが良いと思います。

import twitterXLogo from "./twitter-x.png";
import hatenaLogo from "./hatena.png";

const socials = {
  twitterX: {
    logo: twitterXLogo,
    alt: "Twitter(現X)",
  },
  hatena: {
    logo: hatenaLogo,
    alt: "はてなブックマーク"
  },
};


// JSXでこんな感じで書ける
{
  Object.entries(socials).map(([key, { logo, alt }]) => (
    <Image key={key} src={logo} alt={alt} />
  );
}

Choko KakiChoko Kaki

参考のコードまでありがとうございます!!修正してみます!

ちなみに画像の扱いをNext.jsに行ってもらうメリットというのは、具体的にどのような点なのでしょうか、、?
widthとheightとかの設定だけだと結果的にコード量は大きくは減らないのかなと思いまして、、

拙い質問で恐縮です、、!

Honey32Honey32

Imageの width, height を毎回自分で書くのと、バンドル時に勝手に画像ファイルの縦横を読み取ってもらうのとを比べると、

前者だと、画像ファイルを差し替えるたびに、そのファイルの縦横サイズの情報を確認して、手書きのwidth/heightとの間で矛盾がないか常に気にする必要があります。

なので、互いに矛盾してしまう可能性のある情報が複数の箇所に存在するのは避けて、「画像ファイル」という一つの情報源から読み取る形にするほうが良いです。(Single Source of Truth と呼ばれる実装上の原則です)

Choko KakiChoko Kaki

なるほど、、!すごく理解が深まりました!ありがとうございます!