diff --git a/packages/next/server/base-server.ts b/packages/next/server/base-server.ts index 51baa1aedb35..73a8413f9410 100644 --- a/packages/next/server/base-server.ts +++ b/packages/next/server/base-server.ts @@ -465,8 +465,10 @@ export default abstract class Server { : matchedPathname let srcPathname = isDataUrl - ? parsedMatchedPath.pathname?.replace(/\.json$/, '') || - matchedPathnameNoExt + ? this.stripNextDataPath( + parsedMatchedPath.pathname?.replace(/\.json$/, '') || + matchedPathnameNoExt + ) || '/' : matchedPathnameNoExt if (this.nextConfig.i18n) { @@ -1338,21 +1340,6 @@ export default abstract class Server { this.nextConfig.i18n?.locales ).pathname - const stripNextDataPath = (path: string) => { - if (path.includes(this.buildId)) { - const splitPath = path.substring( - path.indexOf(this.buildId) + this.buildId.length - ) - - path = denormalizePagePath(splitPath.replace(/\.json$/, '')) - } - - if (this.nextConfig.i18n) { - return normalizeLocalePath(path, locales).pathname - } - return path - } - const handleRedirect = (pageData: any) => { const redirect = { destination: pageData.pageProps.__N_REDIRECT, @@ -1383,8 +1370,8 @@ export default abstract class Server { // remove /_next/data prefix from urlPathname so it matches // for direct page visit and /_next/data visit if (isDataReq) { - resolvedUrlPathname = stripNextDataPath(resolvedUrlPathname) - urlPathname = stripNextDataPath(urlPathname) + resolvedUrlPathname = this.stripNextDataPath(resolvedUrlPathname) + urlPathname = this.stripNextDataPath(urlPathname) } let ssgCacheKey = @@ -1743,6 +1730,22 @@ export default abstract class Server { } } + private stripNextDataPath(path: string) { + if (path.includes(this.buildId)) { + const splitPath = path.substring( + path.indexOf(this.buildId) + this.buildId.length + ) + + path = denormalizePagePath(splitPath.replace(/\.json$/, '')) + } + + if (this.nextConfig.i18n) { + const { locales } = this.nextConfig.i18n + return normalizeLocalePath(path, locales).pathname + } + return path + } + private async renderToResponse( ctx: RequestContext ): Promise { diff --git a/test/production/required-server-files.test.ts b/test/production/required-server-files.test.ts index 1b105c739546..8f5e3dd5084c 100644 --- a/test/production/required-server-files.test.ts +++ b/test/production/required-server-files.test.ts @@ -56,6 +56,10 @@ describe('should set-up next', () => { source: '/an-ssg-path', destination: '/hello.txt', }, + { + source: '/fallback-false/:path', + destination: '/hello.txt', + }, ], afterFiles: [ { @@ -980,6 +984,35 @@ describe('should set-up next', () => { expect(JSON.parse($('#router').text()).asPath).toBe('/an-ssg-path') }) + it('should have correct asPath on dynamic SSG page fallback correctly', async () => { + const toCheck = [ + { + pathname: '/fallback-false/first', + matchedPath: '/fallback-false/first', + }, + { + pathname: '/fallback-false/first', + matchedPath: `/_next/data/${next.buildId}/fallback-false/first.json`, + }, + ] + for (const check of toCheck) { + console.warn('checking', check) + const res = await fetchViaHTTP(appPort, check.pathname, undefined, { + headers: { + 'x-matched-path': check.matchedPath, + }, + redirect: 'manual', + }) + + const html = await res.text() + const $ = cheerio.load(html) + expect($('#page').text()).toBe('blog slug') + expect($('#asPath').text()).toBe('/fallback-false/first') + expect($('#pathname').text()).toBe('/fallback-false/[slug]') + expect(JSON.parse($('#query').text())).toEqual({ slug: 'first' }) + } + }) + it('should copy and read .env file', async () => { const res = await fetchViaHTTP(appPort, '/api/env') diff --git a/test/production/required-server-files/pages/fallback-false/[slug].js b/test/production/required-server-files/pages/fallback-false/[slug].js new file mode 100644 index 000000000000..8296dbc7bd93 --- /dev/null +++ b/test/production/required-server-files/pages/fallback-false/[slug].js @@ -0,0 +1,35 @@ +import { useRouter } from 'next/router' + +export default function Page(props) { + const router = useRouter() + + return ( + <> +

blog slug

+

{JSON.stringify(props)}

+

{JSON.stringify(router.query)}

+

{router.pathname}

+

{router.asPath}

+ + ) +} + +export function getStaticProps({ params }) { + console.log({ blogSlug: true, params }) + + return { + props: { + random: Math.random() + Date.now(), + blogSlug: true, + params, + }, + revalidate: 1, + } +} + +export function getStaticPaths() { + return { + paths: ['/fallback-false/first', '/fallback-false/second'], + fallback: false, + } +}