diff --git a/packages/next/server/base-server.ts b/packages/next/server/base-server.ts index a575e1ad59696..5168da0997e9b 100644 --- a/packages/next/server/base-server.ts +++ b/packages/next/server/base-server.ts @@ -1323,6 +1323,10 @@ export default abstract class Server { return seg }) .join('/') + + // ensure /index and / is normalized to one key + ssgCacheKey = + ssgCacheKey === '/index' && pathname === '/' ? '/' : ssgCacheKey } const doRender: () => Promise = async () => { diff --git a/test/production/required-server-files-i18n.test.ts b/test/production/required-server-files-i18n.test.ts index 43303acf24854..b74cd9bd9f0d4 100644 --- a/test/production/required-server-files-i18n.test.ts +++ b/test/production/required-server-files-i18n.test.ts @@ -162,6 +162,8 @@ describe('should set-up next', () => { const res2 = await fetchViaHTTP(appPort, '/gssp', undefined, { redirect: 'manual ', }) + await next.patchFile('standalone/data.txt', 'show') + expect(res2.status).toBe(404) expect(res2.headers.get('cache-control')).toBe( 's-maxage=1, stale-while-revalidate' @@ -169,18 +171,18 @@ describe('should set-up next', () => { }) it('should render SSR page correctly', async () => { - const html = await renderViaHTTP(appPort, '/') + const html = await renderViaHTTP(appPort, '/gssp') const $ = cheerio.load(html) const data = JSON.parse($('#props').text()) - expect($('#index').text()).toBe('index page') + expect($('#gssp').text()).toBe('getServerSideProps page') expect(data.hello).toBe('world') - const html2 = await renderViaHTTP(appPort, '/') + const html2 = await renderViaHTTP(appPort, '/gssp') const $2 = cheerio.load(html2) const data2 = JSON.parse($2('#props').text()) - expect($2('#index').text()).toBe('index page') + expect($2('#gssp').text()).toBe('getServerSideProps page') expect(isNaN(data2.random)).toBe(false) expect(data2.random).not.toBe(data.random) }) @@ -244,24 +246,24 @@ describe('should set-up next', () => { it('should render SSR page correctly with x-matched-path', async () => { const html = await renderViaHTTP(appPort, '/some-other-path', undefined, { headers: { - 'x-matched-path': '/', + 'x-matched-path': '/gssp', }, }) const $ = cheerio.load(html) const data = JSON.parse($('#props').text()) - expect($('#index').text()).toBe('index page') + expect($('#gssp').text()).toBe('getServerSideProps page') expect(data.hello).toBe('world') const html2 = await renderViaHTTP(appPort, '/some-other-path', undefined, { headers: { - 'x-matched-path': '/', + 'x-matched-path': '/gssp', }, }) const $2 = cheerio.load(html2) const data2 = JSON.parse($2('#props').text()) - expect($2('#index').text()).toBe('index page') + expect($2('#gssp').text()).toBe('getServerSideProps page') expect(isNaN(data2.random)).toBe(false) expect(data2.random).not.toBe(data.random) }) @@ -508,7 +510,7 @@ describe('should set-up next', () => { }, { headers: { - 'x-matched-path': '/', + 'x-matched-path': '/gssp', }, } ) diff --git a/test/production/required-server-files.test.ts b/test/production/required-server-files.test.ts index 4f8eb6969c6cc..010f7dbbf8586 100644 --- a/test/production/required-server-files.test.ts +++ b/test/production/required-server-files.test.ts @@ -176,6 +176,29 @@ describe('should set-up next', () => { expect(res2.status).toBe(200) const { pageProps: props2 } = await res2.json() expect(props2.gspCalls).toBe(props.gspCalls) + + const res3 = await fetchViaHTTP(appPort, '/index', undefined, { + redirect: 'manual', + headers: { + 'x-matched-path': '/index', + }, + }) + expect(res3.status).toBe(200) + const $2 = cheerio.load(await res3.text()) + const props3 = JSON.parse($2('#props').text()) + expect(props3.gspCalls).toBeDefined() + + const res4 = await fetchViaHTTP( + appPort, + `/_next/data/${next.buildId}/index.json`, + undefined, + { + redirect: 'manual', + } + ) + expect(res4.status).toBe(200) + const { pageProps: props4 } = await res4.json() + expect(props4.gspCalls).toBe(props3.gspCalls) }) it('should set correct SWR headers with notFound gsp', async () => { @@ -218,6 +241,8 @@ describe('should set-up next', () => { const res2 = await fetchViaHTTP(appPort, '/gssp', undefined, { redirect: 'manual ', }) + await next.patchFile('standalone/data.txt', 'show') + expect(res2.status).toBe(404) expect(res2.headers.get('cache-control')).toBe( 's-maxage=1, stale-while-revalidate' @@ -225,18 +250,18 @@ describe('should set-up next', () => { }) it('should render SSR page correctly', async () => { - const html = await renderViaHTTP(appPort, '/') + const html = await renderViaHTTP(appPort, '/gssp') const $ = cheerio.load(html) const data = JSON.parse($('#props').text()) - expect($('#index').text()).toBe('index page') + expect($('#gssp').text()).toBe('getServerSideProps page') expect(data.hello).toBe('world') - const html2 = await renderViaHTTP(appPort, '/') + const html2 = await renderViaHTTP(appPort, '/gssp') const $2 = cheerio.load(html2) const data2 = JSON.parse($2('#props').text()) - expect($2('#index').text()).toBe('index page') + expect($2('#gssp').text()).toBe('getServerSideProps page') expect(isNaN(data2.random)).toBe(false) expect(data2.random).not.toBe(data.random) }) @@ -300,24 +325,24 @@ describe('should set-up next', () => { it('should render SSR page correctly with x-matched-path', async () => { const html = await renderViaHTTP(appPort, '/some-other-path', undefined, { headers: { - 'x-matched-path': '/', + 'x-matched-path': '/gssp', }, }) const $ = cheerio.load(html) const data = JSON.parse($('#props').text()) - expect($('#index').text()).toBe('index page') + expect($('#gssp').text()).toBe('getServerSideProps page') expect(data.hello).toBe('world') const html2 = await renderViaHTTP(appPort, '/some-other-path', undefined, { headers: { - 'x-matched-path': '/', + 'x-matched-path': '/gssp', }, }) const $2 = cheerio.load(html2) const data2 = JSON.parse($2('#props').text()) - expect($2('#index').text()).toBe('index page') + expect($2('#gssp').text()).toBe('getServerSideProps page') expect(isNaN(data2.random)).toBe(false) expect(data2.random).not.toBe(data.random) }) @@ -564,7 +589,7 @@ describe('should set-up next', () => { }, { headers: { - 'x-matched-path': '/', + 'x-matched-path': '/gssp', }, } ) diff --git a/test/production/required-server-files/pages/gssp.js b/test/production/required-server-files/pages/gssp.js index 653736f016f41..625cfb7c51386 100644 --- a/test/production/required-server-files/pages/gssp.js +++ b/test/production/required-server-files/pages/gssp.js @@ -1,5 +1,6 @@ import fs from 'fs' import path from 'path' +import { useRouter } from 'next/router' export async function getServerSideProps({ res }) { res.setHeader('cache-control', 's-maxage=1, stale-while-revalidate') @@ -19,6 +20,7 @@ export async function getServerSideProps({ res }) { props: { hello: 'world', data, + random: Math.random(), // make sure fetch if polyfilled example: await fetch('https://example.com').then((res) => res.text()), }, @@ -26,9 +28,12 @@ export async function getServerSideProps({ res }) { } export default function Page(props) { + const router = useRouter() + return ( <> -

getStaticProps page

+

getServerSideProps page

+

{JSON.stringify(router)}

{JSON.stringify(props)}

) diff --git a/test/production/required-server-files/pages/index.js b/test/production/required-server-files/pages/index.js index 74e172d935aba..8e07e51734615 100644 --- a/test/production/required-server-files/pages/index.js +++ b/test/production/required-server-files/pages/index.js @@ -8,12 +8,18 @@ if (localConfig.hello !== 'world') { throw new Error('oof import order is wrong, _app comes first') } -export const getServerSideProps = ({ req }) => { +let gspCalls = 0 + +export const getStaticProps = () => { + gspCalls += 1 + return { props: { hello: 'world', random: Math.random(), + gspCalls, }, + revalidate: 1, } }