rewrites
rewritesを使用すると、リクエストパスを異なる宛先パスにマッピングできます。
rewritesはURLプロキシとして動作し、宛先パスを隠して、ユーザーがサイト上で位置を変えていないように見せます。それに対して、redirectsは新しいページにリダイレクトし、URLの変更を表示します。
rewritesを使用するには、next.config.js
のrewrites
キーを使用します:
module.exports = {
async rewrites() {
return [
{
source: '/about',
destination: '/',
},
]
},
}
rewritesはクライアント側のルーティングに適用され、<Link href="/about">
は上記の例でrewriteが適用されます。
rewrites
は、source
とdestination
プロパティを持つオブジェクトを含む配列または配列のオブジェクト(下記参照)を返すことが期待される非同期関数です:
source
:String
- リクエストパスパターンですdestination
:String
- ルート先のパスですbasePath
:false
ま たはundefined
-false
の場合、basePathは一致に含まれません。外部のrewritesのみに使用されますlocale
:false
またはundefined
- 一致する際にlocaleを含めるべきかどうかhas
はtype
、key
およびvalue
プロパティを持つhas オブジェクトの配列ですmissing
はtype
、key
およびvalue
プロパティを持つmissing オブジェクトの配列です
rewrites
関数が配列を返すとき、rewritesはファイルシステム(ページや/public
ファイル)を確認した後、動的ルートの前に適用されます。rewrites
関数が特定の形状を持つ配列のオブジェクトを返すと、この動作を変更して、Next.jsのv10.1
以降、より細かく制御することができます:
module.exports = {
async rewrites() {
return {
beforeFiles: [
// これらのrewritesはヘッダー/リダイレクトの後にチェックされ、
// ページファイルを上書きできる_next/publicファイルを含む
// すべてのファイルの前にチェックされます
{
source: '/some-page',
destination: '/somewhere-else',
has: [{ type: 'query', key: 'overrideMe' }],
},
],
afterFiles: [
// これらのrewritesは、ページ/publicファイルが確認された後、
// 動的ルートの前にチェックされます
{
source: '/non-existent',
destination: '/somewhere-else',
},
],
fallback: [
// これらのrewritesは、ページ/publicファイルと動的ルートが
// チェックされた後に チェックされます
{
source: '/:path*',
destination: `https://my-old-site.com/:path*`,
},
],
}
},
}
Good to know:
beforeFiles
のrewritesは、ソースに一致した直後にファイルシステム/動的ルートを確認せず、すべてのbeforeFiles
がチェックされるまで続行します。
Next.jsルートのチェック順序は以下のとおりです:
- headersがチェック/適用されます
- redirectsがチェック/適用されます
beforeFiles
rewritesがチェック/適用されます- publicディレクトリ、
_next/static
ファイル、非動的ページからの静的ファイルがチェック/提供されます afterFiles
rewritesがチェック/適用され、これらのrewritesが一致する場合、動的ルート/静的ファイルを各一致後にチェックしますfallback
rewritesがチェック/適用され、これは404ページのレンダリング前、動的ルート/すべての静的アセットのチェック後に適用されます。fallback: true/'blocking'をgetStaticPaths
で利用している場合、next.config.js
で定義したフォールバックのrewritesは実行されません。
リライトパラメータ
リライトでパラメータを使用する場合、パラメータがdestination
で使用されていない場合、デフォルトでクエリで渡されます。
module.exports = {
async rewrites() {
return [
{
source: '/old-about/:path*',
destination: '/about', // パラメータ:pathはここで使用されていないため、自動的にクエリで渡されます
},
]
},
}
destination
でパラメータが使用されている場合、パラメータはクエリで自動的には渡されません。
module.exports = {
async rewrites() {
return [
{
source: '/docs/:path*',
destination: '/:path*', // パラメータ:pathはここで使用されているため、自動的にクエリで渡されません
},
]
},
}
destination
でパラメータがすでに使用されている場合、クエリで手動でパラメータを渡すことはできます。クエリをdestination
で指定します。
module.exports = {
async rewrites() {
return [
{
source: '/:first/:second',
destination: '/:first?second=:second',
// パラメータ:firstはdestinationで使用されていますが、
// クエリで自動的に追加されることはありません
// ただし、上記のように手動で追加できます
},
]
},
}
Good to know: Automatic Static Optimizationまたはprerenderingからのリライトによる静的ページは、ハイドレーション後にクライアントで解析され、クエリで提供されます。
パスマッチング
パスマッチングは許可されています。例えば、/blog/:slug
は/blog/hello-world
に(ネストされたパスなしで)マッチングします:
module.exports = {
async rewrites() {
return [
{
source: '/blog/:slug',
destination: '/news/:slug', // マッチしたパラメータはdestinationで使用できます
},
]
},
}
ワイルドカードパスマッチング
ワイルドカードパスをマッチングするには、パラメータの後に*
を使用します。例えば、/blog/:slug*
は/blog/a/b/c/d/hello-world
にマッチングします:
module.exports = {
async rewrites() {
return [
{
source: '/blog/:slug*',
destination: '/news/:slug*', // マッチしたパラメータはdestinationで使用できます
},
]
},
}
正規表現パスマッチング
正規表現パスをマッチングするには、パラメータの後に括弧で正規表現をラップします。例えば、/blog/:slug(\\d{1,})
は/blog/123
にはマッチしますが、/blog/abc
にはマッチしません:
module.exports = {
async rewrites() {
return [
{
source: '/old-blog/:post(\\d{1,})',
destination: '/blog/:post', // マッチしたパラメータはdestinationで使用できます
},
]
},
}
次の文字(
、)、
、、
[、
]、
|、
`、^
、.
、:
、*
、+
、-
、?
、$
は正規表現パスマッチングに使用されるため、source
で非特別な値として使用する場合は、前に\\
を追加してエスケープする必要があります:
module.exports = {
async rewrites() {
return [
{
// これは`/english(default)/something`がリクエストされたときにマッチします
source: '/english\\(default\\)/:slug',
destination: '/en-us/:slug',
},
]
},
}
ヘッダー、クッキー、クエリマッチング
ヘッダー、クッキー、またはクエリの値がhas
フィールドと一致する場合、またはmissing
フィールドと一致しない場合にのみリライトを適用する場合は、has
フィールドまたはmissing
フィールドを使用できます。source
とすべてのhas
項目がマッチし、すべてのmissing
項目がマッチしない場合にのみ、リライトが適用されます。
has
およびmissing
項目は、以下のフィールドを持つことができます:
type
:String
-header
、cookie
、host
、またはquery
のいずれかでなければなりません。key
:String
- 一致対象の選択されたタイプのキー。value
:String
またはundefined
- チェックする値、undefined
の場合、任意の値が一致します。特定の部分をキャプチャするための正規表現のような文字列を使用できます。例えば、値first-(?<paramName>.*)
がfirst-second
の場合、second
はdestination
で:paramName
として使用可能です。
module.exports = {
async rewrites() {
return [
// ヘッダー`x-rewrite-me`が存在する場合、
// このリライトが適用されます
{
source: '/:path*',
has: [
{
type: 'header',
key: 'x-rewrite-me',
},
],
destination: '/another-page',
},
// ヘッダー`x-rewrite-me`が存在しない場合、
// このリライトが適用されます
{
source: '/:path*',
missing: [
{
type: 'header',
key: 'x-rewrite-me',
},
],
destination: '/another-page',
},
// ソース、クエリ、クッキーが一致する場合、
// このリライトが適用されます
{
source: '/specific/:path*',
has: [
{
type: 'query',
key: 'page',
// pageの値はnamed capture groupを使用しない場合、
// destinationでは利用できません
value: 'home',
},
{
type: 'cookie',
key: 'authorized',
value: 'true',
},
],
destination: '/:path*/home',
},
// ヘッダー`x-authorized`が存在し、
// 一致する値を含む場合、このリライトが適用されます
{
source: '/:path*',
has: [
{
type: 'header',
key: 'x-authorized',
value: '(?<authorized>yes|true)',
},
],
destination: '/home?authorized=:authorized',
},
// ホストが`example.com`の場合、
// このリライトが適用されます
{
source: '/:path*',
has: [
{
type: 'host',
value: 'example.com',
},
],
destination: '/another-page',
},
]
},
}
リライトを外部URLに変更する
rewritesを使用すると、外部URLにリライトできます。これはNext.jsを徐々に導入するのに特に便利です。以下は、メインアプリの/blog
ルートを外部サイトにリダイレクトするための例です。
module.exports = {
async rewrites() {
return [
{
source: '/blog',
destination: 'https://example.com/blog',
},
{
source: '/blog/:slug',
destination: 'https://example.com/blog/:slug', // マッチしたパラメータはdestinationで使用できます
},
]
},
}
trailingSlash: true
を使用している場合、source
パラメータにもトレイリングスラッシュを挿入する必要があります。宛先サーバーもトレイリングスラッシュを期待している場合は、destination
パラメータにも含めるべきです。
module.exports = {
trailingSlash: true,
async rewrites() {
return [
{
source: '/blog/',
destination: 'https://example.com/blog/',
},
{
source: '/blog/:path*/',
destination: 'https://example.com/blog/:path*/',
},
]
},
}
Next.jsのインクリメンタル導入
Next.jsのルートをすべてチェックした後、既存のウェブサイトへのプロキシにフォールバックすることもできます。
この方法を使用すると、より多くのページをNext.jsに移行する際に、リライトの構成を変更する必要がありません。
module.exports = {
async rewrites() {
return {
fallback: [
{
source: '/:path*',
destination: `https://custom-routes-proxying-endpoint.vercel.app/:path*`,
},
],
}
},
}