diff --git a/packages/svelte/src/internal/client/block.js b/packages/svelte/src/internal/client/block.js index 19691f275e..8b20bed390 100644 --- a/packages/svelte/src/internal/client/block.js +++ b/packages/svelte/src/internal/client/block.js @@ -28,22 +28,6 @@ export function create_root_block(intro) { }; } -/** @returns {import('./types.js').HeadBlock} */ -export function create_head_block() { - return { - // dom - d: null, - // effect - e: null, - // parent - p: /** @type {import('./types.js').Block} */ (current_block), - // transition - r: null, - // type - t: HEAD_BLOCK - }; -} - /** @returns {import('./types.js').SnippetBlock} */ export function create_snippet_block() { return { diff --git a/packages/svelte/src/internal/client/dom/blocks/svelte-head.js b/packages/svelte/src/internal/client/dom/blocks/svelte-head.js new file mode 100644 index 0000000000..08b1c52471 --- /dev/null +++ b/packages/svelte/src/internal/client/dom/blocks/svelte-head.js @@ -0,0 +1,76 @@ +import { HEAD_BLOCK } from '../../constants.js'; +import { + current_hydration_fragment, + get_hydration_fragment, + hydrating, + set_current_hydration_fragment +} from '../../hydration.js'; +import { empty } from '../../operations.js'; +import { render_effect } from '../../reactivity/effects.js'; +import { remove } from '../../reconciler.js'; +import { current_block } from '../../runtime.js'; + +/** + * @param {(anchor: Node | null) => void} render_fn + * @returns {void} + */ +export function head(render_fn) { + /** @type {import('#client').HeadBlock} */ + const block = { + // dom + d: null, + // effect + e: null, + // parent + p: /** @type {import('#client').Block} */ (current_block), + // transition + r: null, + // type + t: HEAD_BLOCK + }; + + // The head function may be called after the first hydration pass and ssr comment nodes may still be present, + // therefore we need to skip that when we detect that we're not in hydration mode. + let hydration_fragment = null; + let previous_hydration_fragment = null; + + let is_hydrating = hydrating; + if (is_hydrating) { + hydration_fragment = get_hydration_fragment(document.head.firstChild); + previous_hydration_fragment = current_hydration_fragment; + set_current_hydration_fragment(hydration_fragment); + } + + try { + const head_effect = render_effect( + () => { + const current = block.d; + if (current !== null) { + remove(current); + block.d = null; + } + let anchor = null; + if (!hydrating) { + anchor = empty(); + document.head.appendChild(anchor); + } + render_fn(anchor); + }, + block, + false + ); + + head_effect.ondestroy = () => { + const current = block.d; + if (current !== null) { + remove(current); + } + }; + + block.e = head_effect; + } finally { + if (is_hydrating) { + set_current_hydration_fragment(previous_hydration_fragment); + } + } +} diff --git a/packages/svelte/src/internal/client/render.js b/packages/svelte/src/internal/client/render.js index 6daa89b271..6da29bdd39 100644 --- a/packages/svelte/src/internal/client/render.js +++ b/packages/svelte/src/internal/client/render.js @@ -10,7 +10,7 @@ import { map_set, set_class_name } from './operations.js'; -import { create_root_block, create_head_block, create_snippet_block } from './block.js'; +import { create_root_block, create_snippet_block } from './block.js'; import { PassiveDelegatedEvents, DelegatedEvents, @@ -1511,55 +1511,6 @@ export function slot(anchor_node, slot_fn, slot_props, fallback_fn) { } } -/** - * @param {(anchor: Node | null) => void} render_fn - * @returns {void} - */ -export function head(render_fn) { - const block = create_head_block(); - // The head function may be called after the first hydration pass and ssr comment nodes may still be present, - // therefore we need to skip that when we detect that we're not in hydration mode. - let hydration_fragment = null; - let previous_hydration_fragment = null; - let is_hydrating = hydrating; - if (is_hydrating) { - hydration_fragment = get_hydration_fragment(document.head.firstChild); - previous_hydration_fragment = current_hydration_fragment; - set_current_hydration_fragment(hydration_fragment); - } - - try { - const head_effect = render_effect( - () => { - const current = block.d; - if (current !== null) { - remove(current); - block.d = null; - } - let anchor = null; - if (!hydrating) { - anchor = empty(); - document.head.appendChild(anchor); - } - render_fn(anchor); - }, - block, - false - ); - head_effect.ondestroy = () => { - const current = block.d; - if (current !== null) { - remove(current); - } - }; - block.e = head_effect; - } finally { - if (is_hydrating) { - set_current_hydration_fragment(previous_hydration_fragment); - } - } -} - /** * @param {Element | Text | Comment} anchor * @param {boolean} is_html diff --git a/packages/svelte/src/internal/index.js b/packages/svelte/src/internal/index.js index ae90cfbdad..afc2336c16 100644 --- a/packages/svelte/src/internal/index.js +++ b/packages/svelte/src/internal/index.js @@ -27,6 +27,7 @@ export { key_block as key } from './client/dom/blocks/key.js'; export * from './client/dom/blocks/each.js'; export * from './client/dom/blocks/svelte-component.js'; export * from './client/dom/blocks/svelte-element.js'; +export * from './client/dom/blocks/svelte-head.js'; export * from './client/reactivity/deriveds.js'; export * from './client/reactivity/effects.js'; export * from './client/reactivity/sources.js';