Skip to content

Commit

Permalink
Enable InstaClick by default (#1162)
Browse files Browse the repository at this point in the history
* Enable InstaClick by default

It will be the new default for Turbo 8. You can always opt out by setting
`<meta name="turbo-prefetch" content="false">` in the head of your HTML.

* Don't prefetch any anchor links

* Don't prefetch UJS links

For compatibility with older apps that use UJS, we should not prefetch
links that have `data-remote`, `data-behavior`, `data-method`, or
`data-confirm` attributes.

All of these behaviors are now usually implemented as buttons, but
there are still some apps that use them on links.

* Allow to customize check to opt out of prefetched links

* Tweak documentation

* Introduce `turbo:before-prefetch` event

To allow for more fine-grained control over when Turbo should prefetch
links. This change introduces a new event that can be used to cancel
prefetch requests based on custom logic.

For example, if you want to prevent Turbo from prefetching links that
include UJS attributes, you can do so by adding an event listener for
the `turbo:before-prefetch` event and calling `preventDefault` on the
event object when the link should not be prefetched.

```javascript
document.body.addEventListener("turbo:before-prefetch", (event) => {
  if (isUJSLink(event.target)) event.preventDefault()
})

function isUJSLink(link) {
  return link.hasAttribute("data-remote") || link.hasAttribute("data-behavior") || link.hasAttribute("data-method") || link.hasAttribute("data-confirm")
}
```
  • Loading branch information
Alberto Fernández-Capel authored Feb 6, 2024
1 parent f4bbb77 commit cdf158f
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 2 deletions.
14 changes: 12 additions & 2 deletions src/observers/link_prefetch_observer.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
dispatch,
doesNotTargetIFrame,
getLocationForLink,
getMetaContent,
Expand Down Expand Up @@ -58,7 +59,7 @@ export class LinkPrefetchObserver {
}

#tryToPrefetchRequest = (event) => {
if (getMetaContent("turbo-prefetch") !== "true") return
if (getMetaContent("turbo-prefetch") === "false") return

const target = event.target
const isLink = target.matches && target.matches("a[href]:not([target^=_]):not([download])")
Expand Down Expand Up @@ -134,7 +135,16 @@ export class LinkPrefetchObserver {
#isPrefetchable(link) {
const href = link.getAttribute("href")

if (!href || href === "#" || link.getAttribute("data-turbo") === "false" || link.getAttribute("data-turbo-prefetch") === "false") {
if (!href || href.startsWith("#") || link.getAttribute("data-turbo") === "false" || link.getAttribute("data-turbo-prefetch") === "false") {
return false
}

const event = dispatch("turbo:before-prefetch", {
target: link,
cancelable: true
})

if (event.defaultPrevented) {
return false
}

Expand Down
2 changes: 2 additions & 0 deletions src/tests/fixtures/hover_to_prefetch.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
>Won't prefetch when hovering me</a>
<a href="/src/tests/fixtures/prefetched.html" id="anchor_with_turbo_false" data-turbo="false"
>Won't prefetch when hovering me</a>
<a href="/src/tests/fixtures/prefetched.html" id="anchor_with_remote_true" data-remote="true"
>Won't prefetch when hovering me</a>
<a href="/src/tests/fixtures/hover_to_prefetch.html" id="anchor_for_same_location"
>Won't prefetch when hovering me</a>
<a href="/src/tests/fixtures/prefetched.html?foo=bar" id="anchor_for_same_location_with_query"
Expand Down
16 changes: 16 additions & 0 deletions src/tests/functional/link_prefetch_observer_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,22 @@ test("it doesn't prefetch the page when link has data-turbo=false", async ({ pag
await assertNotPrefetchedOnHover({ page, selector: "#anchor_with_turbo_false" })
})

test("allows to cancel prefetch requests with custom logic", async ({ page }) => {
await goTo({ page, path: "/hover_to_prefetch.html" })

await assertPrefetchedOnHover({ page, selector: "#anchor_with_remote_true" })

await page.evaluate(() => {
document.body.addEventListener("turbo:before-prefetch", (event) => {
if (event.target.hasAttribute("data-remote")) {
event.preventDefault()
}
})
})

await assertNotPrefetchedOnHover({ page, selector: "#anchor_with_remote_true" })
})

test("it doesn't prefetch the page when link has the same location", async ({ page }) => {
await goTo({ page, path: "/hover_to_prefetch.html" })
await assertNotPrefetchedOnHover({ page, selector: "#anchor_for_same_location" })
Expand Down

0 comments on commit cdf158f

Please sign in to comment.