diff --git a/packages/next/server/next-dev-server.ts b/packages/next/server/next-dev-server.ts
index 3df13d0499adf..a74f71f0d5f23 100644
--- a/packages/next/server/next-dev-server.ts
+++ b/packages/next/server/next-dev-server.ts
@@ -140,6 +140,10 @@ export default class DevServer extends Server {
return
}
+ const regexPageExtension = new RegExp(
+ `\\.+(?:${this.nextConfig.pageExtensions.join('|')})$`
+ )
+
let resolved = false
return new Promise(resolve => {
const pagesDir = this.pagesDir
@@ -163,18 +167,13 @@ export default class DevServer extends Server {
const dynamicRoutedPages = []
const knownFiles = wp.getTimeInfoEntries()
for (const [fileName, { accuracy }] of knownFiles) {
- if (accuracy === undefined) {
+ if (accuracy === undefined || !regexPageExtension.test(fileName)) {
continue
}
let pageName =
'/' + relative(pagesDir!, fileName).replace(/\\+/g, '/')
-
- pageName = pageName.replace(
- new RegExp(`\\.+(?:${this.nextConfig.pageExtensions.join('|')})$`),
- ''
- )
-
+ pageName = pageName.replace(regexPageExtension, '')
pageName = pageName.replace(/\/index$/, '') || '/'
if (!isDynamicRoute(pageName)) {
diff --git a/test/integration/dynamic-routing/pages/index.js b/test/integration/dynamic-routing/pages/index.js
index 156f952d43962..793621998daf9 100644
--- a/test/integration/dynamic-routing/pages/index.js
+++ b/test/integration/dynamic-routing/pages/index.js
@@ -44,6 +44,18 @@ const Page = () => (
Catch-all route (multi)
+
+ Nested Catch-all route (single)
+
+
+ Nested Catch-all route (multi)
+
)
diff --git a/test/integration/dynamic-routing/pages/p1/p2/nested-all-ssg/[...rest]/index.js b/test/integration/dynamic-routing/pages/p1/p2/nested-all-ssg/[...rest]/index.js
new file mode 100644
index 0000000000000..0a44171410f32
--- /dev/null
+++ b/test/integration/dynamic-routing/pages/p1/p2/nested-all-ssg/[...rest]/index.js
@@ -0,0 +1,15 @@
+import styles from './styles.module.css'
+
+function All({ params }) {
+ return (
+
+ {JSON.stringify(params)}
+
+ )
+}
+
+export function unstable_getStaticProps({ params }) {
+ return { props: { params } }
+}
+
+export default All
diff --git a/test/integration/dynamic-routing/pages/p1/p2/nested-all-ssg/[...rest]/styles.module.css b/test/integration/dynamic-routing/pages/p1/p2/nested-all-ssg/[...rest]/styles.module.css
new file mode 100644
index 0000000000000..6446ebfd42749
--- /dev/null
+++ b/test/integration/dynamic-routing/pages/p1/p2/nested-all-ssg/[...rest]/styles.module.css
@@ -0,0 +1,3 @@
+.test {
+ color: red;
+}
diff --git a/test/integration/dynamic-routing/test/index.test.js b/test/integration/dynamic-routing/test/index.test.js
index 0b3d8f125d260..c5debfe8529c0 100644
--- a/test/integration/dynamic-routing/test/index.test.js
+++ b/test/integration/dynamic-routing/test/index.test.js
@@ -257,6 +257,24 @@ function runTests(dev) {
})
})
+ it('[nested ssg: catch all] should pass param in getStaticProps during SSR', async () => {
+ const data = await renderViaHTTP(
+ appPort,
+ `/_next/data/${buildId}/p1/p2/nested-all-ssg/test1.json`
+ )
+ expect(JSON.parse(data).pageProps.params).toEqual({ rest: ['test1'] })
+ })
+
+ it('[nested ssg: catch all] should pass params in getStaticProps during SSR', async () => {
+ const data = await renderViaHTTP(
+ appPort,
+ `/_next/data/${buildId}/p1/p2/nested-all-ssg/test1/test2.json`
+ )
+ expect(JSON.parse(data).pageProps.params).toEqual({
+ rest: ['test1', 'test2'],
+ })
+ })
+
it('[predefined ssg: catch all] should pass param in getStaticProps during SSR', async () => {
const data = await renderViaHTTP(
appPort,
@@ -321,6 +339,34 @@ function runTests(dev) {
}
})
+ it('[nested ssg: catch-all] should pass params in getStaticProps during client navigation (single)', async () => {
+ let browser
+ try {
+ browser = await webdriver(appPort, '/')
+ await browser.elementByCss('#nested-ssg-catch-all-single').click()
+ await browser.waitForElementByCss('#nested-all-ssg-content')
+
+ const text = await browser.elementByCss('#nested-all-ssg-content').text()
+ expect(text).toBe('{"rest":["hello"]}')
+ } finally {
+ if (browser) await browser.close()
+ }
+ })
+
+ it('[nested ssg: catch-all] should pass params in getStaticProps during client navigation (multi)', async () => {
+ let browser
+ try {
+ browser = await webdriver(appPort, '/')
+ await browser.elementByCss('#nested-ssg-catch-all-multi').click()
+ await browser.waitForElementByCss('#nested-all-ssg-content')
+
+ const text = await browser.elementByCss('#nested-all-ssg-content').text()
+ expect(text).toBe('{"rest":["hello1","hello2"]}')
+ } finally {
+ if (browser) await browser.close()
+ }
+ })
+
it('should update dynamic values on mount', async () => {
const html = await renderViaHTTP(appPort, '/on-mount/post-1')
expect(html).toMatch(/onmpost:.*pending/)
@@ -465,6 +511,12 @@ function runTests(dev) {
page: '/p1/p2/all-ssr/[...rest]',
regex: normalizeRegEx('^\\/p1\\/p2\\/all\\-ssr\\/(.+?)(?:\\/)?$'),
},
+ {
+ page: '/p1/p2/nested-all-ssg/[...rest]',
+ regex: normalizeRegEx(
+ '^\\/p1\\/p2\\/nested\\-all\\-ssg\\/(.+?)(?:\\/)?$'
+ ),
+ },
{
page: '/p1/p2/predefined-ssg/[...rest]',
regex: normalizeRegEx(