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

100% Statements 72/72
100% Branches 11/11
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 1554x 1554x 2x 2x 2x 2x 2x 2x 39x 39x 39x 39x 39x 39x 39x 39x 39x 19x 19x 19x 19x 17x 17x 19x 19x 19x 20x 19x 2x 2x 19x 19x 19x 19x 1x 19x 18x 18x 19x 39x 39x 21x 21x 39x 39x 39x 39x 39x 19x 19x 19x 19x 39x 39x  
/** @import { TemplateNode } from '#client' */
import { hydrate_node, hydrating, set_hydrate_node, set_hydrating } from '../hydration.js';
import { empty } 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} */ (document.head.firstChild);
		}
 
		while (
			head_anchor !== null &&
			(head_anchor.nodeType !== 8 || /** @type {Comment} */ (head_anchor).data !== HYDRATION_START)
		) {
			head_anchor = /** @type {TemplateNode} */ (head_anchor.nextSibling);
		}
 
		// 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} */ (head_anchor.nextSibling));
		}
	}
 
	if (!hydrating) {
		anchor = document.head.appendChild(empty());
	}
 
	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));
		}
	}
}