Next.jsの/pages内でページ以外のコンポーネントを配置する方法
結論
next.config.js
の pageExtensions
オプションを設定すると良いです 💪
module.exports = {
// ページコンポーネントの拡張子を変更する
// 以下の設定の場合、ページコンポーネントは pages/index.page.tsx などのようになる
pageExtensions: ['page.tsx', 'page.ts']
}
具体的な解説
デフォルトの設定では、/pages
内のコンポーネントは全てページを表示するためのコンポーネントとして扱われます。例えば以下のような感じ。
.
├── _app.tsx
├── header.tsx <- index.tsx内でしか使ってないコンポーネントのファイル
└── index.tsx <- ページコンポーネント
import { Header } from "./header";
const HomePage = () => (
<>
{/* ... */}
{/* ここで普通のコンポーネントとして使っている */}
<Header />
{/* ... */}
</>
)
export default HomePage;
/**
* @description HomePageでしか使わないヘッダー
* @note ページコンポーネントではない!
**/
export const Header = () => (
<header>
{/* ... */}
</header>
)
上記のソースコードを実行すると、header.tsx
がページコンポーネントとして扱われてしまい、http://localhost:3000/header
にアクセスすると 404 Not Found にならずにエラーが発生してしまいます。
これの回避策としては、header.tsx
を /pages
から移動する事なんですが、問題なのは header.tsx
が index.tsx
でしか使われていないので、別の所に移動するとソースコードが分散してしまって、後から読むときにフォルダーを行ったり来たりしないといけなくなります。
ソースコードが少なければそれで大丈夫ですが、大きなプロジェクトだとファイルを探すのも大変ですし、エディターの機能を使ってもファイルを見失う事がよくあるので、ただ /pages
から移動するだけなのは、あまりやりたくない訳です。
なので、next.config.js
の pageExtensions
オプションを設定して、ページコンポーネントの拡張子を変更する事によって、/pages
内にページコンポーネント以外のコンポーネントを置けるようにします。
以下のように、next.config.js
を設定しましょう。
module.exports = {
// ページコンポーネントの拡張子を変更する
pageExtensions: ['page.tsx', 'page.ts']
}
上記のように設定したら、以下のようにファイル名を変更します。
.
├── _app.page.tsx <- _app.tsxから変更
├── header.tsx <- ページコンポーネントでは無いので、変更なし!
└── index.page.tsx <- index.tsxから変更
上記の変更をして実行をすると、http://localhost:3000/header
にアクセスしても 404 Not Found が表示されるようになります。
これによって、
- ページコンポーネント ->
.page.tsx
- ページコンポーネント以外のコンポーネント ->
.tsx
で、棲み分けることが出来るようになりました。
めでたしめでたし 👏
高度な使い方
フォルダー構造のちょっとした知見をここで共有したいと思います 🧭
先ず TypeScript では、index.tsx
またはindex.ts
をフォルダー名でインポートすることが出来ます。
.
├── example
| └── index.ts
└── hoge.tsx
export const message = "Example内のindex.tsファイルです"
// フォルダー名のみ指定しているが、example/index.tsの値をインポートできている
import { message } from "./example";
console.log( message ); // 出力結果 : Example内のindex.tsファイルです
上記の挙動を利用して、Next.js の/pages
でもコンポーネントをフォルダーとして管理することが出来ます。
.
├── hoge
| └── index.page.tsx
├── _app.page.tsx
└── index.page.tsx
ここまでの事を応用して、最終的に上記のインポートの挙動と今回のpageExtensions
オプションを組み合わせることで、もっと分かりやすいコンポーネント構造にすることが出来ます。以下はサンプルのフォルダー構造です 👇
.
├── hoge
| ├── components <- hoge内のみで使われているコンポーネントをまとめるフォルダー
| | ├── footer.tsx
| | └── header.tsx
| └── index.page.tsx
|
├── _app.page.tsx
|
└── index.page.tsx
上記のフォルダー構造にすることで、/pages/hoge
内にコンポーネントをたくさん作っても、一目で依存関係が分かりやすくて管理しやすいですし、.module.css
ファイルや、別のファイルをフォルダー内に入れる事も出来るので、コンポーネントの拡張性も上がっています。
StoryBookやテストファイルなどが入れやすいので、私は良く多用しています 👺
参考
この記事は、以下の issues を参考にさせてもらっています 👨💻
あとがき
ここまで読んでくれてありがとうございます 🙏
記事に間違いなどがあれば、コメントなどで教えて頂けると嬉しいです。
これが誰かの参考になれば幸いです。
それではまた 👋
Discussion