『Qiita: Next.jsで作ったアプリをGitHub Pagesにデプロイする@ozaki25』や、『Qiita: Next.jsをGitHub Pagesにデプロイしたらリンクが壊れた』、『GitHub: gh-pages Hello World example』にNext.jsのWebサイトをGithub Pagesに投稿する方法が載っていますが、どれも静的ページのみへのルーティングを説明していて、動的ルーティングには深く言及されていません。
そこで、Next.js 9.4でサイトをGitHub Pagesにあげたところ、動的ルーティングでハマってしまいました。結果、対処法がわからずにVercelに移行したのですが、Next.js 9.5のアップデートでベースパスをカスタマイズできる機能が追加され、自分がハマっていた動的ルーティングが解決しました!🎉
この記事では、Next.js 9.4の動的ルーティングのハマっていた背景とNext.js 9.5での対処法について説明します。
Next.js 9.4 × GitHub Pages 🤔
ご存知だと思いますが、GitHub Pagesはhttps://[username].github.io/[repository-name]
といったurlにマッピングされます。これによって、以下のような普通のNext.jsのルーティングでは、https://[username].github.io/[repository-name]/items
に行ってほしいのに、https://[username].github.io/items
にルーティングされてしまい、リロード時にエラーとなってしまいます。
const MyLink = () => (
<Link href="/items">
<a>Item</a>
</Link>
)
なので、『Qiita: Next.jsをGitHub Pagesにデプロイしたらリンクが壊れた』などに記載されている変更が必要となります。
module.exports = {
assetPrefix: process.env.NODE_ENV === 'production' ? '/[repository-name]' : ''
}
const withRootPath = (path: string) =>
process.env.NODE_ENV === 'production' ? `/[repository-name]/${path}` : path
const MyLink = () => (
<Link href={withRootPath("/items")}>
<a>Item</a>
</Link>
)
これで、静的なリンクへはうまくいきます。が、前述している通り、動的ルーティングの場合は同様に以下のようにしてもプリフェッチされず、ブラウザのロードが挟まれてしまいます。
const withRootPath = (path: string) =>
process.env.NODE_ENV === 'production' ? `/[repository-name]/${path}` : path
const MyLink = () => (
<Link href={withRootPath("/items")}>
<a>Item</a>
</Link>
)
const MyDynamicLink = () => (
<Link href={withRootPath("/items/[id]")} as={withRootPath("/items/a")}>
<a>Item</a>
</Link>
)
また、上の記事に記載されている以下の方法で実装すると、エラーを出力します。
const MyDynamicLink = () => (
<Link href="/items/[id]" as={withRootPath("/items/a")}>
<a>Item</a>
</Link>
)
これは、href
とas
が対応していない事によるエラーです。詳しい内容はNext.jsのリポジトリに記入してあります。vercel/next.js-Incompatible href and as values
…ということで、自分の知る限りではGitHubでNext.jsの動的ルーティングを実装するには、プリフェッチとブラウザへのロードを妥協するしかありませんでした。
Next.js 9.5 × GitHub Pages 🎉
最初に説明している通り、Next.js 9.5でベースパスを設定できるようになりました。対処法も簡単で、next.config.js
に追加するだけでOKです。
module.exports = {
basePath: process.env.NODE_ENV === 'production' ? '/[repository-name]' : ''
}
これだけで、妥協しない動的ルーティングが可能になります🎉
おわりに
自分の認識不足で、Next.js 9.4でも動的ルーティングでプリフェッチできる方法がありましたら、教えてください。
デモとして使用したリポジトリ