mirror of https://github.com/vuejs/vitepress
parent
7a90c4f870
commit
da4852a61b
@ -1,9 +1,14 @@
|
|||||||
import { h } from 'vue'
|
import { h } from 'vue'
|
||||||
import { useRoute } from '../router'
|
import { useRoute } from '../router'
|
||||||
|
import { usePrefetch } from '../composables/preFetch'
|
||||||
|
|
||||||
export const Content = {
|
export const Content = {
|
||||||
setup() {
|
setup() {
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
if (!__DEV__) {
|
||||||
|
// in prod mode, enable intersectionObserver based pre-fetch.
|
||||||
|
usePrefetch()
|
||||||
|
}
|
||||||
return () => (route.contentComponent ? h(route.contentComponent) : null)
|
return () => (route.contentComponent ? h(route.contentComponent) : null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,89 @@
|
|||||||
|
// Customized pre-fetch for page chunks based on
|
||||||
|
// https://github.com/GoogleChromeLabs/quicklink
|
||||||
|
|
||||||
|
import { onMounted, onUnmounted, onUpdated } from 'vue'
|
||||||
|
import { inBrowser, pathToFile } from '../utils'
|
||||||
|
|
||||||
|
const hasFetched = new Set<string>()
|
||||||
|
const createLink = () => document.createElement('link')
|
||||||
|
|
||||||
|
const viaDOM = (url: string) => {
|
||||||
|
const link = createLink()
|
||||||
|
link.rel = `prefetch`
|
||||||
|
link.href = url
|
||||||
|
document.head.appendChild(link)
|
||||||
|
}
|
||||||
|
|
||||||
|
const viaXHR = (url: string) => {
|
||||||
|
const req = new XMLHttpRequest()
|
||||||
|
req.open('GET', url, (req.withCredentials = true))
|
||||||
|
req.send()
|
||||||
|
}
|
||||||
|
|
||||||
|
let link
|
||||||
|
const doFetch: (url: string) => void =
|
||||||
|
inBrowser &&
|
||||||
|
(link = createLink()) &&
|
||||||
|
link.relList &&
|
||||||
|
link.relList.supports &&
|
||||||
|
link.relList.supports('prefetch')
|
||||||
|
? viaDOM
|
||||||
|
: viaXHR
|
||||||
|
|
||||||
|
export function usePrefetch() {
|
||||||
|
if (!inBrowser) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!window.IntersectionObserver) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let conn
|
||||||
|
if (
|
||||||
|
(conn = (navigator as any).connection) &&
|
||||||
|
(conn.saveData || /2g/.test(conn.effectiveType))
|
||||||
|
) {
|
||||||
|
// Don't prefetch if using 2G or if Save-Data is enabled.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const rIC = (window as any).requestIdleCallback || setTimeout
|
||||||
|
let observer: IntersectionObserver | null = null
|
||||||
|
|
||||||
|
const observeLinks = () => {
|
||||||
|
if (observer) {
|
||||||
|
observer.disconnect()
|
||||||
|
}
|
||||||
|
|
||||||
|
observer = new IntersectionObserver((entries) => {
|
||||||
|
entries.forEach((entry) => {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
const link = entry.target as HTMLAnchorElement
|
||||||
|
observer!.unobserve(link)
|
||||||
|
const { pathname } = link
|
||||||
|
if (!hasFetched.has(pathname)) {
|
||||||
|
hasFetched.add(pathname)
|
||||||
|
const pageChunkPath = pathToFile(pathname)
|
||||||
|
doFetch(pageChunkPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
rIC(() => {
|
||||||
|
document.querySelectorAll('.vitepress-content a').forEach((link) => {
|
||||||
|
if ((link as HTMLAnchorElement).hostname === location.hostname) {
|
||||||
|
observer!.observe(link)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(observeLinks)
|
||||||
|
onUpdated(observeLinks)
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
observer && observer.disconnect()
|
||||||
|
})
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
export const inBrowser = typeof window !== 'undefined'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a url path to the corresponding js chunk filename.
|
||||||
|
*/
|
||||||
|
export function pathToFile(path: string): string {
|
||||||
|
let pagePath = path.replace(/\.html$/, '')
|
||||||
|
if (pagePath.endsWith('/')) {
|
||||||
|
pagePath += 'index'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__DEV__) {
|
||||||
|
// awlays force re-fetch content in dev
|
||||||
|
pagePath += `.md?t=${Date.now()}`
|
||||||
|
} else {
|
||||||
|
// in production, each .md file is built into a .md.js file following
|
||||||
|
// the path conversion scheme.
|
||||||
|
// /foo/bar.html -> ./foo_bar.md
|
||||||
|
if (inBrowser) {
|
||||||
|
pagePath = pagePath.slice(__BASE__.length).replace(/\//g, '_') + '.md'
|
||||||
|
// client production build needs to account for page hash, which is
|
||||||
|
// injected directly in the page's html
|
||||||
|
const pageHash = __VP_HASH_MAP__[pagePath]
|
||||||
|
pagePath = `${__BASE__}_assets/${pagePath}.${pageHash}.js`
|
||||||
|
} else {
|
||||||
|
// ssr build uses much simpler name mapping
|
||||||
|
pagePath = `./${pagePath.slice(1).replace(/\//g, '_')}.md.js`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pagePath
|
||||||
|
}
|
Loading…
Reference in new issue