Skip to content

Commit

Permalink
Ensure basePath behavior with GS(S)P redirect
Browse files Browse the repository at this point in the history
  • Loading branch information
ijjk committed Nov 9, 2020
1 parent 5aa7606 commit 797a510
Show file tree
Hide file tree
Showing 12 changed files with 766 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -824,10 +824,15 @@ const nextServerlessLoader: loader.Loader = function () {
} else if (renderOpts.isRedirect && !_nextData) {
const redirect = {
destination: renderOpts.pageData.pageProps.__N_REDIRECT,
statusCode: renderOpts.pageData.pageProps.__N_REDIRECT_STATUS
statusCode: renderOpts.pageData.pageProps.__N_REDIRECT_STATUS,
basePath: renderOpts.pageData.pageProps.__N_REDIRECT_BASE_PATH
}
const statusCode = getRedirectStatus(redirect)
if ("${basePath}" && redirect.basePath !== false) {
redirect.destination = \`${basePath}\${redirect.destination}\`
}
if (statusCode === PERMANENT_REDIRECT_STATUS) {
res.setHeader('Refresh', \`0;url=\${redirect.destination}\`)
}
Expand Down
9 changes: 7 additions & 2 deletions packages/next/next-server/lib/router/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -815,10 +815,15 @@ export default class Router implements BaseRouter {
// it's not
if (destination.startsWith('/')) {
const parsedHref = parseRelativeUrl(destination)
this._resolveHref(parsedHref, pages)
this._resolveHref(parsedHref, pages, false)

if (pages.includes(parsedHref.pathname)) {
return this.change(method, destination, destination, options)
const { url: newUrl, as: newAs } = prepareUrlAs(
this,
destination,
destination
)
return this.change(method, newUrl, newAs, options)
}
}

Expand Down
6 changes: 6 additions & 0 deletions packages/next/next-server/server/next-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1259,8 +1259,14 @@ export default class Server {
const redirect = {
destination: pageData.pageProps.__N_REDIRECT,
statusCode: pageData.pageProps.__N_REDIRECT_STATUS,
basePath: pageData.pageProps.__N_REDIRECT_BASE_PATH,
}
const statusCode = getRedirectStatus(redirect)
const { basePath } = this.nextConfig

if (basePath && redirect.basePath !== false) {
redirect.destination = `${basePath}${redirect.destination}`
}

if (statusCode === PERMANENT_REDIRECT_STATUS) {
res.setHeader('Refresh', `0;url=${redirect.destination}`)
Expand Down
23 changes: 16 additions & 7 deletions packages/next/next-server/server/render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import optimizeAmp from './optimize-amp'
import {
allowedStatusCodes,
getRedirectStatus,
Redirect,
} from '../../lib/load-custom-routes'

function noRouter() {
Expand Down Expand Up @@ -306,18 +307,12 @@ const invalidKeysMsg = (methodName: string, invalidKeys: string[]) => {
)
}

type Redirect = {
permanent: boolean
destination: string
statusCode?: number
}

function checkRedirectValues(
redirect: Redirect,
req: IncomingMessage,
method: 'getStaticProps' | 'getServerSideProps'
) {
const { destination, permanent, statusCode } = redirect
const { destination, permanent, statusCode, basePath } = redirect
let errors: string[] = []

const hasStatusCode = typeof statusCode !== 'undefined'
Expand All @@ -342,6 +337,14 @@ function checkRedirectValues(
)
}

const basePathType = typeof basePath

if (basePathType !== 'undefined' && basePathType !== 'boolean') {
errors.push(
`\`basePath\` should be undefined or a false, received ${basePathType}`
)
}

if (errors.length > 0) {
throw new Error(
`Invalid redirect object returned from ${method} for ${req.url}\n` +
Expand Down Expand Up @@ -685,6 +688,9 @@ export async function renderToHTML(
__N_REDIRECT: data.redirect.destination,
__N_REDIRECT_STATUS: getRedirectStatus(data.redirect),
}
if (typeof data.redirect.basePath !== 'undefined') {
;(data as any).props.__N_REDIRECT_BASE_PATH = data.redirect.basePath
}
;(renderOpts as any).isRedirect = true
}

Expand Down Expand Up @@ -811,6 +817,9 @@ export async function renderToHTML(
__N_REDIRECT: data.redirect.destination,
__N_REDIRECT_STATUS: getRedirectStatus(data.redirect),
}
if (typeof data.redirect.basePath !== 'undefined') {
;(data as any).props.__N_REDIRECT_BASE_PATH = data.redirect.basePath
}
;(renderOpts as any).isRedirect = true
}

