Code Monkey home page Code Monkey logo

preload-plugin's Introduction

Swup Preload Plugin

A swup plugin for preloading pages and faster navigation.

  • Links with a data-swup-preload attribute will be preloaded automatically
  • Hovering a link on pointer devices will preload that link's URL, speeding up load time by a few 100ms. To save server resources, the number of simultaneous preload requests is limited to 5 by default.
  • Touch devices will instead preload links at the start of touch events, giving a ~80ms speed-up
  • Optionally preload links as they become visible in the viewport

Installation

Install the plugin from npm and import it into your bundle.

npm install @swup/preload-plugin
import SwupPreloadPlugin from '@swup/preload-plugin';

Or include the minified production file from a CDN:

<script src="https://unpkg.com/@swup/preload-plugin@3"></script>

Usage

To run this plugin, include an instance in the swup options.

const swup = new Swup({
  plugins: [new SwupPreloadPlugin()]
});

Preloading

The plugin supports four ways of preloading links:

  • Hovering a link
  • Marking links to preload with a special attribute
  • Watching the viewport for links to become visible
  • Passing in a list of URLs to preload at once

Hovering links

Hovering a link will automatically preload it. Enabled by default.

Depending on the user's device, the preload will be triggered when it is hovered with a mouse, touched with a finger, or focused using the keyboard. Hovered links are preloaded with higher priority than other running requests.

<a href="/about">About</a> <!-- will preload when hovering -->

Marking links to preload

To preload specific links, mark them with the data-swup-preload attribute.

<a href="/about" data-swup-preload>About</a>

To preload all links in a container, mark the container with data-swup-preload-all.

<nav data-swup-preload-all>
  <a href="/about">About</a>
  <a href="/contact">Contact</a>
</nav>

Preload links as they become visible

Preload links as they enter the viewport. Not enabled by default.

See the preloadVisibleLinks option for details.

Preload a list of URLs

Preload specific known URLs.

See the swup.preload() method for details.

Options

throttle

Type: Number, Default: 5

The concurrency limit for simultaneous requests when preloading.

preloadHoveredLinks

Type: Boolean, Default: true

Preload links when they are hovered, touched or focused.

preloadVisibleLinks

Type: Boolean | Object, Default: false

Preload links when they enter the viewport. Pass in a boolean true to enable with default options.

new SwupPreloadPlugin({ preloadVisibleLinks: true })

For more control over the behavior, pass in an object. These are the default options:

new SwupPreloadPlugin({
  preloadVisibleLinks: {
    /** How much area of a link must be visible to preload it: 0 to 1.0 */
    threshold: 0.2,
    /** How long a link must be visible to preload it, in milliseconds */
    delay: 500,
    /** Containers to look for links in */
    containers: ['body'],
    /** Callback for opting out selected elements from preloading */
    ignore: (el) => false
  }
})

preloadInitialPage

Type: Boolean, Default: true

Preload the initial page to allow instant back-button navigation after having navigated away from it. Disable this if it causes issues or doesn't make sense in your specific scenario.

Methods on the swup instance

The plugin adds two methods for preloading pages to the swup instance.

preload

Preload a URL or array of URLs. Returns a Promise that resolves when all requested pages have been preloaded.

await swup.preload('/path/to/page');
await swup.preload(['/some/page', '/other/page']);

preloadLinks

Scan the DOM for links with the attribute [data-swup-preload] and call preload for each URL:

swup.preloadLinks();

Hooks

The plugin creates two new hooks.

Note The visit object might be undefined or already settled for these hooks

page:preload

Fires when a page was preloaded.

swup.hooks.on('page:preload', (_visit, { page }) => console.log('preloaded:', page));

link:hover

Fires every time a link is hovered.

swup.hooks.on('link:hover', (_visit, { el }) => console.log('link hovered:', el));

preload-plugin's People

Contributors

daun avatar dependabot[bot] avatar gmrchk avatar hirasso avatar princecodes247 avatar woutervanerp avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

preload-plugin's Issues

Possibility to ignore a certain link?

First of all, great work on Swup.js!

I was wondering if it's possible to ignore a certain link from preloading? Ideally via a data attribute. My website has multiple links to PDF files, these can't be preloaded which throws errors in the console.

Any guidance would be appreciated!

Optimize the preload mechanism on desktop and mobile

Describe your issue:

During the last refactor I had the chance to investigate how preload plugin handles preloading pages if the visitor hovers a link:

  • It initializes the preload immediately on mouseover of a link
  • It checks if swup is already preloading another page
  • If no other preload is in progress, it starts the preload of the page the link points towards
  • On mobile, the mouseover event is also being triggered (in my tests around ~5ms before the click event). Here the preload effect is minimal due to the near-immediate click after mouseover.

Where I see some room for improvement:

1. On Desktop

