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

Implement isFallback Router Property #10539

Merged
merged 1 commit into from Feb 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/next/client/index.js
Expand Up @@ -206,6 +206,7 @@ export default async ({ webpackHMR: passedWebpackHMR } = {}) => {
Component,
wrapApp,
err: initialErr,
isFallback,
subscription: ({ Component, props, err }, App) => {
render({ App, Component, props, err })
},
Expand Down
9 changes: 8 additions & 1 deletion packages/next/client/router.ts
Expand Up @@ -29,7 +29,14 @@ const singletonRouter: SingletonRouterBase = {
}

// Create public properties and methods of the router in the singletonRouter
const urlPropertyFields = ['pathname', 'route', 'query', 'asPath', 'components']
const urlPropertyFields = [
'pathname',
'route',
'query',
'asPath',
'components',
'isFallback',
]
const routerEvents = [
'routeChangeStart',
'beforeHistoryChange',
Expand Down
8 changes: 8 additions & 0 deletions packages/next/next-server/lib/router/router.ts
Expand Up @@ -49,6 +49,7 @@ export type NextRouter = BaseRouter &
| 'prefetch'
| 'beforePopState'
| 'events'
| 'isFallback'
>

type RouteInfo = {
Expand Down Expand Up @@ -122,6 +123,7 @@ export default class Router implements BaseRouter {
events: MittEmitter
_wrapApp: (App: ComponentType) => any
isSsr: boolean
isFallback: boolean

static events: MittEmitter = mitt()

Expand All @@ -137,6 +139,7 @@ export default class Router implements BaseRouter {
Component,
err,
subscription,
isFallback,
}: {
subscription: Subscription
initialProps: any
Expand All @@ -145,6 +148,7 @@ export default class Router implements BaseRouter {
App: ComponentType
wrapApp: (App: ComponentType) => any
err?: Error
isFallback: boolean
}
) {
// represents the current component key
Expand Down Expand Up @@ -180,6 +184,8 @@ export default class Router implements BaseRouter {
// back from external site
this.isSsr = true

this.isFallback = isFallback

if (typeof window !== 'undefined') {
// in order for `e.state` to work on the `onpopstate` event
// we have to register the initial route upon initialization
Expand Down Expand Up @@ -580,6 +586,8 @@ export default class Router implements BaseRouter {
as: string,
data: RouteInfo
): void {
this.isFallback = false

this.route = route
this.pathname = pathname
this.query = query
Expand Down
14 changes: 12 additions & 2 deletions packages/next/next-server/server/render.tsx
Expand Up @@ -46,14 +46,22 @@ class ServerRouter implements NextRouter {
query: ParsedUrlQuery
asPath: string
events: any
isFallback: boolean
// TODO: Remove in the next major version, as this would mean the user is adding event listeners in server-side `render` method
static events: MittEmitter = mitt()

constructor(pathname: string, query: ParsedUrlQuery, as: string) {
constructor(
pathname: string,
query: ParsedUrlQuery,
as: string,
{ isFallback }: { isFallback: boolean }
) {
this.route = pathname.replace(/\/$/, '') || '/'
this.pathname = pathname
this.query = query
this.asPath = as

this.isFallback = isFallback
}
push(): any {
noRouter()
Expand Down Expand Up @@ -394,7 +402,9 @@ export async function renderToHTML(

// @ts-ignore url will always be set
const asPath: string = req.url
const router = new ServerRouter(pathname, query, asPath)
const router = new ServerRouter(pathname, query, asPath, {
isFallback: isFallback,
})
const ctx = {
err,
req: isAutoExport ? undefined : req,
Expand Down
14 changes: 13 additions & 1 deletion test/integration/prerender/pages/catchall/[...slug].js
@@ -1,4 +1,10 @@
import { useRouter } from 'next/router'

export async function unstable_getStaticProps({ params: { slug } }) {
if (slug[0] === 'delayby3s') {
await new Promise(resolve => setTimeout(resolve, 3000))
}

return {
props: {
slug,
Expand All @@ -18,4 +24,10 @@ export async function unstable_getStaticPaths() {
}
}

export default ({ slug }) => <p id="catchall">Hi {slug?.join('/')}</p>
export default ({ slug }) => {
const { isFallback } = useRouter()
if (isFallback) {
return <p id="catchall">fallback</p>
}
return <p id="catchall">Hi {slug.join('/')}</p>
}
17 changes: 14 additions & 3 deletions test/integration/prerender/test/index.test.js
Expand Up @@ -386,9 +386,20 @@ const runTests = (dev = false) => {
}
// Production will render fallback for a "lazy" route
else {
const browser = await webdriver(appPort, '/catchall/notreturnedinpaths')
const text = await browser.elementByCss('#catchall').text()
expect(text).toMatch(/Hi.*?notreturnedinpaths/)
const html = await renderViaHTTP(appPort, '/catchall/notreturnedinpaths')
const $ = cheerio.load(html)
expect($('#catchall').text()).toBe('fallback')

// hydration
const browser = await webdriver(appPort, '/catchall/delayby3s')

const text1 = await browser.elementByCss('#catchall').text()
expect(text1).toBe('fallback')

await new Promise(resolve => setTimeout(resolve, 4000))

const text2 = await browser.elementByCss('#catchall').text()
expect(text2).toMatch(/Hi.*?delayby3s/)
}
})

Expand Down