pull/12507/head
Rich Harris 2 years ago
commit 382f17c1b9

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: reset hydrate node after `hydrate(...)`

@ -1,6 +1,5 @@
/** @import { BlockStatement, CallExpression, Expression, ExpressionStatement, Identifier, Literal, MemberExpression, ObjectExpression, Pattern, Property, Statement, Super, TemplateElement, TemplateLiteral } from 'estree' */
/** @import { BindDirective } from '#compiler' */
/** @import { ComponentClientTransformState } from '../types' */
import {
extract_identifiers,
extract_paths,

@ -119,6 +119,7 @@ export function hydrate(component, options) {
options.intro = options.intro ?? false;
const target = options.target;
const was_hydrating = hydrating;
const previous_hydrate_node = hydrate_node;
try {
// Don't flush previous effects to ensure order of outer effects stays consistent
@ -175,6 +176,7 @@ export function hydrate(component, options) {
throw error;
} finally {
set_hydrating(was_hydrating);
set_hydrate_node(previous_hydrate_node);
reset_head_anchor();
}
}

@ -35,6 +35,7 @@ export interface RuntimeTest<Props extends Record<string, any> = Record<string,
ssrHtml?: string;
compileOptions?: Partial<CompileOptions>;
props?: Props;
server_props?: Props;
before_test?: () => void;
after_test?: () => void;
test?: (args: {
@ -256,7 +257,9 @@ async function run_test_variant(
config.before_test?.();
// ssr into target
const SsrSvelteComponent = (await import(`${cwd}/_output/server/main.svelte.js`)).default;
const { html, head } = render(SsrSvelteComponent, { props: config.props || {} });
const { html, head } = render(SsrSvelteComponent, {
props: config.server_props ?? config.props ?? {}
});
fs.writeFileSync(`${cwd}/_output/rendered.html`, html);
target.innerHTML = html;

@ -0,0 +1,7 @@
<script>
let count = $state(0);
</script>
<button onclick={() => (count += 1)}>
clicks: {count}
</button>

@ -0,0 +1,21 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
export default test({
props: {
browser: true
},
server_props: {
browser: false
},
html: `<div><button>clicks: 0</button></div>`,
test({ target, assert }) {
const button = target.querySelector('button');
flushSync(() => button?.click());
assert.htmlEqual(target.innerHTML, `<div><button>clicks: 1</button></div>`);
}
});

@ -0,0 +1,20 @@
<script>
import { createRawSnippet, hydrate } from 'svelte';
import { render } from 'svelte/server';
import Child from './Child.svelte';
let { browser } = $props();
let count = $state(0);
const hello = createRawSnippet((count) => ({
render: () => `
<div>${browser ? '' : render(Child).body}</div>
`,
setup(target) {
hydrate(Child, { target })
}
}));
</script>
{@render hello()}

@ -0,0 +1,8 @@
import { test } from '../../test';
export default test({
compileOptions: {
dev: true
},
runtime_error: 'invalid_default_snippet'
});

@ -0,0 +1,5 @@
<script>
let { children: x } = $props();
</script>
{@render x(true)}

@ -0,0 +1,7 @@
<script>
import Inner from './inner.svelte';
</script>
<Inner let:foo>
{foo}
</Inner>

@ -18,7 +18,7 @@ import App from './App.svelte'
export default app;
```
`mount` and `hydrate` have the exact same API. The difference is that `hydrate` will pick up the Svelte's server-rendered HTML inside its target and hydrate it. Both return an object with the exports of the component and potentially property accessors (if compiled with `accesors: true`). They do not come with the `$on`, `$set` and `$destroy` methods you may know from the class component API. These are its replacements:
`mount` and `hydrate` have the exact same API. The difference is that `hydrate` will pick up the Svelte's server-rendered HTML inside its target and hydrate it. Both return an object with the exports of the component and potentially property accessors (if compiled with `accessors: true`). They do not come with the `$on`, `$set` and `$destroy` methods you may know from the class component API. These are its replacements:
For `$on`, instead of listening to events, pass them via the `events` property on the options argument.
@ -99,7 +99,7 @@ In Svelte 4, rendering a component to a string also returned the CSS of all comp
### Component typing changes
The change from classes towards functions is also reflected in the typings: `SvelteComponent`, the base class from Svelte 4, is deprecated in favor of the new `Component` type which defines the function shape of a Svelte component. To manually define a component shape in a `d.ts` file:
The change from classes towards functions is also reflected in the typings: `SvelteComponent`, the base class from Svelte 4, is deprecated in favour of the new `Component` type which defines the function shape of a Svelte component. To manually define a component shape in a `d.ts` file:
```ts
import type { Component } from 'svelte';

Loading…
Cancel
Save