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

Bug fix: dynamic page should not be interpreted as predefined page #33808

Merged
22 changes: 13 additions & 9 deletions packages/next/server/base-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -881,7 +881,7 @@ export default abstract class Server {
): Promise<boolean> {
let page = pathname
let params: Params | false = false
let pageFound = await this.hasPage(page)
let pageFound = !isDynamicRoute(page) && (await this.hasPage(page))

if (!pageFound && this.dynamicRoutes) {
for (const dynamicRoute of this.dynamicRoutes) {
Expand Down Expand Up @@ -1536,15 +1536,19 @@ export default abstract class Server {
delete query._nextBubbleNoFallback

try {
const result = await this.findPageComponents(pathname, query)
if (result) {
try {
return await this.renderToResponseWithComponents(ctx, result)
} catch (err) {
const isNoFallbackError = err instanceof NoFallbackError
// Ensure a request to the URL /accounts/[id] will be treated as a dynamic
// route correctly and not loaded immediately without parsing params.
if (!isDynamicRoute(pathname)) {
const result = await this.findPageComponents(pathname, query)
if (result) {
try {
return await this.renderToResponseWithComponents(ctx, result)
} catch (err) {
const isNoFallbackError = err instanceof NoFallbackError

if (!isNoFallbackError || (isNoFallbackError && bubbleNoFallback)) {
throw err
if (!isNoFallbackError || (isNoFallbackError && bubbleNoFallback)) {
throw err
}
}
}
}
Expand Down
63 changes: 63 additions & 0 deletions test/e2e/dynamic-route-interpolation/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { createNext } from 'e2e-utils'
import { NextInstance } from 'test/lib/next-modes/base'
import { renderViaHTTP } from 'next-test-utils'
import cheerio from 'cheerio'

describe('Dynamic Route Interpolation', () => {
let next: NextInstance

beforeAll(async () => {
next = await createNext({
files: {
'pages/blog/[slug].js': `
export function getServerSideProps({ params }) {
return { props: { slug: params.slug } }
}

export default function Page(props) {
return <p id="slug">{props.slug}</p>
}

`,

'pages/api/dynamic/[slug].js': `
export default function Page(req, res) {
const { slug } = req.query
res.end('slug: ' + slug)
}

`,
},
dependencies: {},
})
})
afterAll(() => next.destroy())

it('should work', async () => {
const html = await renderViaHTTP(next.url, '/blog/a')
const $ = cheerio.load(html)
expect($('#slug').text()).toBe('a')
})

it('should work with parameter itself', async () => {
const html = await renderViaHTTP(next.url, '/blog/[slug]')
const $ = cheerio.load(html)
expect($('#slug').text()).toBe('[slug]')
})

it('should work with brackets', async () => {
const html = await renderViaHTTP(next.url, '/blog/[abc]')
const $ = cheerio.load(html)
expect($('#slug').text()).toBe('[abc]')
})

it('should work with parameter itself in API routes', async () => {
const text = await renderViaHTTP(next.url, '/api/dynamic/[slug]')
expect(text).toBe('slug: [slug]')
})

it('should work with brackets in API routes', async () => {
const text = await renderViaHTTP(next.url, '/api/dynamic/[abc]')
expect(text).toBe('slug: [abc]')
})
})