Skip to content

Commit f6e7a38

Browse files
authored
Add paths field for unstable_getStaticPaths (vercel#10454)
* Add paths field for unstable_getStaticPaths * Make sure to specify page in getStaticPaths errors
1 parent 0183a13 commit f6e7a38

File tree

10 files changed

+68
-33
lines changed

10 files changed

+68
-33
lines changed

packages/next/build/utils.ts

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { recursiveReadDir } from '../lib/recursive-readdir'
1515
import { getRouteMatcher, getRouteRegex } from '../next-server/lib/router/utils'
1616
import { isDynamicRoute } from '../next-server/lib/router/utils/is-dynamic'
1717
import { findPageFile } from '../server/lib/find-page-file'
18+
import { Unstable_getStaticPaths } from '../next-server/server/load-components'
1819

1920
const fileGzipStats: { [k: string]: Promise<number> } = {}
2021
const fsStatGzip = (file: string) => {
@@ -559,9 +560,35 @@ export async function isPageStatic(
559560
// Get the default list of allowed params.
560561
const _validParamKeys = Object.keys(_routeMatcher(page))
561562

562-
const toPrerender: Array<
563-
{ params?: { [key: string]: string } } | string
564-
> = await mod.unstable_getStaticPaths()
563+
const staticPathsResult = await (mod.unstable_getStaticPaths as Unstable_getStaticPaths)()
564+
565+
if (!staticPathsResult || typeof staticPathsResult !== 'object') {
566+
throw new Error(
567+
`Invalid value returned from unstable_getStaticPaths in ${page}. Received ${typeof staticPathsResult} Expected: { paths: [] }`
568+
)
569+
}
570+
571+
const invalidStaticPathKeys = Object.keys(staticPathsResult).filter(
572+
key => key !== 'paths'
573+
)
574+
575+
if (invalidStaticPathKeys.length > 0) {
576+
throw new Error(
577+
`Extra keys returned from unstable_getStaticPaths in ${page} (${invalidStaticPathKeys.join(
578+
', '
579+
)}) The only field allowed currently is \`paths\``
580+
)
581+
}
582+
583+
const toPrerender = staticPathsResult.paths
584+
585+
if (!Array.isArray(toPrerender)) {
586+
throw new Error(
587+
`Invalid \`paths\` value returned from unstable_getStaticProps in ${page}.\n` +
588+
`\`paths\` must be an array of strings or objects of shape { params: [key: string]: string }`
589+
)
590+
}
591+
565592
toPrerender.forEach(entry => {
566593
// For a string-provided path, we must make sure it matches the dynamic
567594
// route.
@@ -594,9 +621,7 @@ export async function isPageStatic(
594621
let builtPage = page
595622
_validParamKeys.forEach(validParamKey => {
596623
const { repeat } = _routeRegex.groups[validParamKey]
597-
const paramValue: string | string[] = params[validParamKey] as
598-
| string
599-
| string[]
624+
const paramValue = params[validParamKey]
600625
if (
601626
(repeat && !Array.isArray(paramValue)) ||
602627
(!repeat && typeof paramValue !== 'string')

packages/next/next-server/server/load-components.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ type Unstable_getStaticProps = (params: {
3232
revalidate?: number | boolean
3333
}>
3434

35-
type Unstable_getStaticPaths = () => Promise<Array<string | ParsedUrlQuery>>
35+
export type Unstable_getStaticPaths = () => Promise<{
36+
paths: Array<string | { params: ParsedUrlQuery }>
37+
}>
3638

3739
type Unstable_getServerProps = (context: {
3840
params: ParsedUrlQuery | undefined
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export async function unstable_getStaticPaths() {
2-
return ['/hello', '/world']
2+
return { paths: ['/hello', '/world'] }
33
}
44

55
export default () => <p>something is missing 🤔</p>

test/integration/dynamic-routing/pages/p1/p2/predefined-ssg/[...rest].js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ export function unstable_getStaticProps({ params }) {
77
}
88

99
export function unstable_getStaticPaths() {
10-
return [
11-
`/p1/p2/predefined-ssg/one-level`,
12-
`/p1/p2/predefined-ssg/1st-level/2nd-level`,
13-
]
10+
return {
11+
paths: [
12+
`/p1/p2/predefined-ssg/one-level`,
13+
`/p1/p2/predefined-ssg/1st-level/2nd-level`,
14+
],
15+
}
1416
}
1517

1618
export default All

test/integration/prerender-invalid-catchall-params/pages/[...slug].js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react'
22

33
// eslint-disable-next-line camelcase
44
export async function unstable_getStaticPaths() {
5-
return [{ params: { slug: 'hello' } }]
5+
return { paths: [{ params: { slug: 'hello' } }] }
66
}
77

88
// eslint-disable-next-line camelcase

test/integration/prerender-invalid-paths/pages/[foo]/[post].js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react'
22

33
// eslint-disable-next-line camelcase
44
export async function unstable_getStaticPaths() {
5-
return [{ foo: 'bad', baz: 'herro' }]
5+
return { paths: [{ foo: 'bad', baz: 'herro' }] }
66
}
77

88
// eslint-disable-next-line camelcase

test/integration/prerender/pages/blog/[post]/[comment].js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ import Link from 'next/link'
33

44
// eslint-disable-next-line camelcase
55
export async function unstable_getStaticPaths() {
6-
return [
7-
'/blog/post-1/comment-1',
8-
{ params: { post: 'post-2', comment: 'comment-2' } },
9-
]
6+
return {
7+
paths: [
8+
'/blog/post-1/comment-1',
9+
{ params: { post: 'post-2', comment: 'comment-2' } },
10+
],
11+
}
1012
}
1113

1214
// eslint-disable-next-line camelcase

test/integration/prerender/pages/blog/[post]/index.js

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@ import { useRouter } from 'next/router'
44

55
// eslint-disable-next-line camelcase
66
export async function unstable_getStaticPaths() {
7-
return [
8-
'/blog/post-1',
9-
{ params: { post: 'post-2' } },
10-
'/blog/[post3]',
11-
'/blog/post-4',
12-
'/blog/post.1',
13-
'/blog/post.1', // handle duplicates
14-
]
7+
return {
8+
paths: [
9+
'/blog/post-1',
10+
{ params: { post: 'post-2' } },
11+
'/blog/[post3]',
12+
'/blog/post-4',
13+
'/blog/post.1',
14+
'/blog/post.1', // handle duplicates
15+
],
16+
}
1517
}
1618

1719
// eslint-disable-next-line camelcase

test/integration/prerender/pages/catchall/[...slug].js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ export async function unstable_getStaticProps({ params: { slug } }) {
88
}
99

1010
export async function unstable_getStaticPaths() {
11-
return [
12-
{ params: { slug: ['first'] } },
13-
'/catchall/second',
14-
{ params: { slug: ['another', 'value'] } },
15-
'/catchall/hello/another',
16-
]
11+
return {
12+
paths: [
13+
{ params: { slug: ['first'] } },
14+
'/catchall/second',
15+
{ params: { slug: ['another', 'value'] } },
16+
'/catchall/hello/another',
17+
],
18+
}
1719
}
1820

1921
export default ({ slug }) => <p id="catchall">Hi {slug?.join('/')}</p>

test/integration/prerender/pages/user/[user]/profile.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import Link from 'next/link'
33

44
// eslint-disable-next-line camelcase
55
export async function unstable_getStaticPaths() {
6-
return []
6+
return { paths: [] }
77
}
88

99
// eslint-disable-next-line camelcase

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy