feat: hydratable and a more consistent remote functions model#15533
Conversation
🦋 Changeset detectedLatest commit: 95fdd23 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
…rowser consoles
This commit fixes the issue reported at packages/kit/src/runtime/client/remote-functions/query.svelte.js:58
**Bug Explanation:**
Three debug console.log statements were left in the production code at:
* Line 58: `console.log(cache_key + ' bypassed hydratable');`
* Line 292: `console.log(this._key, 'serving from the cache');`
* Line 295: `console.log(this._key, 'made it past the cache');`
These statements appear to be development debugging aids that were not removed before committing. The codebase has a clear pattern for console.log usage:
1. In build/CLI tools (acceptable since those run in Node.js during development)
2. Guarded by `DEV` checks for runtime code (e.g., line 671 in respond.js uses `if (DEV && ...) { console.log(...) }`)
The unguarded console.log statements in query.svelte.js would execute on every query run/cache check in production, spamming end users' browser consoles with internal debugging messages like "query-key serving from the cache" and "query-key bypassed hydratable".
**Fix:**
Removed all three debug console.log statements since they serve no purpose for production users and were clearly left in accidentally (evidenced by commit messages like "i think it work" indicating development-in-progress code).
Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: elliott-with-the-longest-name-on-github <hello@ell.iott.dev>
…om:sveltejs/kit into elliott/remote-functions-hydratable-take-2
03670ad
into
main
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## @sveltejs/kit@2.56.0 ### Minor Changes - breaking: rework client-driven refreshes ([#15562](#15562)) - breaking: stabilize remote function caching by sorting object keys ([#15570](#15570)) - breaking: add `run()` method to queries, disallow awaiting queries outside render ([#15533](#15533)) - feat: support TypeScript 6.0 ([#15595](#15595)) - breaking: isolate command-triggered query refresh failures per-query ([#15562](#15562)) - feat: use `hydratable` for remote function transport ([#15533](#15533)) - feat: allow `form` fields to specify a default value (`field.as(type, value)`) ([#15577](#15577)) ### Patch Changes - fix: don't request new data when `.refresh` is called on a query with no cache entry ([#15533](#15533)) - fix: allow using multiple remote functions within one async derived ([#15561](#15561)) - fix: avoid false-positive overridden Vite `base` setting warning when setting a `paths.base` in `svelte.config.js` ([#15623](#15623)) - fix: manage queries in their own `$effect.root` ([#15533](#15533)) - fix: avoid `inlineDynamicImports` deprecation warning when building the service worker with Vite 8 ([#15550](#15550)) - fix: correctly escape backticks when precomputing CSS ([#15593](#15593)) - fix: discard obsolete forks before finishing navigation ([#15634](#15634)) - chore: tighten up override implementation ([#15562](#15562)) - fix: ensure the default Svelte 5 `error.svelte` file uses runes mode ([#15609](#15609)) - fix: deduplicate same-cache-key `batch` calls during SSR ([#15533](#15533)) - fix: decrement pending_count when form callback doesn't call submit() ([#15520](#15520)) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [@sveltejs/kit](https://svelte.dev) ([source](https://github.com/sveltejs/kit/tree/HEAD/packages/kit)) | [`2.55.0` → `2.56.1`](https://renovatebot.com/diffs/npm/@sveltejs%2fkit/2.55.0/2.56.1) |  |  | --- ### Release Notes <details> <summary>sveltejs/kit (@​sveltejs/kit)</summary> ### [`v2.56.1`](https://github.com/sveltejs/kit/blob/HEAD/packages/kit/CHANGELOG.md#2561) [Compare Source](https://github.com/sveltejs/kit/compare/@sveltejs/kit@2.56.0...@sveltejs/kit@2.56.1) ##### Patch Changes - chore: update JSDoc ([#​15640](sveltejs/kit#15640)) ### [`v2.56.0`](https://github.com/sveltejs/kit/blob/HEAD/packages/kit/CHANGELOG.md#2560) [Compare Source](https://github.com/sveltejs/kit/compare/@sveltejs/kit@2.55.0...@sveltejs/kit@2.56.0) ##### Minor Changes - breaking: rework client-driven refreshes ([#​15562](sveltejs/kit#15562)) - breaking: stabilize remote function caching by sorting object keys ([#​15570](sveltejs/kit#15570)) - breaking: add `run()` method to queries, disallow awaiting queries outside render ([#​15533](sveltejs/kit#15533)) - feat: support TypeScript 6.0 ([#​15595](sveltejs/kit#15595)) - breaking: isolate command-triggered query refresh failures per-query ([#​15562](sveltejs/kit#15562)) - feat: use `hydratable` for remote function transport ([#​15533](sveltejs/kit#15533)) - feat: allow `form` fields to specify a default value (`field.as(type, value)`) ([#​15577](sveltejs/kit#15577)) ##### Patch Changes - fix: don't request new data when `.refresh` is called on a query with no cache entry ([#​15533](sveltejs/kit#15533)) - fix: allow using multiple remote functions within one async derived ([#​15561](sveltejs/kit#15561)) - fix: avoid false-positive overridden Vite `base` setting warning when setting a `paths.base` in `svelte.config.js` ([#​15623](sveltejs/kit#15623)) - fix: manage queries in their own `$effect.root` ([#​15533](sveltejs/kit#15533)) - fix: avoid `inlineDynamicImports` deprecation warning when building the service worker with Vite 8 ([#​15550](sveltejs/kit#15550)) - fix: correctly escape backticks when precomputing CSS ([#​15593](sveltejs/kit#15593)) - fix: discard obsolete forks before finishing navigation ([#​15634](sveltejs/kit#15634)) - chore: tighten up override implementation ([#​15562](sveltejs/kit#15562)) - fix: ensure the default Svelte 5 `error.svelte` file uses runes mode ([#​15609](sveltejs/kit#15609)) - fix: deduplicate same-cache-key `batch` calls during SSR ([#​15533](sveltejs/kit#15533)) - fix: decrement pending\_count when form callback doesn't call submit() ([#​15520](sveltejs/kit#15520)) </details> --- ### Configuration 📅 **Schedule**: (in timezone UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMDQuMSIsInVwZGF0ZWRJblZlciI6IjQzLjEwNC4xIiwidGFyZ2V0QnJhbmNoIjoiZGV2ZWxvcCIsImxhYmVscyI6WyJLaW5kL0RlcGVuZGVuY2llcyJdfQ==--> Reviewed-on: https://codeberg.org/ampmod/aw3/pulls/57 Co-authored-by: AmpMod Bot <ampmod-bot@noreply.codeberg.org> Co-committed-by: AmpMod Bot <ampmod-bot@noreply.codeberg.org>
This isn't documented in https://svelte.dev/docs/kit/remote-functions I was using a remote query inside a class method that gets invoked on a button click. After updating to the latest sveltekit, I need to add a |
) Per #17862 (comment), this freezes the value of a derived if it was created inside a parent effect that is now destroyed. This prevents the sort of bug where a derived reads `foo.bar` even though `foo` is now `undefined`. If the derived is dirty, a warning will be printed. This PR also gets rid of some weirdness around `derived.parent` — it can only ever be an `Effect | null`, and there's no need for `get_derived_parent_effect`. Blocked on sveltejs/kit#15533 and a follow-up that switches remote functions to use `$effect.root` (since this effectively undoes #17171), hence draft. ### Before submitting the PR, please make sure you do the following - [x] It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs - [x] Prefix your PR title with `feat:`, `fix:`, `chore:`, or `docs:`. - [x] This message body should clearly illustrate what problems it solves. - [x] Ideally, include a test that fails without this PR but passes with it. - [x] If this PR changes code within `packages/svelte/src`, add a changeset (`npx changeset`). ### Tests and linting - [x] Run the tests with `pnpm test` and lint the project with `pnpm lint` --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>
|
Hi, this has broken some existing integration with Tanstack Query v6 that we relied on. Is there a recommended pattern to keep this functional with Tanstack Query? Example in <script lang="ts">
import { createQuery } from "@tanstack/svelte-query";
import { query_program } from "../../programs/(remote)/programs.remote.ts";
const program_query = createQuery(() => ({
queryKey: ["program", programId] as const,
queryFn: async () => {
return await query_program(programId);
},
}));
</script> |
|
This also broke the type system, commands returning |
|
@sergiocampama / @ConProgramming please file issues for these, happy to discuss there -- not going to spam other maintainers who were following this PR with notifications |
…-reactive contexts (#15699) As of #15533, `query().current` no longer works in non-reactive contexts. I believe this is unwanted behavior -- take the following scenario: ```svelte <script> import { list_todos } from '$lib/todos.remote'; $effect(() => { const events = subscribe_to_something_external(); events.on('new-todo', (item) => { // I don't want to call `.run()` here, because if `list_todos` // is not currently used, I don't care about the result // (it would just waste a network request) const current = list_todos().current; if (!current) return; list_todos().set([data.item, ...current]); }); }); </script> ``` This PR fixes it by simply restoring the old behavior of `.current` returning `undefined` if the query has not been called yet.
|
For anyone coming back to this - |
This PR makes a number of substantial changes to how remote queries work.
hydratableImplementation-wise, it replaces our custom transport solution with
hydratablefor queries that are used during render -- this method of transport is more correct and prevents us from accidentally using stale data for queries in a small subset of cases. There's one breaking side effect of this: If you didn't render a query on the server, you can't render it during hydration.It means this:
would throw during hydration because
get_counttried to access cached data that did not exist. This is almost always an undesirable mistake: It means you introduced a waterfall on the client and blocked hydration. If you really do want this, you'd do something like this instead:New rules around query usage
From now on, on the client, you can only access a query's data if that query is:
It may be easier to illustrate when you can't create and use a query on the client:
loadWe're making this change because otherwise it's basically impossible to reliably cache queries across your app. However, for most use cases, this probably doesn't cause any pain:
.refresh,.set,.withOverrideare all availablequery().run(), which will return a plain oldPromiseresolving to your dataBugfixes
$effect.rootwhen created. This prevents them from associating with their parent effect, making their usage more predictable when retrieved from the cache.refreshis now a noop if there is no cached instance of the query, meaning you won't have a useless query request in some circumstanceshydratable!)