Skip to content

Commit fc35d9f

Browse files
authored
fix: add then to class component render output (#16783)
* fix: add `then` to class component `render` output * drive-by tidy up * fix types
1 parent 037314a commit fc35d9f

File tree

3 files changed

+58
-12
lines changed

3 files changed

+58
-12
lines changed

.changeset/sixty-crabs-laugh.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: add `then` to class component `render` output

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

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/** @import { ComponentType, SvelteComponent, Component } from 'svelte' */
2-
/** @import { RenderOutput, SSRContext } from '#server' */
2+
/** @import { RenderOutput } from '#server' */
33
/** @import { Store } from '#shared' */
44
/** @import { AccumulatedContent } from './payload.js' */
55
export { FILENAME, HMR } from '../../constants.js';
@@ -14,14 +14,10 @@ import {
1414
} from '../../constants.js';
1515
import { escape_html } from '../../escaping.js';
1616
import { DEV } from 'esm-env';
17-
import { ssr_context, pop, push, set_ssr_context } from './context.js';
1817
import { EMPTY_COMMENT, BLOCK_CLOSE, BLOCK_OPEN, BLOCK_OPEN_ELSE } from './hydration.js';
1918
import { validate_store } from '../shared/validate.js';
2019
import { is_boolean_attribute, is_raw_text_element, is_void } from '../../utils.js';
21-
import { Payload, SSRState } from './payload.js';
22-
import { abort } from './abort-signal.js';
23-
import { async_mode_flag } from '../flags/index.js';
24-
import * as e from './errors.js';
20+
import { Payload } from './payload.js';
2521

2622
// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
2723
// https://infra.spec.whatwg.org/#noncharacter

packages/svelte/src/legacy/legacy-server.js

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
/** @import { SvelteComponent } from '../index.js' */
22
import { asClassComponent as as_class_component, createClassComponent } from './legacy-client.js';
33
import { render } from '../internal/server/index.js';
4+
import { async_mode_flag } from '../internal/flags/index.js';
5+
import * as w from '../internal/server/warnings.js';
46

57
// By having this as a separate entry point for server environments, we save the client bundle from having to include the server runtime
68

79
export { createClassComponent };
810

11+
/** @typedef {{ head: string, html: string, css: { code: string, map: null }}} LegacyRenderResult */
12+
913
/**
1014
* Takes a Svelte 5 component and returns a Svelte 4 compatible component constructor.
1115
*
@@ -21,15 +25,56 @@ export { createClassComponent };
2125
*/
2226
export function asClassComponent(component) {
2327
const component_constructor = as_class_component(component);
24-
/** @type {(props?: {}, opts?: { $$slots?: {}; context?: Map<any, any>; }) => { html: any; css: { code: string; map: any; }; head: string; } } */
28+
/** @type {(props?: {}, opts?: { $$slots?: {}; context?: Map<any, any>; }) => LegacyRenderResult & PromiseLike<LegacyRenderResult> } */
2529
const _render = (props, { context } = {}) => {
2630
// @ts-expect-error the typings are off, but this will work if the component is compiled in SSR mode
2731
const result = render(component, { props, context });
28-
return {
29-
css: { code: '', map: null },
30-
head: result.head,
31-
html: result.body
32-
};
32+
33+
const munged = Object.defineProperties(
34+
/** @type {LegacyRenderResult & PromiseLike<LegacyRenderResult>} */ ({}),
35+
{
36+
css: {
37+
value: { code: '', map: null }
38+
},
39+
head: {
40+
get: () => result.head
41+
},
42+
html: {
43+
get: () => result.body
44+
},
45+
then: {
46+
/**
47+
* this is not type-safe, but honestly it's the best I can do right now, and it's a straightforward function.
48+
*
49+
* @template TResult1
50+
* @template [TResult2=never]
51+
* @param { (value: LegacyRenderResult) => TResult1 } onfulfilled
52+
* @param { (reason: unknown) => TResult2 } onrejected
53+
*/
54+
value: (onfulfilled, onrejected) => {
55+
if (!async_mode_flag) {
56+
w.experimental_async_ssr();
57+
const user_result = onfulfilled({
58+
css: munged.css,
59+
head: munged.head,
60+
html: munged.html
61+
});
62+
return Promise.resolve(user_result);
63+
}
64+
65+
return result.then((result) => {
66+
return onfulfilled({
67+
css: munged.css,
68+
head: result.head,
69+
html: result.body
70+
});
71+
}, onrejected);
72+
}
73+
}
74+
}
75+
);
76+
77+
return munged;
3378
};
3479

3580
// @ts-expect-error this is present for SSR

0 commit comments

Comments
 (0)