All files / src/internal/client/dom/blocks svelte-head.js

100% Statements 72/72
100% Branches 10/10
100% Functions 2/2
100% Lines 67/67

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 682x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 1219x 1219x 2x 2x 2x 2x 2x 2x 33x 33x 33x 33x 33x 33x 33x 33x 33x 17x 17x 17x 17x 16x 16x 17x 17x 17x 17x 17x 1x 1x 17x 17x 17x 17x 1x 17x 16x 16x 17x 33x 33x 17x 17x 33x 33x 33x 33x 33x 17x 17x 17x 17x 33x 33x  
/** @import { TemplateNode } from '#client' */
import { hydrate_node, hydrating, set_hydrate_node, set_hydrating } from '../hydration.js';
import { create_text, get_first_child, get_next_sibling } from '../operations.js';
import { block } from '../../reactivity/effects.js';
import { HEAD_EFFECT } from '../../constants.js';
import { HYDRATION_START } from '../../../../constants.js';
 
/**
 * @type {Node | undefined}
 */
let head_anchor;
 
export function reset_head_anchor() {
	head_anchor = undefined;
}
 
/**
 * @param {(anchor: Node) => void} render_fn
 * @returns {void}
 */
export function head(render_fn) {
	// 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 previous_hydrate_node = null;
	let was_hydrating = hydrating;
 
	/** @type {Comment | Text} */
	var anchor;
 
	if (hydrating) {
		previous_hydrate_node = hydrate_node;
 
		// There might be multiple head blocks in our app, so we need to account for each one needing independent hydration.
		if (head_anchor === undefined) {
			head_anchor = /** @type {TemplateNode} */ (get_first_child(document.head));
		}
 
		while (
			head_anchor !== null &&
			(head_anchor.nodeType !== 8 || /** @type {Comment} */ (head_anchor).data !== HYDRATION_START)
		) {
			head_anchor = /** @type {TemplateNode} */ (get_next_sibling(head_anchor));
		}
 
		// If we can't find an opening hydration marker, skip hydration (this can happen
		// if a framework rendered body but not head content)
		if (head_anchor === null) {
			set_hydrating(false);
		} else {
			head_anchor = set_hydrate_node(/** @type {TemplateNode} */ (get_next_sibling(head_anchor)));
		}
	}
 
	if (!hydrating) {
		anchor = document.head.appendChild(create_text());
	}
 
	try {
		block(() => render_fn(anchor), HEAD_EFFECT);
	} finally {
		if (was_hydrating) {
			set_hydrating(true);
			head_anchor = hydrate_node; // so that next head block starts from the correct node
			set_hydrate_node(/** @type {TemplateNode} */ (previous_hydrate_node));
		}
	}
}