If the visitor moves their mouse over a bunch of links towards the link they actually want to click, they will trigger a preload for the very first link they hovered during moving their mouse. This preload will have to finish before another preload can be started. I would propose that we introduce a slight delay (65ms 100ms) that will be reset every time another link is being hovered. That way, we increase the chance that the actual page the user wants to visit will be able to be preloaded and not be blocked by another running preload.

2. On Mobile

While the mouseover event is being triggered before the actual click event, the timespan could be improved by using touchstart instead. That will give the preload ~80ms more time to load.

Props to instant.page for the inspiration :)

'pagePreloaded' event doesn't pass any arguments

The docs for this plugin include an example for listening to the pagePreloaded event like this:

swup.on('pagePreloaded', (page) => console.log('preloaded:' page));

which simply logs preloaded: undefined

The event is triggered from here in the code: https://github.com/swup/preload-plugin/blob/365df1f881fa4c6482de547e6a6fcbba6813457c/src/index.js#LL180C4-L183C32

const cacheablePageData = { ...page, url };
swup.cache.cacheUrl(cacheablePageData);
swup.triggerEvent('pagePreloaded');

Adjusting this last line to swup.triggerEvent('pagePreloaded', page) or swup.triggerEvent('pagePreloaded', url) seems to do the trick! (I'm not sure what kind of data was initially intended to be passed to that listener) It's a small thing but would be nice to be able to grab the page info.

I haven't made a demo or anything since I think it's pretty simple to see what's going on and replicate, but let me know if that would be helpful πŸ˜„ Thank you for the awesome library/plugin!

requestIdleCallback not available in Safari

Although the plugin seems to work just fine, the following error is being thrown in Safari: Unhandled Promise Rejection: ReferenceError: Can't find variable: requestIdleCallback, as the browser does not support requestIdleCallback.

See a related issue: remix-run/indie-stack#124 where a possible fallback is being suggested.

Thanks for all your effort on this, much appreciated!

`options.preloadHoveredLinks` incorrectly set up

Description of the issue

It seems the preloadHoveredLinks option has not been set up correctly. If it's set to false, links are still preloaded on hover.
This is because the mouse/touch/focus event delegates are created regardless of this option.

Additionally, when set to false, it seems the option disables the preloading of links with the [data-swup-preload] attribute instead.
I don't believe this was intentional as the docs clearly state the preloading of these links should happen automatically.

Perhaps totally pointless, but this option could be optionally set as an object (similarly to preloadVisibleLinks) to enable/disable
preloading on mouse/touch/focus independently:

new SwupPreloadPlugin({
  preloadHoveredLinks: {
    /** Enable preloading on mouse enter */
    mouse: true,
    /** Enable preloading on touch start */
    touch: true,
    /** Enable preloading on focus */
    focus: true
  }
})

How to reproduce the issue

Simply set preloadHoveredLinks: false, open the Network tab in developer tools and see links still being preloaded as they're hovered on. Also, links with the [data-swup-preload] attribute will not be preloaded.

Before creating this issue...

  • Have you provided all helpful information available?
  • Have you checked closed issues for similar/related problems?
  • Have you considered creating a demo so we can help you better?

Remove duplicated logic for handling fetch response

  • Currently, the logic for handling the fetch response is duplicated between the core and the preload plugin
  • Instead of handling the response here, just pass the promise itself to swup and let it handle it
  • To keep the pagePreloaded event, this would require chaining a single .then() to the promise before passing it on
  • Think about the effects an aborted promise would have -- memory leak?

Links with identical `href` will remove urls from `preloadVisibleLinks` queue even if these should actually be preloaded.

Description of the issue

Imagine a sub page of a website where there is a link to let's say /, both at the very start as well as in the footer of the document. preloadVisibleLinks will never preload the first element on the page, even though it's in the viewport. The reason for that is that the the link to / in the footer is not in the viewport and thus will immediately remove the link again, just after it was added for the first link.

Workaround

Providing a data-swup-preload attribute manually.

Possible Solution

Haven't thought about a solution, yet πŸ˜„ ...but we definitely need one.

Preload stylesheets

Describe the proposed solution

  • Parse the head of preloaded pages for stylesheets and prefetch them
  • Stylesheets are always render-blocking when in the head, so it makes sense to prefetch them
  • Should use native rel=prefetch markup as swup has no concept of an asset cache

Alternatives considered

  • Implement it myself in the page:preload hook

How important is this feature to you?

  • Nice to have
  • Would make my life a lot easier
  • I cannot use swup without it

[Bug]: External links are not being properly ignored on hover

What did you expect? 🧐

If I am on a website https://example.com and I have an external link on that site, for example:

<a href="https://www.instagram.com/followme">@followme</a>

I'd expect preload plugin to ignore that link when I hover over it.

What actually happened? πŸ˜΅β€πŸ’«

Currently the plugin will attempt to preload this URL:

https://example.com/{{path/of/external/link}}

So based on the example above this: https://example.com/followme

I suspect the problem lies within Location.fromElement that is being used here:

({ url } = Location.fromElement(input));

That function doesn't check if the provided URL is actually an internal URL or not.

I'll investigate further.

Swup and plugin versions πŸ“

❯ npm list | grep swup
β”œβ”€β”€ @swup/[email protected]
β”œβ”€β”€ @swup/[email protected]
β”œβ”€β”€ @swup/[email protected]
β”œβ”€β”€ @swup/[email protected]
β”œβ”€β”€ @swup/[email protected]
β”œβ”€β”€ @swup/[email protected]
β”œβ”€β”€ @swup/[email protected]
β”œβ”€β”€ @swup/[email protected]
β”œβ”€β”€ [email protected]

What browsers are you seeing the problem on? 🧭

No response

Relevant log output πŸ€“

No response

URL to minimal reproduction πŸ”—

n/a

Checked all these? πŸ“š

dist/index.module.js is missing

Parcel gives me this error on this package only. It works perfectly in 3.2.0 when I'm forcing it, so I'm assuming a regression.

[Question] How to activate hover only preload

Describe your issue:
Sometimes it's not necessary to preload or even not optimal (on mobile data), to preload all the annotated links.

So it possible to activate the hover-only link preload?

Preload-Plugin Compromises SSL Certificate and creates time-out issues in WP

Good greetings!
Love swup. I'm using v2 and noticed that when using the Preload plugin, the SSL lock disappears from the browser and time-outs are prompted in Wordpress. These issues are resolved once the Preload plugin is disabled/removed.

Any ideas as to why this is the case?
Would love to continue using the preload plugin, but these are major interruptions to workflow.

Please let me know!

Kind regards

`options.preloadVisibleLinks.enabled` not being applied automatically

Description of the issue

IMO it's save to assume that initializing preload plugin like this:

new SwupPreloadPlugin({
	preloadVisibleLinks: {
		delay: 0,
	},
})

...should automatically set preloadVisibleLinks.enabled to true. The plugin docs also suggest that behavior.

This is not the case right now. What's your opinion here @daun ?

Before creating this issue...

  • Have you provided all helpful information available?
  • Have you checked closed issues for similar/related problems?

Detect network idle time for preloading?

First of, thanks for swup in general. We integrated it some days ago in one of our sites and it works like a charm.

I had the idea of using requestIdleCallback for preloading other pages. What do you think? I would be happy to try it out in a fork and make a PR, if you are interested.

Preload not working on hover

Hi, I'm moving a site from the previous version of swup to the new one, and I've added the preload plugin but it doesn't seem to preload on hover anymore. Has this functionality been removed/broken?

`mouseover` is triggered multiple times on links with complex (nested) markup

Describe your issue:
Right now, since mouseover bubbles, it triggers multiple times on links with complex markup:

<a href="/my-path/">
  <span>Link Text</span>
</a>

Here swup.on('hoverLink') will be triggered as for the <a> as well as for the <span>

A consumer-side workaround for that is to disable pointer events on the link's children:

a * {
  pointer-events: none;
}

But maybe we can find a better solution that doesn't depend on the consumer-side implementation? mouseenter wouldn't work with delegation, since it doesn't bubble.

Feature: preload links in viewport

Describe the problem

  • Currently, we have to add DOM attributes on elements to preload
  • That doesn't quite fit the claim of the plugin: smart preloading
  • A better heuristic would be preloading visible links

Describe the proposed solution

  • Implement a feature similar to quicklink: preload visible links in the viewport
  • Install an IntersectionObserver on the viewport
  • Preload all links inside the viewport

Alternatives considered

  • Use quicklink directly
    • They include lots of compatibility code we don't need
    • They have lots of options we don't need

How important is this feature to you?

  • Nice to have
  • Would make my life a lot easier
  • I cannot use swup without it

Bundling error with webpack

Description of the issue

  • Webpack seems to have problems bundling the throttles package from throttles/priority

How to reproduce the issue

  • Install preload-plugin
  • Bundle using webpack ^5.0

Suggested solution

  • Inline the package for now, until this is solved and the recent PR for TS support is merged

Priority queue

Describe the problem

  • Assign priority to preloads: low for DOM links, high for current hover/touchstart links

Describe the proposed solution

  • Use a queue system to enqueue the maximum amount of items
  • Allow setting a priority on preloads

How important is this feature to you?

  • Would make my life a lot easier
  • Would make another feature much simpler to implement

Feature: preload links on focus

Describe the problem

  • If hovering a link should preload it, focusing it with the keyboard should preload it as well

Describe the proposed solution

  • Install an additional focus event handler that triggers a preload

How important is this feature to you?

  • Great for accessibility

Allow marking parent container to preload all children

Allow setting the preload attribute on a parent.

<ul data-swup-preload>
  <li><a href="/lorem/">Lorem</a></li>
  <li><a href="/ipsum/">Ipsum</a></li>
  <li><a href="/dolor/">Dolor</a></li>
</ul>

Probable solution:

- queryAll('[data-swup-preload]')
+ queryAll('a[data-swup-preload], [data-swup-preload] a')

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.