Skip to content

Commit

Permalink
Merge branch 'canary' into fix/api-regex
Browse files Browse the repository at this point in the history
  • Loading branch information
Timer authored Sep 14, 2020
2 parents 36d257b + d3f4a4c commit 1f0413a
Show file tree
Hide file tree
Showing 9 changed files with 141 additions and 26 deletions.
1 change: 1 addition & 0 deletions docs/basic-features/data-fetching.md
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,7 @@ The `context` parameter is an object containing the following keys:
- `query`: The query string.
- `preview`: `preview` is `true` if the page is in the preview mode and `false` otherwise. See the [Preview Mode documentation](/docs/advanced-features/preview-mode.md).
- `previewData`: The preview data set by `setPreviewData`. See the [Preview Mode documentation](/docs/advanced-features/preview-mode.md).
- `resolvedUrl`: A normalized version of the request URL that strips the `_next/data` prefix for client transitions and includes original query values.

> **Note**: You can import modules in top-level scope for use in `getServerSideProps`.
> Imports used in `getServerSideProps` will not be bundled for the client-side.
Expand Down
8 changes: 4 additions & 4 deletions packages/next/build/webpack/loaders/next-serverless-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ const nextServerlessLoader: loader.Loader = function () {
!fromExport &&
(getStaticProps || getServerSideProps)
) {
const curQuery = {...parsedUrl.query}
const origQuery = parseUrl(req.url, true).query
${
pageIsDynamicRoute
Expand All @@ -507,17 +507,17 @@ const nextServerlessLoader: loader.Loader = function () {
delete parsedUrl.search
for (const param of Object.keys(defaultRouteRegex.groups)) {
delete curQuery[param]
delete origQuery[param]
}
}
`
: ``
}
parsedUrl.pathname = denormalizePagePath(parsedUrl.pathname)
renderOpts.normalizedAsPath = formatUrl({
renderOpts.resolvedUrl = formatUrl({
...parsedUrl,
query: curQuery
query: origQuery
})
}
Expand Down
12 changes: 5 additions & 7 deletions packages/next/next-server/server/next-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1111,13 +1111,11 @@ export default class Server {
...components,
...opts,
isDataReq,
normalizedAsPath: isDataReq
? formatUrl({
pathname: urlPathname,
// make sure to only add query values from original URL
query: parseUrl(req.url!, true).query,
})
: undefined,
resolvedUrl: formatUrl({
pathname: urlPathname,
// make sure to only add query values from original URL
query: parseUrl(req.url || '', true).query,
}),
}

renderResult = await renderToHTML(
Expand Down
6 changes: 4 additions & 2 deletions packages/next/next-server/server/render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ export type RenderOptsPartial = {
fontManifest?: FontManifest
optimizeImages: boolean
devOnlyCacheBusterQueryString?: string
normalizedAsPath?: string
resolvedUrl?: string
}

export type RenderOpts = LoadComponentsReturnType & RenderOptsPartial
Expand Down Expand Up @@ -476,6 +476,7 @@ export async function renderToHTML(
: {}),
}
req.url = pathname
renderOpts.resolvedUrl = pathname
renderOpts.nextExport = true
}

Expand All @@ -489,7 +490,7 @@ export async function renderToHTML(
await Loadable.preloadAll() // Make sure all dynamic imports are loaded

// url will always be set
const asPath: string = renderOpts.normalizedAsPath || (req.url as string)
const asPath: string = renderOpts.resolvedUrl || (req.url as string)
const router = new ServerRouter(
pathname,
query,
Expand Down Expand Up @@ -689,6 +690,7 @@ export async function renderToHTML(
req,
res,
query,
resolvedUrl: asPath,
...(pageIsDynamic ? { params: params as ParsedUrlQuery } : undefined),
...(previewData !== false
? { preview: true, previewData: previewData }
Expand Down
1 change: 1 addition & 0 deletions packages/next/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export type GetServerSidePropsContext<
query: ParsedUrlQuery
preview?: boolean
previewData?: any
resolvedUrl: string
}

export type GetServerSidePropsResult<P> = {
Expand Down
19 changes: 19 additions & 0 deletions test/integration/getserversideprops/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module.exports = {
// replace me
async rewrites() {
return [
{
source: '/blog-post-1',
destination: '/blog/post-1',
},
{
source: '/blog-post-2',
destination: '/blog/post-2?hello=world',
},
{
source: '/blog-:param',
destination: '/blog/post-3',
},
]
},
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react'
import Link from 'next/link'
import { useRouter } from 'next/router'

export async function getServerSideProps({ params }) {
export async function getServerSideProps({ params, resolvedUrl }) {
if (params.post === 'post-10') {
await new Promise((resolve) => {
setTimeout(() => resolve(), 1000)
Expand All @@ -16,13 +16,14 @@ export async function getServerSideProps({ params }) {
return {
props: {
params,
resolvedUrl,
post: params.post,
time: (await import('perf_hooks')).performance.now(),
},
}
}

export default ({ post, time, params, appProps }) => {
export default ({ post, time, params, appProps, resolvedUrl }) => {
return (
<>
<p>Post: {post}</p>
Expand All @@ -31,6 +32,7 @@ export default ({ post, time, params, appProps }) => {
<div id="query">{JSON.stringify(useRouter().query)}</div>
<div id="app-query">{JSON.stringify(appProps.query)}</div>
<div id="app-url">{appProps.url}</div>
<div id="resolved-url">{resolvedUrl}</div>
<Link href="/">
<a id="home">to home</a>
</Link>
Expand Down
14 changes: 12 additions & 2 deletions test/integration/getserversideprops/pages/something.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import React from 'react'
import Link from 'next/link'
import { useRouter } from 'next/router'

export async function getServerSideProps({ params, query }) {
export async function getServerSideProps({ params, query, resolvedUrl }) {
return {
props: {
resolvedUrl: resolvedUrl,
world: 'world',
query: query || {},
params: params || {},
Expand All @@ -14,7 +15,15 @@ export async function getServerSideProps({ params, query }) {
}
}

export default ({ world, time, params, random, query, appProps }) => {
export default ({
world,
time,
params,
random,
query,
appProps,
resolvedUrl,
}) => {
return (
<>
<p>hello: {world}</p>
Expand All @@ -25,6 +34,7 @@ export default ({ world, time, params, random, query, appProps }) => {
<div id="query">{JSON.stringify(useRouter().query)}</div>
<div id="app-query">{JSON.stringify(appProps.query)}</div>
<div id="app-url">{appProps.url}</div>
<div id="resolved-url">{resolvedUrl}</div>
<Link href="/">
<a id="home">to home</a>
</Link>
Expand Down
100 changes: 91 additions & 9 deletions test/integration/getserversideprops/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
check,
fetchViaHTTP,
findPort,
File,
getBrowserBodyText,
getRedboxHeader,
killApp,
Expand All @@ -22,7 +23,8 @@ import { join } from 'path'

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

let app
let appPort
let buildId
Expand Down Expand Up @@ -295,7 +297,9 @@ const runTests = (dev = false) => {
it('should have original req.url for /_next/data request dynamic page', async () => {
const curUrl = `/_next/data/${buildId}/blog/post-1.json`
const data = await renderViaHTTP(appPort, curUrl)
const { appProps } = JSON.parse(data)
const { appProps, pageProps } = JSON.parse(data)

expect(pageProps.resolvedUrl).toEqual('/blog/post-1')

expect(appProps).toEqual({
url: curUrl,
Expand All @@ -305,10 +309,27 @@ const runTests = (dev = false) => {
})
})

it('should have original req.url for /_next/data request dynamic page with query', async () => {
const curUrl = `/_next/data/${buildId}/blog/post-1.json`
const data = await renderViaHTTP(appPort, curUrl, { hello: 'world' })
const { appProps, pageProps } = JSON.parse(data)

expect(pageProps.resolvedUrl).toEqual('/blog/post-1?hello=world')

expect(appProps).toEqual({
url: curUrl + '?hello=world',
query: { post: 'post-1', hello: 'world' },
asPath: '/blog/post-1?hello=world',
pathname: '/blog/[post]',
})
})

it('should have original req.url for /_next/data request', async () => {
const curUrl = `/_next/data/${buildId}/something.json`
const data = await renderViaHTTP(appPort, curUrl)
const { appProps } = JSON.parse(data)
const { appProps, pageProps } = JSON.parse(data)

expect(pageProps.resolvedUrl).toEqual('/something')

expect(appProps).toEqual({
url: curUrl,
Expand All @@ -318,18 +339,78 @@ const runTests = (dev = false) => {
})
})

it('should have original req.url for /_next/data request with query', async () => {
const curUrl = `/_next/data/${buildId}/something.json`
const data = await renderViaHTTP(appPort, curUrl, { hello: 'world' })
const { appProps, pageProps } = JSON.parse(data)

expect(pageProps.resolvedUrl).toEqual('/something?hello=world')

expect(appProps).toEqual({
url: curUrl + '?hello=world',
query: { hello: 'world' },
asPath: '/something?hello=world',
pathname: '/something',
})
})

it('should have correct req.url and query for direct visit dynamic page', async () => {
const html = await renderViaHTTP(appPort, '/blog/post-1')
const $ = cheerio.load(html)
expect($('#app-url').text()).toContain('/blog/post-1')
expect(JSON.parse($('#app-query').text())).toEqual({ post: 'post-1' })
expect($('#resolved-url').text()).toBe('/blog/post-1')
})

it('should have correct req.url and query for direct visit dynamic page rewrite direct', async () => {
const html = await renderViaHTTP(appPort, '/blog-post-1')
const $ = cheerio.load(html)
expect($('#app-url').text()).toContain('/blog-post-1')
expect(JSON.parse($('#app-query').text())).toEqual({ post: 'post-1' })
expect($('#resolved-url').text()).toBe('/blog/post-1')
})

it('should have correct req.url and query for direct visit dynamic page rewrite direct with internal query', async () => {
const html = await renderViaHTTP(appPort, '/blog-post-2')
const $ = cheerio.load(html)
expect($('#app-url').text()).toContain('/blog-post-2')
expect(JSON.parse($('#app-query').text())).toEqual({
post: 'post-2',
hello: 'world',
})
expect($('#resolved-url').text()).toBe('/blog/post-2')
})

it('should have correct req.url and query for direct visit dynamic page rewrite param', async () => {
const html = await renderViaHTTP(appPort, '/blog-post-3')
const $ = cheerio.load(html)
expect($('#app-url').text()).toContain('/blog-post-3')
expect(JSON.parse($('#app-query').text())).toEqual({
post: 'post-3',
param: 'post-3',
})
expect($('#resolved-url').text()).toBe('/blog/post-3')
})

it('should have correct req.url and query for direct visit dynamic page with query', async () => {
const html = await renderViaHTTP(appPort, '/blog/post-1', {
hello: 'world',
})
const $ = cheerio.load(html)
expect($('#app-url').text()).toContain('/blog/post-1?hello=world')
expect(JSON.parse($('#app-query').text())).toEqual({
post: 'post-1',
hello: 'world',
})
expect($('#resolved-url').text()).toBe('/blog/post-1?hello=world')
})

it('should have correct req.url and query for direct visit', async () => {
const html = await renderViaHTTP(appPort, '/something')
const $ = cheerio.load(html)
expect($('#app-url').text()).toContain('/something')
expect(JSON.parse($('#app-query').text())).toEqual({})
expect($('#resolved-url').text()).toBe('/something')
})

it('should return data correctly', async () => {
Expand Down Expand Up @@ -587,10 +668,9 @@ describe('getServerSideProps', () => {

describe('serverless mode', () => {
beforeAll(async () => {
await fs.writeFile(
nextConfig,
`module.exports = { target: 'serverless' }`,
'utf8'
await nextConfig.replace(
'// replace me',
`target: 'experimental-serverless-trace', `
)
await nextBuild(appDir)
stderr = ''
Expand All @@ -602,14 +682,16 @@ describe('getServerSideProps', () => {
})
buildId = await fs.readFile(join(appDir, '.next/BUILD_ID'), 'utf8')
})
afterAll(() => killApp(app))
afterAll(async () => {
await killApp(app)
nextConfig.restore()
})

runTests()
})

describe('production mode', () => {
beforeAll(async () => {
await fs.remove(nextConfig)
await nextBuild(appDir, [], { stdout: true })

appPort = await findPort()
Expand Down

0 comments on commit 1f0413a

Please sign in to comment.