kit: Opt out of `load` invalidation

Describe the problem

When running a load function, SvelteKit notes what dependencies the function has…

  • url.pathname, url.search, etc
  • params.x, params.y
  • resources loaded with fetch
  • await parent()

…and re-runs the function when those things change. It’s possible to force an invalidation with invalidate(resource) (where the load function called depends(resource)) or with invalidate() (which invalidates all load functions), but it’s not possible to opt out of invalidation, which is occasionally helpful:

  • you want to log some values but not ‘observe’ them
  • you want to implement more fine-grained invalidation, a la #5850

Describe the proposed solution

We could add an untrack function to load:

export function load({ params, untrack }) {
  untrack(() => console.log(`this will not re-run when ${params.foo}` changes...`));
  console.log(`...but it will re-run when ${params.bar} changes`);
}

Code executed synchronously inside the callback would not affect the function’s dependencies.

Alternatives considered

The alternative is to require developers to be completely explicit about when load should re-run, or to always re-run every load function (which no-one wants).

Importance

nice to have

Additional Information

No response

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 28
  • Comments: 21 (18 by maintainers)

Commits related to this issue

Most upvoted comments

In case someone else needs this now, you can use Object.getOwnPropertyDescriptor to get object properties without triggering a the invalidation. Based on the solution from @Algoinde 🙌

const someUntrackedParam = Object.getOwnPropertyDescriptor(event.params, 'some-param')?.value; 

Had a showerthought about a possible solution for this. I think the concept of “automatic invalidation” is inherently confusing - you did not do anything to cause that, it just happens inside the framework. Most of the time you’d rather conserve on requests rather than invalidate everything, therefore you’ll want imperative control over what exactly you want to invalidate, and what you want to just simply reference.

My idea is event.track - an object that includes all of the invalidating things like url, params and so on (even maybe moving depends there), and if accessed via it in the style of event.track.url.searchParams, will raise the invalidation flag. This way, you’re very explicit about the behavior - and no need to opt out, you instead opt in.

I currently opt out via

const absolutelyNotSearchParams =
    Object.getOwnPropertyDescriptor(Object.getPrototypeOf(event.url), 'searchParams').get.call(event.url)

and it feels very cursed to do this. One thing I like about Svelte is I don’t have to wrangle with it, it’s permissive. Here I feel it turned out to be the reverse.

If the invalidation is preferred by default and you’d rather not change the entire API after 1.0, you can put the concept on its head and do event.untrack.url.searchParams. Via intellisense, this will neatly provide the context to what is being tracked.

i’m not sure if this is on-topic, but this is how i got around load invalidation when my load function depends on search params:

export const load: LayoutServerLoad = async ({ request }) => {

    const { searchParams } = new URL(request.url)
      
    console.log(searchParams)
}

Totally valid, yes, this is more a QOL thing

The use case would be “don’t rerun this unless I explictly tell it to”, which you can do with depends and invalidate - but there’s no way to invalidate specific keys while using goto, which I think would be needed as part of the whole picture for this feature.

Yeah, pretty much. Scatter it around the load code, no need to wrap in anything every time - as long as you go through untracked or notrack or whatever the name should be, it’s fine. And it only has properties in which getters are tracked by default.