elliott/hydratable
Elliott Johnson 19 hours ago
parent 90dd32b6e2
commit 3f3ad1a2e6

@ -7,9 +7,6 @@ A `hydratable` value with key `%key%` was created, but at least part of it was n
The `hydratable` was initialized in:
%stack%
The unresolved data is:
%unresolved_data%
```
The most likely cause of this is creating a `hydratable` in the `script` block of your component and then `await`ing

@ -4,9 +4,6 @@
>
> The `hydratable` was initialized in:
> %stack%
>
> The unresolved data is:
> %unresolved_data%
The most likely cause of this is creating a `hydratable` in the `script` block of your component and then `await`ing
the result inside a `svelte:boundary` with a `pending` snippet:

@ -21,11 +21,8 @@ export function hydratable(key, fn) {
}
const store = window.__svelte?.h;
const unused_keys = window.__svelte?.uh;
if (!store?.has(key)) {
if (!unused_keys?.has(key)) {
hydratable_missing_but_expected(key);
}
return fn();
}

@ -7,8 +7,6 @@ declare global {
__svelte?: {
/** hydratables */
h?: Map<string, unknown>;
/** unused hydratable keys */
uh?: Set<string>;
};
}
}

@ -10,7 +10,6 @@ import { BLOCK_CLOSE, BLOCK_OPEN } from './hydration.js';
import { attributes } from './index.js';
import { get_render_context, with_render_context, init_render_context } from './render-context.js';
import { DEV } from 'esm-env';
import { get_stack } from './dev.js';
/** @typedef {'head' | 'body'} RendererType */
/** @typedef {{ [key in RendererType]: string }} AccumulatedContent */
@ -578,14 +577,10 @@ export class Renderer {
async #collect_hydratables() {
const ctx = get_render_context().hydratable;
for (const [promise, key] of ctx.unresolved_promises) {
for (const [_, key] of ctx.unresolved_promises) {
// this is a problem -- it means we've finished the render but we're still waiting on a promise to resolve so we can
// serialize it, so we're blocking the response on useless content.
w.unresolved_hydratable(
key,
ctx.lookup.get(key)?.dev?.stack ?? '<missing stack trace>',
await promise
);
w.unresolved_hydratable(key, ctx.lookup.get(key)?.dev?.stack ?? '<missing stack trace>');
}
for (const comparison of ctx.comparisons) {
@ -593,7 +588,7 @@ export class Renderer {
await comparison;
}
return await Renderer.#hydratable_block(ctx, []);
return await Renderer.#hydratable_block(ctx);
}
/**
@ -652,10 +647,9 @@ export class Renderer {
/**
* @param {HydratableContext} ctx
* @param {string[]} unused_keys
*/
static async #hydratable_block(ctx, unused_keys) {
if (ctx.lookup.size === 0 && unused_keys.length === 0) {
static async #hydratable_block(ctx) {
if (ctx.lookup.size === 0) {
return null;
}
@ -676,7 +670,7 @@ export class Renderer {
const value = v[i];
return typeof value === 'function' ? value() : value;
};
const sv = window.__svelte ??= {};${Renderer.#used_hydratables(ctx.lookup)}${Renderer.#unused_hydratables(unused_keys)}
const sv = window.__svelte ??= {};${Renderer.#used_hydratables(ctx.lookup)}
}
</script>`;
}
@ -693,16 +687,6 @@ export class Renderer {
store.set(k, d(i));
}`;
}
/** @param {string[]} unused_keys */
static #unused_hydratables(unused_keys) {
if (unused_keys.length === 0) return '';
return `
const unused = sv.uh ??= new Set();
for (const k of ${JSON.stringify(unused_keys)}) {
unused.add(k);
}`;
}
}
export class SSRState {

@ -2,7 +2,6 @@ import { afterAll, beforeAll, describe, expect, test } from 'vitest';
import { Renderer, SSRState } from './renderer.js';
import type { Component } from 'svelte';
import { disable_async_mode_flag, enable_async_mode_flag } from '../flags/index.js';
import { uneval } from 'devalue';
test('collects synchronous body content by default', () => {
const component = (renderer: Renderer) => {

@ -10,23 +10,16 @@ var normal = 'font-weight: normal';
*
* The `hydratable` was initialized in:
* %stack%
*
* The unresolved data is:
* %unresolved_data%
* @param {string} key
* @param {string} stack
* @param {string} unresolved_data
*/
export function unresolved_hydratable(key, stack, unresolved_data) {
export function unresolved_hydratable(key, stack) {
if (DEV) {
console.warn(
`%c[svelte] unresolved_hydratable\n%cA \`hydratable\` value with key \`${key}\` was created, but at least part of it was not used during the render.
The \`hydratable\` was initialized in:
${stack}
The unresolved data is:
${unresolved_data}\nhttps://svelte.dev/e/unresolved_hydratable`,
${stack}\nhttps://svelte.dev/e/unresolved_hydratable`,
bold,
normal
);

@ -107,7 +107,6 @@ declare global {
var __svelte:
| {
h?: Map<string, unknown>;
uh?: Set<string>;
}
| undefined;
}
@ -127,7 +126,6 @@ beforeAll(() => {
beforeEach(() => {
delete globalThis?.__svelte?.h;
delete globalThis?.__svelte?.uh;
});
afterAll(() => {

@ -15,7 +15,7 @@ export default test({
},
async test({ assert, target }) {
// let it hydrate and resolve the promise on the client
// make sure the hydratable promise on the client has a chance to run and reject (it shouldn't, because the server data should be used)
await tick();
assert.htmlEqual(

Loading…
Cancel
Save