2017-12-26 20:46:46 +00:00
|
|
|
import PropTypes from 'prop-types'
|
|
|
|
import Link from 'next/link'
|
|
|
|
import Router from 'next/router'
|
|
|
|
import { execOnce, warn } from 'next/dist/lib/utils'
|
|
|
|
import exact from 'prop-types-exact'
|
|
|
|
import { format, resolve, parse } from 'url'
|
|
|
|
|
2018-12-17 16:34:32 +00:00
|
|
|
export const prefetch = async href => {
|
2018-01-26 16:07:17 +00:00
|
|
|
// if we're running server side do nothing
|
|
|
|
if (typeof window === 'undefined') return
|
|
|
|
|
2018-12-17 16:34:32 +00:00
|
|
|
const url = typeof href !== 'string' ? format(href) : href
|
2018-01-26 16:07:17 +00:00
|
|
|
|
2019-01-20 12:41:49 +00:00
|
|
|
const parsedHref = resolve(window.location.pathname, url)
|
2018-01-26 16:07:17 +00:00
|
|
|
|
2019-01-20 12:41:49 +00:00
|
|
|
const { query, pathname } = typeof href !== 'string' ? href : parse(url, true)
|
2018-01-26 16:07:17 +00:00
|
|
|
|
|
|
|
const Component = await Router.prefetch(parsedHref)
|
|
|
|
|
|
|
|
// if Component exists and has getInitialProps
|
|
|
|
// fetch the component props (the component should save it in cache)
|
|
|
|
if (Component && Component.getInitialProps) {
|
2019-01-20 12:41:49 +00:00
|
|
|
const ctx = { pathname, query, isVirtualCall: true }
|
2018-01-26 16:07:17 +00:00
|
|
|
await Component.getInitialProps(ctx)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-26 20:46:46 +00:00
|
|
|
// extend default next/link to customize the prefetch behaviour
|
|
|
|
export default class LinkWithData extends Link {
|
|
|
|
// re defined Link propTypes to add `withData`
|
|
|
|
static propTypes = exact({
|
|
|
|
href: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired,
|
|
|
|
as: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
|
|
|
prefetch: PropTypes.bool,
|
|
|
|
replace: PropTypes.bool,
|
|
|
|
shallow: PropTypes.bool,
|
|
|
|
passHref: PropTypes.bool,
|
|
|
|
scroll: PropTypes.bool,
|
|
|
|
children: PropTypes.oneOfType([
|
|
|
|
PropTypes.element,
|
|
|
|
(props, propName) => {
|
|
|
|
const value = props[propName]
|
|
|
|
|
|
|
|
if (typeof value === 'string') {
|
2018-12-17 16:34:32 +00:00
|
|
|
execOnce(warn)(
|
|
|
|
`Warning: You're using a string directly inside <Link>. This usage has been deprecated. Please add an <a> tag as child of <Link>`
|
|
|
|
)
|
2017-12-26 20:46:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
]).isRequired,
|
|
|
|
withData: PropTypes.bool // our custom prop
|
2018-12-17 16:34:32 +00:00
|
|
|
})
|
2017-12-26 20:46:46 +00:00
|
|
|
|
|
|
|
// our custom prefetch method
|
|
|
|
async prefetch () {
|
2018-01-26 16:07:17 +00:00
|
|
|
// if the prefetch prop is not defined do nothing
|
2017-12-26 20:46:46 +00:00
|
|
|
if (!this.props.prefetch) return
|
|
|
|
|
2018-01-26 16:07:17 +00:00
|
|
|
// if withData prop is defined
|
|
|
|
// prefetch with data
|
|
|
|
// otherwise just prefetch the page
|
|
|
|
if (this.props.withData) {
|
|
|
|
prefetch(this.props.href)
|
|
|
|
} else {
|
|
|
|
super.prefetch()
|
2017-12-26 20:46:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|