diff --git a/packages/svelte/src/internal/server/dev.js b/packages/svelte/src/internal/server/dev.js
index 66dff0fde2..1211670f94 100644
--- a/packages/svelte/src/internal/server/dev.js
+++ b/packages/svelte/src/internal/server/dev.js
@@ -39,10 +39,7 @@ function print_error(renderer, message) {
// eslint-disable-next-line no-console
console.error(message);
- renderer.child(
- (renderer) => renderer.push(``),
- 'head'
- );
+ renderer.head((r) => r.push(``));
}
/**
diff --git a/packages/svelte/src/internal/server/index.js b/packages/svelte/src/internal/server/index.js
index 618e75f932..1e2d75d6dc 100644
--- a/packages/svelte/src/internal/server/index.js
+++ b/packages/svelte/src/internal/server/index.js
@@ -69,11 +69,11 @@ export function render(component, options = {}) {
* @returns {void}
*/
export function head(renderer, fn) {
- renderer.child((renderer) => {
+ renderer.head((renderer) => {
renderer.push(BLOCK_OPEN);
renderer.child(fn);
renderer.push(BLOCK_CLOSE);
- }, 'head');
+ });
}
/**
diff --git a/packages/svelte/src/internal/server/renderer.js b/packages/svelte/src/internal/server/renderer.js
index 26f7ac2b3c..21ae91fbb7 100644
--- a/packages/svelte/src/internal/server/renderer.js
+++ b/packages/svelte/src/internal/server/renderer.js
@@ -81,23 +81,33 @@ export class Renderer {
/**
* @param {SSRState} global
* @param {Renderer | undefined} [parent]
- * @param {RendererType} [type]
*/
- constructor(global, parent, type) {
+ constructor(global, parent) {
+ this.#parent = parent;
+
this.global = global;
this.local = parent ? { ...parent.local } : { select_value: undefined };
- this.#parent = parent;
- this.type = type ?? parent?.type ?? 'body';
+ this.type = parent ? parent.type : 'body';
+ }
+
+ /**
+ * @param {(renderer: Renderer) => void} fn
+ */
+ head(fn) {
+ const head = new Renderer(this.global, this);
+ head.type = 'head';
+
+ this.#out.push(head);
+ head.child(fn);
}
/**
* Create a child renderer. The child renderer inherits the state from the parent,
* but has its own content.
* @param {(renderer: Renderer) => MaybePromise} fn
- * @param {RendererType} [type]
*/
- child(fn, type) {
- const child = new Renderer(this.global, this, type);
+ child(fn) {
+ const child = new Renderer(this.global, this);
this.#out.push(child);
const parent = ssr_context;
@@ -184,7 +194,7 @@ export class Renderer {
* @deprecated this is needed for legacy component bindings
*/
copy() {
- const copy = new Renderer(this.global, this.#parent, this.type);
+ const copy = new Renderer(this.global, this.#parent);
copy.#out = this.#out.map((item) => (item instanceof Renderer ? item.copy() : item));
copy.promises = this.promises;
return copy;
@@ -457,7 +467,8 @@ export class Renderer {
static #push_accumulated_content(tree, accumulated_content) {
for (const [type, content] of Object.entries(accumulated_content)) {
if (!content) continue;
- const child = new Renderer(tree.global, tree, /** @type {RendererType} */ (type));
+ const child = new Renderer(tree.global, tree);
+ child.type = /** @type {RendererType} */ (type);
child.push(content);
tree.#out.push(child);
}
diff --git a/packages/svelte/src/internal/server/renderer.test.ts b/packages/svelte/src/internal/server/renderer.test.ts
index fb14654d5d..2b2bf14cf7 100644
--- a/packages/svelte/src/internal/server/renderer.test.ts
+++ b/packages/svelte/src/internal/server/renderer.test.ts
@@ -20,9 +20,9 @@ test('collects synchronous body content by default', () => {
test('child type switches content area (head vs body)', () => {
const component = (renderer: Renderer) => {
renderer.push('a');
- renderer.child(($$renderer) => {
+ renderer.head(($$renderer) => {
$$renderer.push('T');
- }, 'head');
+ });
renderer.push('b');
};
@@ -33,12 +33,12 @@ test('child type switches content area (head vs body)', () => {
test('child inherits parent type when not specified', () => {
const component = (renderer: Renderer) => {
- renderer.child((renderer) => {
+ renderer.head((renderer) => {
renderer.push('');
renderer.child((renderer) => {
renderer.push('');
});
- }, 'head');
+ });
};
const { head, body } = Renderer.render(component as unknown as Component);
@@ -118,7 +118,9 @@ test('local state is shallow-copied to children', () => {
});
test('subsume replaces tree content and state from other', () => {
- const a = new Renderer(new SSRState('async'), undefined, 'head');
+ const a = new Renderer(new SSRState('async'));
+ a.type = 'head';
+
a.push('');
a.local.select_value = 'A';
@@ -140,7 +142,9 @@ test('subsume replaces tree content and state from other', () => {
});
test('subsume refuses to switch modes', () => {
- const a = new Renderer(new SSRState('sync'), undefined, 'head');
+ const a = new Renderer(new SSRState('sync'));
+ a.type = 'head';
+
a.push('');
a.local.select_value = 'A';
@@ -273,12 +277,12 @@ describe('async', () => {
test('push async functions work with head content type', async () => {
const component = (renderer: Renderer) => {
- renderer.child(($$renderer) => {
+ renderer.head(($$renderer) => {
$$renderer.push(async () => {
await Promise.resolve();
return 'Async Title';
});
- }, 'head');
+ });
};
const { head, body } = await Renderer.render(component as unknown as Component);
diff --git a/packages/svelte/tests/server-side-rendering/samples/head-multiple-title/_config.js b/packages/svelte/tests/server-side-rendering/samples/head-multiple-title/_config.js
index 45054bbada..f47bee71df 100644
--- a/packages/svelte/tests/server-side-rendering/samples/head-multiple-title/_config.js
+++ b/packages/svelte/tests/server-side-rendering/samples/head-multiple-title/_config.js
@@ -1,5 +1,3 @@
import { test } from '../../test';
-export default test({
- props: { adjective: 'custom' }
-});
+export default test({});