Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Turbolinks Prefetching
const hoverTime = 400
const fetchers = {}
const doc = document.implementation.createHTMLDocument('prefetch')
function fetchPage (url, success) {
const xhr = new XMLHttpRequest()
xhr.open('GET', url)
xhr.setRequestHeader('VND.PREFETCH', 'true')
xhr.setRequestHeader('Accept', 'text/html')
xhr.onreadystatechange = () => {
if (xhr.readyState !== XMLHttpRequest.DONE) return
if (xhr.status !== 200) return
success(xhr.responseText)
}
xhr.send()
}
function prefetchTurbolink (url) {
fetchPage(url, responseText => {
doc.open()
doc.write(responseText)
doc.close()
const snapshot = Turbolinks.Snapshot.fromHTMLElement(doc.documentElement)
Turbolinks.controller.cache.put(url, snapshot)
})
}
function prefetch (url) {
if (prefetched(url)) return
prefetchTurbolink(url)
}
function prefetched (url) {
return location.href === url || Turbolinks.controller.cache.has(url)
}
function prefetching (url) {
return !!fetchers[url]
}
function cleanup (event) {
const element = event.target
clearTimeout(fetchers[element.href])
element.removeEventListener('mouseleave', cleanup)
}
document.addEventListener('mouseover', event => {
if (!event.target.dataset.prefetch) return
const url = event.target.href
if (prefetched(url)) return
if (prefetching(url)) return
cleanup(event)
event.target.addEventListener('mouseleave', cleanup)
fetchers[url] = setTimeout(() => prefetch(url), hoverTime)
})
@frederikhors

This comment has been minimized.

Copy link

frederikhors commented Sep 26, 2019

let can be changed to const on lines 6, 22, 48.

'url' is never reassigned. Use 'const' instead.eslint(prefer-const)

@feliperaul

This comment has been minimized.

Copy link

feliperaul commented Mar 18, 2020

@hopsoft Can you please consider adding xhr.setRequestHeader('Accept', 'text/html') to avoid triggering format.js responses on controllers that use respond_to do |block| syntax, since it's we're always looking for the HTML versions?

That fixed the ActionController::InvalidCrossOriginRequest I was getting on that controller/action.

@hopsoft

This comment has been minimized.

Copy link
Owner Author

hopsoft commented Mar 20, 2020

Thanks for suggesting this. I'll get the gist updated.

@vitobotta

This comment has been minimized.

Copy link

vitobotta commented Mar 27, 2020

Hi, thanks a lot for this gist! I've tried adding the touchstart event too for mobile but it doesn't seem to work. Any suggestions? Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.