Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix aspath for getInitialProps #20572

Merged
merged 10 commits into from Jan 25, 2021
30 changes: 16 additions & 14 deletions packages/next/next-server/server/next-server.ts
Expand Up @@ -1347,11 +1347,12 @@ export default class Server {
typeof components.Component === 'object' &&
typeof (components.Component as any).renderReqToHTML === 'function'
const isSSG = !!components.getStaticProps
const isServerProps = !!components.getServerSideProps
const hasServerProps = !!components.getServerSideProps
const hasStaticPaths = !!components.getStaticPaths
const hasGetInitialProps = !!(components.Component as any).getInitialProps

// Toggle whether or not this is a Data request
const isDataReq = !!query._nextDataReq && (isSSG || isServerProps)
const isDataReq = !!query._nextDataReq && (isSSG || hasServerProps)
delete query._nextDataReq

// we need to ensure the status code if /404 is visited directly
Expand Down Expand Up @@ -1379,7 +1380,7 @@ export default class Server {
let previewData: string | false | object | undefined
let isPreviewMode = false

if (isServerProps || isSSG) {
if (hasServerProps || isSSG) {
previewData = tryGetPreviewData(req, res, this.renderOpts.previewProps)
isPreviewMode = previewData !== false
}
Expand Down Expand Up @@ -1603,17 +1604,18 @@ export default class Server {
locale,
locales,
defaultLocale,
// For getServerSideProps we need to ensure we use the original URL
// For getServerSideProps and getInitialProps we need to ensure we use the original URL
// and not the resolved URL to prevent a hydration mismatch on
// asPath
resolvedAsPath: isServerProps
? formatUrl({
// we use the original URL pathname less the _next/data prefix if
// present
pathname: `${urlPathname}${hadTrailingSlash ? '/' : ''}`,
query: origQuery,
})
: resolvedUrl,
resolvedAsPath:
hasServerProps || hasGetInitialProps
? formatUrl({
// we use the original URL pathname less the _next/data prefix if
// present
pathname: `${urlPathname}${hadTrailingSlash ? '/' : ''}`,
query: origQuery,
})
: resolvedUrl,
}

renderResult = await renderToHTML(
Expand Down Expand Up @@ -1720,7 +1722,7 @@ export default class Server {
let resHtml = html

const revalidateOptions =
!this.renderOpts.dev || (isServerProps && !isDataReq)
!this.renderOpts.dev || (hasServerProps && !isDataReq)
? {
private: isPreviewMode,
stateful: !isSSG,
Expand All @@ -1731,7 +1733,7 @@ export default class Server {
if (
!isResSent(res) &&
!isNotFound &&
(isSSG || isDataReq || isServerProps)
(isSSG || isDataReq || hasServerProps)
) {
if (isRedirect && !isDataReq) {
await handleRedirect(pageData)
Expand Down
11 changes: 11 additions & 0 deletions test/integration/getinitialprops/next.config.js
@@ -0,0 +1,11 @@
module.exports = {
// replace me
async rewrites() {
return [
{
source: '/blog/post/:pid',
destination: '/blog/:pid',
},
]
},
}
16 changes: 16 additions & 0 deletions test/integration/getinitialprops/pages/blog/[post].js
@@ -0,0 +1,16 @@
import React from 'react'
import { useRouter } from 'next/router'

const Post = () => {
const router = useRouter()

return (
<>
<div id="as-path">{router.asPath}</div>
</>
)
}

Post.getInitialProps = () => ({ hello: 'hi' })

export default Post
3 changes: 3 additions & 0 deletions test/integration/getinitialprops/pages/index.js
@@ -0,0 +1,3 @@
const page = () => 'hello from sub id'
page.getInitialProps = () => ({ hello: 'hi' })
export default page
1 change: 1 addition & 0 deletions test/integration/getinitialprops/pages/normal.js
@@ -0,0 +1 @@
export default () => <p id="normal-text">a normal page</p>
81 changes: 81 additions & 0 deletions test/integration/getinitialprops/test/index.test.js
@@ -0,0 +1,81 @@
import cheerio from 'cheerio'
import { join } from 'path'
import {
findPort,
launchApp,
killApp,
nextStart,
nextBuild,
renderViaHTTP,
File,
} from 'next-test-utils'

jest.setTimeout(1000 * 60 * 5)
let app
let appPort
const appDir = join(__dirname, '..')
const nextConfig = new File(join(appDir, 'next.config.js'))

const runTests = () => {
it('should have gip in __NEXT_DATA__', async () => {
const html = await renderViaHTTP(appPort, '/')
const $ = cheerio.load(html)
expect(JSON.parse($('#__NEXT_DATA__').text()).gip).toBe(true)
})

it('should not have gip in __NEXT_DATA__ for non-GIP page', async () => {
const html = await renderViaHTTP(appPort, '/normal')
const $ = cheerio.load(html)
expect('gip' in JSON.parse($('#__NEXT_DATA__').text())).toBe(false)
})

it('should have correct router.asPath for direct visit dynamic page', async () => {
const html = await renderViaHTTP(appPort, '/blog/1')
const $ = cheerio.load(html)
expect($('#as-path').text()).toBe('/blog/1')
})

it('should have correct router.asPath for direct visit dynamic page rewrite direct', async () => {
const html = await renderViaHTTP(appPort, '/blog/post/1')
const $ = cheerio.load(html)
expect($('#as-path').text()).toBe('/blog/post/1')
})
}

describe('getInitialProps', () => {
describe('dev mode', () => {
beforeAll(async () => {
appPort = await findPort()
app = await launchApp(appDir, appPort)
})
afterAll(() => killApp(app))

runTests()
})

describe('serverless mode', () => {
beforeAll(async () => {
await nextConfig.replace('// replace me', `target: 'serverless', `)
await nextBuild(appDir)
appPort = await findPort()
app = await nextStart(appDir, appPort)
})
afterAll(async () => {
await killApp(app)
nextConfig.restore()
})

runTests()
})

describe('production mode', () => {
beforeAll(async () => {
await nextBuild(appDir)
appPort = await findPort()
app = await nextStart(appDir, appPort)
})
afterAll(() => killApp(app))

runTests()
})
})