Skip to content

Commit

Permalink
Correct /_next/data link for GS(S)P with basePath (#14376)
Browse files Browse the repository at this point in the history
This corrects the `/_next/data` path generated when using `basePath` with `getStaticProps` in a `pages/index.js` file which was previously stripping the `basePath` without checking if `/index` needed to be appended after stripping. This also adds additional checks to the `basePath` test suite to prevent regressing   

x-ref: #9872 (comment)
  • Loading branch information
ijjk authored Jun 19, 2020
1 parent 4e5e3b9 commit 546c651
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 17 deletions.
33 changes: 16 additions & 17 deletions packages/next/next-server/lib/router/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ function toRoute(path: string): string {
return path.replace(/\/$/, '') || '/'
}

const prepareRoute = (path: string) =>
toRoute(!path || path === '/' ? '/index' : path)
function prepareRoute(path: string) {
path = delBasePath(path || '')
return toRoute(!path || path === '/' ? '/index' : path)
}

type Url = UrlObject | string

Expand Down Expand Up @@ -106,7 +108,7 @@ function fetchNextData(
formatWithValidation({
pathname: addBasePath(
// @ts-ignore __NEXT_DATA__
`/_next/data/${__NEXT_DATA__.buildId}${delBasePath(pathname)}.json`
`/_next/data/${__NEXT_DATA__.buildId}${pathname}.json`
),
query,
}),
Expand Down Expand Up @@ -446,13 +448,12 @@ export default class Router implements BaseRouter {

const route = toRoute(pathname)
const { shallow = false } = options
const cleanedAs = delBasePath(as)

if (isDynamicRoute(route)) {
const { pathname: asPathname } = parse(as)
const { pathname: asPathname } = parse(cleanedAs)
const routeRegex = getRouteRegex(route)
const routeMatch = getRouteMatcher(routeRegex)(
delBasePath(asPathname || '')
)
const routeMatch = getRouteMatcher(routeRegex)(asPathname)
if (!routeMatch) {
const missingParams = Object.keys(routeRegex.groups).filter(
(param) => !query[param]
Expand Down Expand Up @@ -502,17 +503,15 @@ export default class Router implements BaseRouter {
!(routeInfo.Component as any).getInitialProps
}

this.set(route, pathname!, query, delBasePath(as), routeInfo).then(
() => {
if (error) {
Router.events.emit('routeChangeError', error, as)
throw error
}

Router.events.emit('routeChangeComplete', as)
return resolve(true)
this.set(route, pathname!, query, cleanedAs, routeInfo).then(() => {
if (error) {
Router.events.emit('routeChangeError', error, as)
throw error
}
)

Router.events.emit('routeChangeComplete', as)
return resolve(true)
})
},
reject
)
Expand Down
6 changes: 6 additions & 0 deletions test/integration/basepath/pages/hello.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ export default () => (
<h1>catchall page</h1>
</a>
</Link>
<br />
<Link href="/">
<a id="index-gsp">
<h1>index getStaticProps</h1>
</a>
</Link>
<div id="base-path">{useRouter().basePath}</div>
<div id="pathname">{useRouter().pathname}</div>
</>
Expand Down
20 changes: 20 additions & 0 deletions test/integration/basepath/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { useRouter } from 'next/router'

export const getStaticProps = () => {
return {
props: {
hello: 'hello',
},
}
}

export default function Index({ hello }) {
const { query, pathname } = useRouter()
return (
<>
<p id="prop">{hello} world</p>
<p id="query">{JSON.stringify(query)}</p>
<p id="pathname">{pathname}</p>
</>
)
}
35 changes: 35 additions & 0 deletions test/integration/basepath/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,41 @@ const runTests = (context, dev = false) => {
})
}

it('should navigate to index page with getStaticProps', async () => {
const browser = await webdriver(context.appPort, '/docs/hello')
await browser.eval('window.beforeNavigate = "hi"')

await browser.elementByCss('#index-gsp').click()
await browser.waitForElementByCss('#prop')

expect(await browser.eval('window.beforeNavigate')).toBe('hi')

expect(await browser.elementByCss('#prop').text()).toBe('hello world')

expect(JSON.parse(await browser.elementByCss('#query').text())).toEqual({})

expect(await browser.elementByCss('#pathname').text()).toBe('/')

if (!dev) {
const prefetches = await browser.elementsByCss('link[rel="prefetch"]')
let found = false

for (const prefetch of prefetches) {
const fullHref = await prefetch.getAttribute('href')
const href = url.parse(fullHref).pathname

if (
href.startsWith('/docs/_next/data') &&
href.endsWith('index.json')
) {
found = true
}
}

expect(found).toBe(true)
}
})

it('should work with nested folder with same name as basePath', async () => {
const html = await renderViaHTTP(context.appPort, '/docs/docs/another')
expect(html).toContain('hello from another')
Expand Down

0 comments on commit 546c651

Please sign in to comment.