Skip to content

Conversation

@elliott-with-the-longest-name-on-github
Copy link
Contributor

This is a draft, it's not ready, leave me alone

Before submitting the PR, please make sure you do the following

  • 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
  • Prefix your PR title with feat:, fix:, chore:, or docs:.
  • This message body should clearly illustrate what problems it solves.
  • Ideally, include a test that fails without this PR but passes with it.
  • If this PR changes code within packages/svelte/src, add a changeset (npx changeset).

Tests and linting

  • Run the tests with pnpm test and lint the project with pnpm lint

@changeset-bot
Copy link

changeset-bot bot commented Oct 15, 2025

⚠️ No Changeset found

Latest commit: 9a424cd

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@svelte-docs-bot
Copy link

@paoloricciuti
Copy link
Member

This is a draft, it's not ready, leave me alone

17605526257128346051930270607464

@nosovk
Copy link
Contributor

nosovk commented Oct 25, 2025

Very interesting approach

@github-actions
Copy link
Contributor

Playground

pnpm add https://pkg.pr.new/svelte@16960


/** @typedef {{ count: number, item: any }} Entry */
/** @type {Map<string, CacheEntry>} */
const client_cache = new Map();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that the intent here is for libraries to provide a prefix if they're going to use this API, should this be a two-tiered cache? Right now, if a library (like SvelteKit) wants to do something to everything it has in the cache, it has to iterate over all of the map entries, skipping the ones that don't start with its prefix, and refresh the things that do start with its prefix.

Maybe what we should do is make this two-tiered, where, if you don't provide a prefix, everything gets put into client_cache.get(''), but if you do, you get a namespaced cache. So in the case of SvelteKit, we'd end up with client_cache.get('@sveltejs/kit/remote'), which can be operated on as its own entity.

From an API perspective, you can provide a prefix as part of a third options argument to cache. Then, if you use CacheObserver, providing a prefix will automatically scope it to your cache.

The downside would be if you truly wanted to operate on the entire cache, which would be more complicated...

* @returns {Resource<TReturn>}
*/
export function fetcher(url, init) {
const key = `svelte/fetcher/${typeof url === 'string' ? url : url.toString()}`;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given how simple this is I'm quite tempted to say "nah, this can be an example in the docs" instead of shipping it as a core API...

static #hydratable_block(serialized) {
let entries = [];
for (const [k, v] of serialized) {
entries.push(`["${k}",${v}]`);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been struggling with what the correct thing to do here is. Is it to JSON.stringify the key, and leave the value to whatever value.toString results in? When a user provides encode, does that function have to result in a string? Or does it have to result in something that can be toString-ed? Or something else entirely?

/**
* @template T
* @implements {ReadonlyMap<string, T>} */
export class BaseCacheObserver {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thing here -- should this actually be a two-tier cache, where the key provided here gives you access to a map specific to that key?

if (!key.startsWith(this.#prefix)) continue;
yield /** @type {[string, T]} */ ([key, entry.item]);
}
return undefined;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is required for the implementation to succeed in typescript 🤔

Comment on lines +18 to +26
export type Transport<T> =
| {
encode: Encode<T>;
decode?: undefined;
}
| {
encode?: undefined;
decode: Decode<T>;
};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this rather unique way of describing this type will force people to use browser ? { decode: () => {} } : { encode: () => {} } so that encode/decode can be properly treeshaken in the correct environments

export async function fetch_json(url, init) {
const response = await fetch(url, init);
if (!response.ok) {
throw new Error(`TODO error: Fetch error: ${response.status} ${response.statusText}`);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants