sveltejs / sveltejs/kit

Provide ability to instrument preload and load

Open
#10,758 0 comments 5 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

load / layout needs-decision router
Dominant language
JavaScript
Stars
20.8k
Forks
2.3k
Avg merge
1d 16h
Merged PRs (30d)
156

Description

Describe the problem

We are currently trying to setup up client-side instrumentation for our application using OpenTelemetry. For context, Otel generalizes a notion of a span (think like the callstack span you might see in the JS debugger) and allows you to create custom spans that can contain other spans across services. So in the browser, for instance, it is common to wrap fetch in a function that creates a span and passes it along to the server, so you can see all the different things that fetch request triggered and handled.

Instrumenting fetch on the client is it's own can of worms that's being discussed in https://github.com/sveltejs/kit/issues/9530 and https://github.com/sveltejs/kit/pull/10009, and those would help a lot with allowing apps to do this kind of instrumentation. However, there is another issue we've been running into, specifically around the load hooks of pages and the preloading feature.

Ideally, we would create a span to wrap each load hook that is called. This way we can see the collection of load requests that went into every single page's render, and also gather metrics such as duration. We started building a solution to this based on onNavigate (which is not ideal because it's tied to a component lifecycle rather than being global, but that's a separate issue), but we found that our spans created in onNavigate were never being associated with the fetch requests that the load function was making. After some head scratching, we realized this was due to the preloading functionality SvelteKit exposes.

When the user hovers over a link, SvelteKit starts preloading the data for the route it is going to by default. This is great behavior for optimizing UX out of the box, but currently there doesn't seem to be a way to instrument this behavior and group it together logically into a single notion of a "page load". This means we can't accurately track the impact it has on users, whether or not prefetching is erroring, and what the overall performance of these preload calls is.

We considered disabling preloading altogether, but there doesn't appear to be a way to do this globally in an app at the moment. Moreover, the issue is not with the functionality itself, but with our inability to observe it.

Describe the proposed solution

I think this could be handled a few different ways:

  1. Add handle to client side hooks, which would run for all client side load calls. This feels like it would be ideal from an API perspective if it would work, because then you are just conceptually mirroring the server functionality, but I could see this being tricky for a number of reasons on the client (different signatures, different notion of what an "event" is, etc).
  2. Add client-side handleLoad and/or handlePreload hooks, or alternatively handleNavigate (though, like onNavigate, that would imply it only runs on actual user navigation). This would be a more targeted version of adding hooks, which means the API is less generalized and not as much of a commitment.
  3. Add an onPreload function to the navigation module, which allows us to hook into the preload event much like a navigation event. This seems less ideal to me because preloading doesn't really seem to relate to a component as much, but it would solve the issue for us.
Alternatives considered

We've considered wrapping every single load hook with an instrumentLoad helper function, but this has a number of issues:

  1. It makes type annotations a pain to write overall, a lot more boilerplate per module
  2. Mistakes were very common, devs would forget to add the instrumentation all the time
  3. It runs on the server as well, where we don't have this issue because we can wrap all events in a request in a span using the handle hook
Importance

i cannot use SvelteKit without it

Additional Information

Long term we really need this functionality, I'm exploring ways I could have our build-system add instrumentLoad helpers to each page load via a Vite plugin but ideally this would be pluggable within the framework.

Also, happy to implement this if it is accepted.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the client-side load hooks, preloading behavior, and the navigation module, including how onNavigate currently relates to navigation. Compare the proposed client-side handle, handleLoad, handlePreload, handleNavigate, and onPreload entry points. Done would mean applications can observe and group preload and load work for instrumentation without wrapping every load hook.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
frontend, observability
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.