Skip to content

feat: make render options optional #12111

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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/famous-chairs-notice.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

feat: make `render` options optional
2 changes: 1 addition & 1 deletion packages/svelte/scripts/generate-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ await createBundle({
[`${pkg.name}/legacy`]: `${dir}/src/legacy/legacy-client.js`,
[`${pkg.name}/motion`]: `${dir}/src/motion/public.d.ts`,
[`${pkg.name}/reactivity`]: `${dir}/src/reactivity/index-client.js`,
[`${pkg.name}/server`]: `${dir}/src/server/index.js`,
[`${pkg.name}/server`]: `${dir}/src/server/index.d.ts`,
[`${pkg.name}/store`]: `${dir}/src/store/public.d.ts`,
[`${pkg.name}/transition`]: `${dir}/src/transition/public.d.ts`,
[`${pkg.name}/events`]: `${dir}/src/events/index.js`,
Expand Down
18 changes: 16 additions & 2 deletions packages/svelte/src/internal/client/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,20 @@ export function slot(anchor, slot_fn, slot_props, fallback_fn) {
* @template {Record<string, any>} Props
* @template {Record<string, any>} Exports
* @param {import('../../index.js').ComponentType<import('../../index.js').SvelteComponent<Props>> | import('../../index.js').Component<Props, Exports, any>} component
* @param {{
* @param {{} extends Props ? {
* target: Document | Element | ShadowRoot;
* anchor?: Node;
* props?: Props;
* events?: Record<string, (e: any) => any>;
* context?: Map<any, any>;
* intro?: boolean;
* }: {
* target: Document | Element | ShadowRoot;
* props: Props;
* anchor?: Node;
* events?: Record<string, (e: any) => any>;
* context?: Map<any, any>;
* intro?: boolean;
* }} options
* @returns {Exports}
*/
Expand All @@ -98,13 +105,20 @@ export function mount(component, options) {
* @template {Record<string, any>} Props
* @template {Record<string, any>} Exports
* @param {import('../../index.js').ComponentType<import('../../index.js').SvelteComponent<Props>> | import('../../index.js').Component<Props, Exports, any>} component
* @param {{
* @param {{} extends Props ? {
* target: Document | Element | ShadowRoot;
* props?: Props;
* events?: Record<string, (e: any) => any>;
* context?: Map<any, any>;
* intro?: boolean;
* recover?: boolean;
* } : {
* target: Document | Element | ShadowRoot;
* props: Props;
* events?: Record<string, (e: any) => any>;
* context?: Map<any, any>;
* intro?: boolean;
* recover?: boolean;
* }} options
* @returns {Exports}
*/
Expand Down
4 changes: 2 additions & 2 deletions packages/svelte/src/internal/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,10 @@ export let on_destroy = [];
* Takes a component and returns an object with `body` and `head` properties on it, which you can use to populate the HTML when server-rendering your app.
* @template {Record<string, any>} Props
* @param {import('svelte').Component<Props> | import('svelte').ComponentType<import('svelte').SvelteComponent<Props>>} component
* @param {{ props: Omit<Props, '$$slots' | '$$events'>; context?: Map<any, any> }} options
* @param {{ props?: Omit<Props, '$$slots' | '$$events'>; context?: Map<any, any> }} [options]
* @returns {import('#server').RenderOutput}
*/
export function render(component, options) {
export function render(component, options = {}) {
const payload = create_payload();

const prev_on_destroy = on_destroy;
Expand Down
21 changes: 21 additions & 0 deletions packages/svelte/src/server/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { RenderOutput } from '#server';
import type { ComponentProps, Component, SvelteComponent, ComponentType } from 'svelte';

/**
* Only available on the server and when compiling with the `server` option.
* Takes a component and returns an object with `body` and `head` properties on it, which you can use to populate the HTML when server-rendering your app.
*/
export function render<
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

had to move this into a d.ts file - JSDoc was too limiting to properly type this without type errors

Comp extends SvelteComponent<any> | Component<any>,
Props extends ComponentProps<Comp> = ComponentProps<Comp>
>(
...args: {} extends Props
? [
component: Comp extends SvelteComponent<any> ? ComponentType<Comp> : Comp,
options?: { props?: Omit<Props, '$$slots' | '$$events'>; context?: Map<any, any> }
]
: [
component: Comp extends SvelteComponent<any> ? ComponentType<Comp> : Comp,
options: { props: Omit<Props, '$$slots' | '$$events'>; context?: Map<any, any> }
]
): RenderOutput;
53 changes: 51 additions & 2 deletions packages/svelte/tests/types/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,13 @@ mount(NewComponent, {
intro: false,
recover: false
});
mount(
NewComponent,
// @ts-expect-error props missing
{ target: null as any }
);
// if component receives no args, props can be omitted
mount(null as any as typeof SvelteComponent<{}>, { target: null as any });

hydrate(NewComponent, {
target: null as any as Document | Element | ShadowRoot,
Expand All @@ -148,6 +155,13 @@ hydrate(NewComponent, {
intro: false,
recover: false
});
hydrate(
NewComponent,
// @ts-expect-error props missing
{ target: null as any }
);
// if component receives no args, props can be omitted
hydrate(null as any as typeof SvelteComponent<{}>, { target: null as any });

render(NewComponent, {
props: {
Expand All @@ -156,6 +170,14 @@ render(NewComponent, {
x: ''
}
});
// @ts-expect-error
render(NewComponent);
render(NewComponent, {
props: {
// @ts-expect-error
prop: 1
}
});

// --------------------------------------------------------------------------- interop

Expand Down Expand Up @@ -255,6 +277,13 @@ mount(functionComponent, {
readonly: 1
}
});
mount(
functionComponent,
// @ts-expect-error props missing
{ target: null as any }
);
// if component receives no args, props can be omitted
mount(null as any as Component<{}>, { target: null as any });

hydrate(functionComponent, {
target: null as any as Document | Element | ShadowRoot,
Expand All @@ -272,13 +301,33 @@ hydrate(functionComponent, {
binding: true
}
});
hydrate(
functionComponent,
// @ts-expect-error props missing
{ target: null as any }
);
// if component receives no args, props can be omitted
hydrate(null as any as Component<{}>, { target: null as any });

render(functionComponent, {
props: {
binding: true,
readonly: 'foo',
readonly: 'foo'
}
});
// @ts-expect-error
render(functionComponent);
render(functionComponent, {
// @ts-expect-error
props: {
binding: true
}
});
render(functionComponent, {
props: {
binding: true,
// @ts-expect-error
x: ''
readonly: 1
}
});

Expand Down
2 changes: 1 addition & 1 deletion packages/svelte/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"svelte/internal/client": ["./src/internal/client/index.js"],
"svelte/legacy": ["./src/legacy/legacy-client.js"],
"svelte/motion": ["./src/motion/public.d.ts"],
"svelte/server": ["./src/server/index.js"],
"svelte/server": ["./src/server/index.d.ts"],
"svelte/store": ["./src/store/public.d.ts"],
"#compiler": ["./src/compiler/types/index.d.ts"],
"#client": ["./src/internal/client/types.d.ts"],
Expand Down
39 changes: 32 additions & 7 deletions packages/svelte/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,25 +350,39 @@ declare module 'svelte' {
* Mounts a component to the given target and returns the exports and potentially the props (if compiled with `accessors: true`) of the component
*
* */
export function mount<Props extends Record<string, any>, Exports extends Record<string, any>>(component: ComponentType<SvelteComponent<Props, any, any>> | Component<Props, Exports, any>, options: {
export function mount<Props extends Record<string, any>, Exports extends Record<string, any>>(component: ComponentType<SvelteComponent<Props, any, any>> | Component<Props, Exports, any>, options: {} extends Props ? {
target: Document | Element | ShadowRoot;
anchor?: Node | undefined;
props?: Props | undefined;
events?: Record<string, (e: any) => any> | undefined;
context?: Map<any, any> | undefined;
intro?: boolean | undefined;
} : {
target: Document | Element | ShadowRoot;
props: Props;
anchor?: Node | undefined;
events?: Record<string, (e: any) => any> | undefined;
context?: Map<any, any> | undefined;
intro?: boolean | undefined;
}): Exports;
/**
* Hydrates a component on the given target and returns the exports and potentially the props (if compiled with `accessors: true`) of the component
*
* */
export function hydrate<Props extends Record<string, any>, Exports extends Record<string, any>>(component: ComponentType<SvelteComponent<Props, any, any>> | Component<Props, Exports, any>, options: {
export function hydrate<Props extends Record<string, any>, Exports extends Record<string, any>>(component: ComponentType<SvelteComponent<Props, any, any>> | Component<Props, Exports, any>, options: {} extends Props ? {
target: Document | Element | ShadowRoot;
props?: Props | undefined;
events?: Record<string, (e: any) => any> | undefined;
context?: Map<any, any> | undefined;
intro?: boolean | undefined;
recover?: boolean | undefined;
} : {
target: Document | Element | ShadowRoot;
props: Props;
events?: Record<string, (e: any) => any> | undefined;
context?: Map<any, any> | undefined;
intro?: boolean | undefined;
recover?: boolean | undefined;
}): Exports;
/**
* Unmounts a component that was previously mounted using `mount` or `hydrate`.
Expand Down Expand Up @@ -2110,14 +2124,25 @@ declare module 'svelte/reactivity' {
}

declare module 'svelte/server' {
import type { ComponentProps, Component, SvelteComponent, ComponentType } from 'svelte';
/**
* Only available on the server and when compiling with the `server` option.
* Takes a component and returns an object with `body` and `head` properties on it, which you can use to populate the HTML when server-rendering your app.
* */
export function render<Props extends Record<string, any>>(component: import("svelte").Component<Props, any, string> | import("svelte").ComponentType<import("svelte").SvelteComponent<Props, any, any>>, options: {
props: Omit<Props, "$$slots" | "$$events">;
context?: Map<any, any> | undefined;
}): RenderOutput;
*/
export function render<
Comp extends SvelteComponent<any> | Component<any>,
Props extends ComponentProps<Comp> = ComponentProps<Comp>
>(
...args: {} extends Props
? [
component: Comp extends SvelteComponent<any> ? ComponentType<Comp> : Comp,
options?: { props?: Omit<Props, '$$slots' | '$$events'>; context?: Map<any, any> }
]
: [
component: Comp extends SvelteComponent<any> ? ComponentType<Comp> : Comp,
options: { props: Omit<Props, '$$slots' | '$$events'>; context?: Map<any, any> }
]
): RenderOutput;
interface RenderOutput {
/** HTML that goes into the `<head>` */
head: string;
Expand Down
4 changes: 1 addition & 3 deletions playgrounds/demo/src/entry-server.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// @ts-ignore
import { render } from 'svelte/server';
// @ts-ignore you need to create this file
import App from './App.svelte';

// @ts-ignore
export const { head, body, css } = render(App, { props: { initialCount: 0 } });
export const { head, body } = render(App);
Loading