Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/sixty-crabs-laugh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

fix: add `then` to class component `render` output
8 changes: 2 additions & 6 deletions packages/svelte/src/internal/server/index.js
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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
Expand Down
57 changes: 51 additions & 6 deletions packages/svelte/src/legacy/legacy-server.js
Original file line number Diff line number Diff line change
@@ -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.
*
Expand All @@ -21,15 +25,56 @@ export { createClassComponent };
*/
export function asClassComponent(component) {
const component_constructor = as_class_component(component);
/** @type {(props?: {}, opts?: { $$slots?: {}; context?: Map<any, any>; }) => { html: any; css: { code: string; map: any; }; head: string; } } */
/** @type {(props?: {}, opts?: { $$slots?: {}; context?: Map<any, any>; }) => LegacyRenderResult & PromiseLike<LegacyRenderResult> } */
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<LegacyRenderResult>} */ ({}),
{
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
Expand Down
Loading