diff options
Diffstat (limited to 'packages/integrations/svelte/server.js')
-rw-r--r-- | packages/integrations/svelte/server.js | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/packages/integrations/svelte/server.js b/packages/integrations/svelte/server.js new file mode 100644 index 000000000..ac133dced --- /dev/null +++ b/packages/integrations/svelte/server.js @@ -0,0 +1,61 @@ +import { createRawSnippet } from 'svelte'; +import { render } from 'svelte/server'; + +function check(Component) { + if (typeof Component !== 'function') return false; + // Svelte 5 generated components always accept a `$$payload` prop. + // This assumes that the SSR build does not minify it (which Astro enforces by default). + // This isn't the best check, but the only other option otherwise is to try to render the + // component, which is taxing. We'll leave it as a last resort for the future for now. + return Component.toString().includes('$$payload'); +} + +function needsHydration(metadata) { + // Adjust how this is hydrated only when the version of Astro supports `astroStaticSlot` + return metadata.astroStaticSlot ? !!metadata.hydrate : true; +} + +async function renderToStaticMarkup(Component, props, slotted, metadata) { + const tagName = needsHydration(metadata) ? 'astro-slot' : 'astro-static-slot'; + + 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; + children = createRawSnippet(() => ({ + render: () => `<${tagName}>${value}</${tagName}>`, + })); + } else { + $$slots[key] = createRawSnippet(() => ({ + render: () => `<${tagName} name="${key}">${value}</${tagName}>`, + })); + } + // @render support for Svelte ^5.0 + const slotName = key === 'default' ? 'children' : key; + renderProps[slotName] = createRawSnippet(() => ({ + render: () => `<${tagName}${key !== 'default' ? ` name="${key}"` : ''}>${value}</${tagName}>`, + })); + } + + const result = render(Component, { + props: { + ...props, + children, + $$slots, + ...renderProps, + }, + }); + return { html: result.body }; +} + +export default { + name: '@astrojs/svelte', + check, + renderToStaticMarkup, + supportsAstroStaticSlot: true, +}; |