import { useRoute } from '../router' ; import { onMounted , onUnmounted , watch } from 'vue' ; import { inBrowser , pathToFile } from '../utils' ; const hasFetched = new Set < string > ( ) ; const createLink = ( ) => document . createElement ( 'link' ) ; const viaDOM = ( url ) => { const link = createLink ( ) ; link . rel = `prefetch` ; link . href = url ; document . head . appendChild ( link ) ; } ; const viaXHR = ( url ) => { const req = new XMLHttpRequest ( ) ; req . open ( 'GET' , url , ( req . withCredentials = true ) ) ; req . send ( ) ; } ; let link ; const doFetch = 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 ) ) ) { return ; } const rIC = ( window as any ) . requestIdleCallback || setTimeout ; let observer = 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 ( '#app a' ) . forEach ( ( link ) => { const { target , hostname , pathname } = link as HTMLAnchorElement ; const extMatch = pathname . match ( /\.\w+$/ ) ; if ( extMatch && extMatch [ 0 ] !== '.html' ) { return ; } if ( target !== `_blank` && hostname === location . hostname ) { if ( pathname !== location . pathname ) { observer ! . observe ( link ) ; } else { hasFetched . add ( pathname ) ; } } } ) ; } ) ; } ; onMounted ( observeLinks ) ; const route = useRoute ( ) ; watch ( ( ) => route . path , observeLinks ) ; onUnmounted ( ( ) => { observer && observer . disconnect ( ) ; } ) ; }