Expand Down
6 changes: 1 addition & 5 deletions packages/next/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import React from 'react'
import { ParsedUrlQuery } from 'querystring'
import { IncomingMessage, ServerResponse } from 'http'
import { Redirect } from '../lib/load-custom-routes'

import {
NextPageContext,
Expand Down Expand Up @@ -72,11 +73,6 @@ export {
NextApiHandler,
}

type Redirect = {
permanent: boolean
destination: string
}

export type GetStaticPropsContext<Q extends ParsedUrlQuery = ParsedUrlQuery> = {
params?: Q
preview?: boolean
Expand Down
3 changes: 3 additions & 0 deletions test/integration/gssp-redirect-base-path/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
basePath: '/docs',
}
3 changes: 3 additions & 0 deletions test/integration/gssp-redirect-base-path/pages/404.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function NotFound() {
return <p>oops not found</p>
}
3 changes: 3 additions & 0 deletions test/integration/gssp-redirect-base-path/pages/another.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Another() {
return <p id="another">another Page</p>
}
76 changes: 76 additions & 0 deletions test/integration/gssp-redirect-base-path/pages/gsp-blog/[post].js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { useRouter } from 'next/router'

export default function Post(props) {
const router = useRouter()

if (typeof window === 'undefined') {
if (router.query.post?.startsWith('redir')) {
console.log(router)
throw new Error('render should not occur for redirect')
}
}

if (typeof window !== 'undefined' && !window.initialHref) {
window.initialHref = window.location.href
}

if (router.isFallback) return <p>Loading...</p>

return (
<>
<p id="gsp">getStaticProps</p>
<p id="props">{JSON.stringify(props)}</p>
</>
)
}

export const getStaticProps = ({ params }) => {
if (params.post.startsWith('redir')) {
let destination = '/404'

if (params.post.includes('dest-')) {
destination = params.post.split('dest-').pop().replace(/_/g, '/')
}

let permanent = undefined
let statusCode = undefined

if (params.post.includes('statusCode-')) {
permanent = parseInt(
params.post.split('statusCode-').pop().split('-').shift(),
10
)
}

if (params.post.includes('permanent')) {
permanent = true
} else if (!statusCode) {
permanent = false
}

const redirect = {
destination,
permanent,
statusCode,
}

if (params.post.includes('no-basepath-')) {
redirect.basePath = false
}

return { redirect }
}

return {
props: {
params,
},
}
}

export const getStaticPaths = () => {
return {
paths: ['first', 'second'].map((post) => ({ params: { post } })),
fallback: true,
}
}
63 changes: 63 additions & 0 deletions test/integration/gssp-redirect-base-path/pages/gssp-blog/[post].js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { useRouter } from 'next/router'

export default function Post(props) {
const router = useRouter()

if (typeof window === 'undefined') {
if (router.query.post?.startsWith('redir')) {
console.log(router)
throw new Error('render should not occur for redirect')
}
}

return (
<>
<p id="gssp">getServerSideProps</p>
<p id="props">{JSON.stringify(props)}</p>
</>
)
}

export const getServerSideProps = ({ params }) => {
if (params.post.startsWith('redir')) {
let destination = '/404'

if (params.post.includes('dest-')) {
destination = params.post.split('dest-').pop().replace(/_/g, '/')
}

let permanent = undefined
let statusCode = undefined

if (params.post.includes('statusCode-')) {
statusCode = parseInt(
params.post.split('statusCode-').pop().split('-').shift(),
10
)
}

if (params.post.includes('permanent')) {
permanent = true
} else if (!statusCode) {
permanent = false
}

const redirect = {
destination,
permanent,
statusCode,
}

if (params.post.includes('no-basepath-')) {
redirect.basePath = false
}

return { redirect }
}

return {
props: {
params,
},
}
}
7 changes: 7 additions & 0 deletions test/integration/gssp-redirect-base-path/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function Index() {
if (typeof window !== 'undefined' && !window.initialHref) {
window.initialHref = window.location.href
}

return <p id="index">Index Page</p>
}
Loading

0 comments on commit 797a510

Please sign in to comment.