Use Cached SSG Data on History Navigation (#9887)

* Use Cached SSG Data on History Navigation

* Add data caching test

* Create a static data cache

* Eliminate an if / return

* Do not cache in dev mode

* bump

* bump

* bump

* bump

Co-authored-by: JJ Kasper <jj@jjsweb.site>
This commit is contained in:
Joe Haddad 2019-12-30 17:57:06 -05:00 committed by GitHub
parent 3ece98b31b
commit 0957ed6f32
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 72 additions and 28 deletions

View file

@ -71,6 +71,8 @@ export default class Router implements BaseRouter {
* Map of all components loaded in `Router`
*/
components: { [pathname: string]: RouteInfo }
// Static Data Cache
sdc: { [asPath: string]: object } = {}
sub: Subscription
clc: ComponentLoadCancel
pageLoader: any
@ -656,23 +658,31 @@ export default class Router implements BaseRouter {
})
}
_getStaticData = (asPath: string): Promise<any> => {
_getStaticData = (asPath: string, _cachedData?: object): Promise<object> => {
let pathname = parse(asPath).pathname
pathname = !pathname || pathname === '/' ? '/index' : pathname
return fetch(
// @ts-ignore __NEXT_DATA__
`/_next/data/${__NEXT_DATA__.buildId}${pathname}.json`
)
.then(res => {
if (!res.ok) {
throw new Error(`Failed to load static props`)
}
return res.json()
})
.catch((err: Error) => {
;(err as any).code = 'PAGE_LOAD_ERROR'
throw err
})
return process.env.NODE_ENV === 'production' &&
(_cachedData = this.sdc[pathname])
? Promise.resolve(_cachedData)
: fetch(
// @ts-ignore __NEXT_DATA__
`/_next/data/${__NEXT_DATA__.buildId}${pathname}.json`
)
.then(res => {
if (!res.ok) {
throw new Error(`Failed to load static props`)
}
return res.json()
})
.then(data => {
this.sdc[pathname!] = data
return data
})
.catch((err: Error) => {
;(err as any).code = 'PAGE_LOAD_ERROR'
throw err
})
}
getInitialProps(

View file

@ -26,7 +26,7 @@ export async function unstable_getStaticProps() {
export default ({ world, time }) => (
<>
<p>hello {world}</p>
<span>time: {time}</span>
<span id="anotherTime">time: {time}</span>
<Link href="/">
<a id="home">to home</a>
</Link>

View file

@ -110,7 +110,7 @@ const expectedManifestRoutes = () => ({
},
})
const navigateTest = () => {
const navigateTest = (dev = false) => {
it('should navigate between pages successfully', async () => {
const toBuild = [
'/',
@ -133,18 +133,52 @@ const navigateTest = () => {
await waitFor(2500)
// go to /another
await browser.elementByCss('#another').click()
await browser.waitForElementByCss('#home')
text = await browser.elementByCss('p').text()
expect(text).toMatch(/hello.*?world/)
async function goFromHomeToAnother() {
await browser.elementByCss('#another').click()
await browser.waitForElementByCss('#home')
text = await browser.elementByCss('p').text()
expect(text).toMatch(/hello.*?world/)
}
await goFromHomeToAnother()
// go to /
await browser.eval('window.didTransition = 1')
await browser.elementByCss('#home').click()
await browser.waitForElementByCss('#another')
text = await browser.elementByCss('p').text()
expect(text).toMatch(/hello.*?world/)
expect(await browser.eval('window.didTransition')).toBe(1)
async function goFromAnotherToHome() {
await browser.eval('window.didTransition = 1')
await browser.elementByCss('#home').click()
await browser.waitForElementByCss('#another')
text = await browser.elementByCss('p').text()
expect(text).toMatch(/hello.*?world/)
expect(await browser.eval('window.didTransition')).toBe(1)
}
await goFromAnotherToHome()
// Client-side SSG data caching test
// eslint-disable-next-line no-lone-blocks
{
// Let revalidation period lapse
await waitFor(2000)
// Trigger revalidation (visit page)
await goFromHomeToAnother()
const snapTime = await browser.elementByCss('#anotherTime').text()
// Wait for revalidation to finish
await waitFor(2000)
// Re-visit page
await goFromAnotherToHome()
await goFromHomeToAnother()
const nextTime = await browser.elementByCss('#anotherTime').text()
if (dev) {
expect(snapTime).not.toMatch(nextTime)
} else {
expect(snapTime).toMatch(nextTime)
}
// Reset to Home for next test
await goFromAnotherToHome()
}
// go to /something
await browser.elementByCss('#something').click()
@ -180,7 +214,7 @@ const navigateTest = () => {
}
const runTests = (dev = false) => {
navigateTest()
navigateTest(dev)
it('should SSR normal page correctly', async () => {
const html = await renderViaHTTP(appPort, '/')