UNPKG

ripple

Version:

Ripple is an elegant TypeScript UI framework

66 lines (56 loc) • 1.99 kB
import { render } from './blocks.js'; import { DETACHED_BLOCK, HEAD_BLOCK } from './constants.js'; import { COMMENT_NODE } from '../../../constants.js'; import { create_text, get_first_child, get_next_sibling } from './operations.js'; import { hydrate_node, hydrating, set_hydrate_node, set_hydrating, set_hydration, } from './hydration.js'; import { HYDRATION } from 'ripple/internal/client/hydration-enabled'; /** * @param {string} hash * @param {(anchor: Node) => void} render_fn * @returns {void} */ export function head(hash, 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 = HYDRATION && hydrating; /** @type {Comment | Text} */ var anchor; if (HYDRATION && hydrating) { previous_hydrate_node = hydrate_node; var head_anchor = get_first_child(document.head); // There might be multiple head blocks in our app, and they could have been // rendered in an arbitrary order — find one corresponding to this component while ( head_anchor !== null && (head_anchor.nodeType !== COMMENT_NODE || /** @type {Comment} */ (head_anchor).data !== hash) ) { head_anchor = 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 { var start = get_next_sibling(head_anchor); /** @type {ChildNode} */ (head_anchor).remove(); // in case this component is repeated set_hydrate_node(start); } } if (!(HYDRATION && hydrating)) { anchor = document.head.appendChild(create_text()); } try { render(() => render_fn(anchor), null, HEAD_BLOCK | DETACHED_BLOCK); } finally { if (was_hydrating) { set_hydration(true, previous_hydrate_node); } } }