fix: add `then` to class component `render` output (#16783)

* fix: add `then` to class component `render` output

* drive-by tidy up

* fix types
pull/16785/head
Rich Harris 2 days ago committed by GitHub
parent 037314a4c0
commit fc35d9fab8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: add `then` to class component `render` output

@ -1,5 +1,5 @@
/** @import { ComponentType, SvelteComponent, Component } from 'svelte' */ /** @import { ComponentType, SvelteComponent, Component } from 'svelte' */
/** @import { RenderOutput, SSRContext } from '#server' */ /** @import { RenderOutput } from '#server' */
/** @import { Store } from '#shared' */ /** @import { Store } from '#shared' */
/** @import { AccumulatedContent } from './payload.js' */ /** @import { AccumulatedContent } from './payload.js' */
export { FILENAME, HMR } from '../../constants.js'; export { FILENAME, HMR } from '../../constants.js';
@ -14,14 +14,10 @@ import {
} from '../../constants.js'; } from '../../constants.js';
import { escape_html } from '../../escaping.js'; import { escape_html } from '../../escaping.js';
import { DEV } from 'esm-env'; 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 { EMPTY_COMMENT, BLOCK_CLOSE, BLOCK_OPEN, BLOCK_OPEN_ELSE } from './hydration.js';
import { validate_store } from '../shared/validate.js'; import { validate_store } from '../shared/validate.js';
import { is_boolean_attribute, is_raw_text_element, is_void } from '../../utils.js'; import { is_boolean_attribute, is_raw_text_element, is_void } from '../../utils.js';
import { Payload, SSRState } from './payload.js'; import { Payload } from './payload.js';
import { abort } from './abort-signal.js';
import { async_mode_flag } from '../flags/index.js';
import * as e from './errors.js';
// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
// https://infra.spec.whatwg.org/#noncharacter // https://infra.spec.whatwg.org/#noncharacter

@ -1,11 +1,15 @@
/** @import { SvelteComponent } from '../index.js' */ /** @import { SvelteComponent } from '../index.js' */
import { asClassComponent as as_class_component, createClassComponent } from './legacy-client.js'; import { asClassComponent as as_class_component, createClassComponent } from './legacy-client.js';
import { render } from '../internal/server/index.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 // 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 }; 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. * Takes a Svelte 5 component and returns a Svelte 4 compatible component constructor.
* *
@ -21,15 +25,56 @@ export { createClassComponent };
*/ */
export function asClassComponent(component) { export function asClassComponent(component) {
const component_constructor = as_class_component(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 } = {}) => { const _render = (props, { context } = {}) => {
// @ts-expect-error the typings are off, but this will work if the component is compiled in SSR mode // @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 }); const result = render(component, { props, context });
return {
css: { code: '', map: null }, const munged = Object.defineProperties(
head: result.head, /** @type {LegacyRenderResult & PromiseLike<LegacyRenderResult>} */ ({}),
html: result.body {
}; 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 // @ts-expect-error this is present for SSR

Loading…
Cancel
Save