Skip to content

Commit 1e4c6a2

Browse files
committed
simpler createRawSnippet API
1 parent 40d1191 commit 1e4c6a2

File tree

13 files changed

+26
-148
lines changed

13 files changed

+26
-148
lines changed

packages/svelte/messages/client-errors/errors.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,6 @@
6060

6161
> The `%rune%` rune is only available inside `.svelte` and `.svelte.js/ts` files
6262
63-
## snippet_missing_mount
64-
65-
> Snippets created with `createRawSnippet(...)` and used on the client must specify a `mount` function
66-
6763
## state_prototype_fixed
6864

6965
> Cannot set prototype of `$state` object
Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
11
## lifecycle_function_unavailable
22

33
> `%name%(...)` is not available on the server
4-
5-
## snippet_missing_render
6-
7-
> Snippets created with `createRawSnippet(...)` and used on the server must specify a `render` function

packages/svelte/src/internal/client/dom/blocks/snippet.js

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/** @import { Effect, TemplateNode } from '#client' */
22
/** @import { Getters } from '#shared' */
3+
import { run } from '../../../shared/utils.js';
34
import { add_snippet_symbol } from '../../../shared/validate.js';
45
import { EFFECT_TRANSPARENT } from '../../constants.js';
56
import { branch, block, destroy_effect } from '../../reactivity/effects.js';
@@ -8,8 +9,8 @@ import {
89
set_dev_current_component_function
910
} from '../../runtime.js';
1011
import { hydrate_next, hydrate_node, hydrating } from '../hydration.js';
12+
import { create_fragment_from_html } from '../reconciler.js';
1113
import { assign_nodes } from '../template.js';
12-
import * as e from '../../errors.js';
1314

