diff --git a/.changeset/shaggy-kids-juggle.md b/.changeset/shaggy-kids-juggle.md new file mode 100644 index 000000000000..ceb208dc4f40 --- /dev/null +++ b/.changeset/shaggy-kids-juggle.md @@ -0,0 +1,5 @@ +--- +'@astrojs/svelte': patch +--- + +Adds support for Svelte 5's new `@render` syntax while maintaining backward compatibility with traditional slots. diff --git a/packages/integrations/svelte/client-v5.js b/packages/integrations/svelte/client-v5.js index 7a046b5bfd08..f2cc647a2be6 100644 --- a/packages/integrations/svelte/client-v5.js +++ b/packages/integrations/svelte/client-v5.js @@ -8,7 +8,11 @@ export default (element) => { let children = undefined; let $$slots = undefined; + let renderFns = {}; + + for (const [key, value] of Object.entries(slotted)) { + // Legacy slot support $$slots ??= {}; if (key === 'default') { $$slots.default = true; @@ -20,6 +24,16 @@ export default (element) => { render: () => `${value}`, })); } + // @render support for Svelte ^5.0 + if (key === 'default') { + renderFns.children = createRawSnippet(() => ({ + render: () => `${value}` + })); + } else { + renderFns[key] = createRawSnippet(() => ({ + render: () => `${value}` + })); + } } const bootstrap = client !== 'only' ? hydrate : mount; @@ -28,6 +42,7 @@ export default (element) => { ...props, children, $$slots, + ...renderFns }); } else { const component = bootstrap(Component, { @@ -36,6 +51,7 @@ export default (element) => { ...props, children, $$slots, + ...renderFns }, }); existingApplications.set(element, component); diff --git a/packages/integrations/svelte/server-v5.js b/packages/integrations/svelte/server-v5.js index acffd10dfef0..932a52b1ff06 100644 --- a/packages/integrations/svelte/server-v5.js +++ b/packages/integrations/svelte/server-v5.js @@ -17,7 +17,10 @@ async function renderToStaticMarkup(Component, props, slotted, metadata) { let children = undefined; let $$slots = undefined; + const renderProps = {}; + for (const [key, value] of Object.entries(slotted)) { + // Legacy slot support $$slots ??= {}; if (key === 'default') { $$slots.default = true; @@ -29,6 +32,11 @@ async function renderToStaticMarkup(Component, props, slotted, metadata) { render: () => `<${tagName} name="${key}">${value}`, })); } + // @render support for Svelte ^5.0 + const slotName = key === 'default' ? 'children' : key; + renderProps[slotName] = createRawSnippet(() => ({ + render: () => `<${tagName}${key !== 'default' ? ` name="${key}"` : ''}>${value}` + })); } const result = render(Component, { @@ -36,6 +44,7 @@ async function renderToStaticMarkup(Component, props, slotted, metadata) { ...props, children, $$slots, + ...renderProps }, }); return { html: result.body };