diff --git a/.changeset/sixty-crabs-laugh.md b/.changeset/sixty-crabs-laugh.md new file mode 100644 index 0000000000..1780ddc166 --- /dev/null +++ b/.changeset/sixty-crabs-laugh.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: add `then` to class component `render` output diff --git a/packages/svelte/src/internal/server/index.js b/packages/svelte/src/internal/server/index.js index a2cf222da6..13a0706549 100644 --- a/packages/svelte/src/internal/server/index.js +++ b/packages/svelte/src/internal/server/index.js @@ -1,5 +1,5 @@ /** @import { ComponentType, SvelteComponent, Component } from 'svelte' */ -/** @import { RenderOutput, SSRContext } from '#server' */ +/** @import { RenderOutput } from '#server' */ /** @import { Store } from '#shared' */ /** @import { AccumulatedContent } from './payload.js' */ export { FILENAME, HMR } from '../../constants.js'; @@ -14,14 +14,10 @@ import { } from '../../constants.js'; import { escape_html } from '../../escaping.js'; import { DEV } from 'esm-env'; -import { ssr_context, pop, push, set_ssr_context } from './context.js'; import { EMPTY_COMMENT, BLOCK_CLOSE, BLOCK_OPEN, BLOCK_OPEN_ELSE } from './hydration.js'; import { validate_store } from '../shared/validate.js'; import { is_boolean_attribute, is_raw_text_element, is_void } from '../../utils.js'; -import { Payload, SSRState } from './payload.js'; -import { abort } from './abort-signal.js'; -import { async_mode_flag } from '../flags/index.js'; -import * as e from './errors.js'; +import { Payload } from './payload.js'; // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 // https://infra.spec.whatwg.org/#noncharacter diff --git a/packages/svelte/src/legacy/legacy-server.js b/packages/svelte/src/legacy/legacy-server.js index 92f8757d7a..b7d3e673bc 100644 --- a/packages/svelte/src/legacy/legacy-server.js +++ b/packages/svelte/src/legacy/legacy-server.js @@ -1,11 +1,15 @@ /** @import { SvelteComponent } from '../index.js' */ import { asClassComponent as as_class_component, createClassComponent } from './legacy-client.js'; import { render } from '../internal/server/index.js'; +import { async_mode_flag } from '../internal/flags/index.js'; +import * as w from '../internal/server/warnings.js'; // By having this as a separate entry point for server environments, we save the client bundle from having to include the server runtime export { createClassComponent }; +/** @typedef {{ head: string, html: string, css: { code: string, map: null }}} LegacyRenderResult */ + /** * Takes a Svelte 5 component and returns a Svelte 4 compatible component constructor. * @@ -21,15 +25,56 @@ export { createClassComponent }; */ export function asClassComponent(component) { const component_constructor = as_class_component(component); - /** @type {(props?: {}, opts?: { $$slots?: {}; context?: Map; }) => { html: any; css: { code: string; map: any; }; head: string; } } */ + /** @type {(props?: {}, opts?: { $$slots?: {}; context?: Map; }) => LegacyRenderResult & PromiseLike } */ const _render = (props, { context } = {}) => { // @ts-expect-error the typings are off, but this will work if the component is compiled in SSR mode const result = render(component, { props, context }); - return { - css: { code: '', map: null }, - head: result.head, - html: result.body - }; + + const munged = Object.defineProperties( + /** @type {LegacyRenderResult & PromiseLike} */ ({}), + { + css: { + value: { code: '', map: null } + }, + head: { + get: () => result.head + }, + html: { + get: () => result.body + }, + then: { + /** + * this is not type-safe, but honestly it's the best I can do right now, and it's a straightforward function. + * + * @template TResult1 + * @template [TResult2=never] + * @param { (value: LegacyRenderResult) => TResult1 } onfulfilled + * @param { (reason: unknown) => TResult2 } onrejected + */ + value: (onfulfilled, onrejected) => { + if (!async_mode_flag) { + w.experimental_async_ssr(); + const user_result = onfulfilled({ + css: munged.css, + head: munged.head, + html: munged.html + }); + return Promise.resolve(user_result); + } + + return result.then((result) => { + return onfulfilled({ + css: munged.css, + head: result.head, + html: result.body + }); + }, onrejected); + } + } + } + ); + + return munged; }; // @ts-expect-error this is present for SSR