1415
/**
1516
* @template {(node: TemplateNode, ...args: any[]) => void} SnippetFn
@@ -65,20 +66,15 @@ export function wrap_snippet(component, fn) {
6566
}
6667

6768
/**
68-
* Create a snippet imperatively using mount, hydrate and render functions.
69+
* Create a snippet programmatically
6970
* @template {unknown[]} Params
7071
* @param {{
71-
* mount?: (...params: Getters<Params>) => Element,
72-
* hydrate?: (element: Element, ...params: Getters<Params>) => void,
73-
* render?: (...params: Params) => string
72+
* render: (...params: Params) => string
73+
* update?: (element: Element, ...params: Getters<Params>) => void,
7474
* }} options
7575
* @returns {import('svelte').Snippet<Params>}
7676
*/
77-
export function createRawSnippet({ mount, hydrate }) {
78-
if (mount === undefined) {
79-
e.snippet_missing_mount();
80-
}
81-
77+
export function createRawSnippet({ render, update }) {
8278
return add_snippet_symbol(
8379
(/** @type {TemplateNode} */ anchor, /** @type {Getters<Params>} */ ...params) => {
8480
/** @type {Element} */
@@ -87,17 +83,14 @@ export function createRawSnippet({ mount, hydrate }) {
8783
if (hydrating) {
8884
element = /** @type {Element} */ (hydrate_node);
8985
hydrate_next();
90-
91-
if (hydrate === undefined) {
92-
element.replaceWith((element = mount(...params)));
93-
} else {
94-
hydrate(element, ...params);
95-
}
9686
} else {
97-
element = mount(...params);
87+
var html = render(.../** @type {Params} */ (params.map(run)));
88+
var fragment = create_fragment_from_html(html);
89+
element = /** @type {Element} */ (fragment.firstChild);
9890
anchor.before(element);
9991
}
10092

93+
update?.(element, ...params);
10194
assign_nodes(element, element);
10295
}
10396
);

packages/svelte/src/internal/client/errors.js

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -262,22 +262,6 @@ export function rune_outside_svelte(rune) {
262262
}
263263
}
264264

265-
/**
266-
* Snippets created with `createRawSnippet(...)` and used on the client must specify a `mount` function
267-
* @returns {never}
268-
*/
269-
export function snippet_missing_mount() {
270-
if (DEV) {
271-
const error = new Error(`snippet_missing_mount\nSnippets created with \`createRawSnippet(...)\` and used on the client must specify a \`mount\` function`);
272-
273-
error.name = 'Svelte error';
274-
throw error;
275-
} else {
276-
// TODO print a link to the documentation
277-
throw new Error("snippet_missing_mount");
278-
}
279-
}
280-
281265
/**
282266
* Cannot set prototype of `$state` object
283267
* @returns {never}
Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,21 @@
1+
/** @import { Snippet } from 'svelte' */
12
/** @import { Payload } from '#server' */
3+
/** @import { Getters } from '#shared' */
24
import { add_snippet_symbol } from '../../shared/validate.js';
3-
import * as e from '../errors.js';
45

56
/**
6-
* Create a snippet imperatively using mount, hyrdate and render functions.
7+
* Create a snippet programmatically
8+
* @template {unknown[]} Params
79
* @param {{
8-
* mount?: (...params: any[]) => Element,
9-
* hydrate?: (element: Element, ...params: any[]) => void,
10-
* render?: (...params: any[]) => string
10+
* render: (...params: Params) => string
11+
* update?: (element: Element, ...params: Getters<Params>) => void,
1112
* }} options
13+
* @returns {Snippet<Params>}
1214
*/
1315
export function createRawSnippet({ render }) {
14-
if (render === undefined) {
15-
e.snippet_missing_render();
16-
}
17-
18-
const snippet_fn = (/** @type {Payload} */ payload, /** @type {any[]} */ ...args) => {
16+
const snippet_fn = (/** @type {Payload} */ payload, /** @type {Params} */ ...args) => {
1917
payload.out += render(...args);
2018
};
2119
add_snippet_symbol(snippet_fn);
22-
return snippet_fn;
20+
return /** @type {Snippet} */ (snippet_fn);
2321
}

packages/svelte/src/internal/server/errors.js

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,6 @@
88
export function lifecycle_function_unavailable(name) {
99
const error = new Error(`lifecycle_function_unavailable\n\`${name}(...)\` is not available on the server`);
1010

11-
error.name = 'Svelte error';
12-
throw error;
13-
}
14-
15-
/**
16-
* Snippets created with `createRawSnippet(...)` and used on the server must specify a `render` function
17-
* @returns {never}
18-
*/
19-
export function snippet_missing_render() {
20-
const error = new Error(`snippet_missing_render\nSnippets created with \`createRawSnippet(...)\` and used on the server must specify a \`render\` function`);
21-
2211
error.name = 'Svelte error';
2312
throw error;
2413
}

packages/svelte/tests/hydration/samples/snippet-raw-hydrate/main.svelte

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,11 @@
22
import { createRawSnippet } from 'svelte';
33
44
const snippet = createRawSnippet({
5-
mount() {
6-
const p = document.createElement('p');
7-
p.textContent = 'mounted';
8-
return p;
9-
},
10-
hydrate(p) {
11-
p.textContent = 'hydrated';
12-
},
135
render() {
146
return `<p>rendered</p>`;
7+
},
8+
update(p) {
9+
p.textContent = 'hydrated';
1510
}
1611
});
1712
</script>

packages/svelte/tests/hydration/samples/snippet-raw-mount/_config.js

Lines changed: 0 additions & 3 deletions
This file was deleted.

packages/svelte/tests/hydration/samples/snippet-raw-mount/_expected.html

Lines changed: 0 additions & 1 deletion
This file was deleted.

packages/svelte/tests/hydration/samples/snippet-raw-mount/main.svelte

Lines changed: 0 additions & 16 deletions
This file was deleted.

packages/svelte/tests/runtime-runes/samples/snippet-raw-args/_config.js

Lines changed: 0 additions & 17 deletions
This file was deleted.

packages/svelte/tests/runtime-runes/samples/snippet-raw-args/main.svelte

Lines changed: 0 additions & 32 deletions
This file was deleted.

packages/svelte/tests/runtime-runes/samples/snippet-raw/main.svelte

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,13 @@
44
let count = $state(0);
55
66
const hello = createRawSnippet({
7-
mount(count) {
8-
const p = document.createElement('p')
9-
7+
render(count) {
8+
return `<p>clicks: ${count}</p>`;
9+
},
10+
update(p, count) {
1011
$effect(() => {
1112
p.textContent = `clicks: ${count()}`
1213
});
13-
14-
return p;
15-
},
16-
render(count) {
17-
return `<p>clicks: ${count}</p>`;
1814
}
1915
});
2016
</script>

0 commit comments

Comments
 (0)