svelte
Version:
Cybernetically enhanced web apps
123 lines (102 loc) • 3.48 kB
JavaScript
/** @import { Effect, TemplateNode } from '#client' */
import { FILENAME, HYDRATION_ERROR } from '../../../../constants.js';
import { block, branch, destroy_effect } from '../../reactivity/effects.js';
import { hydrate_next, hydrate_node, hydrating, set_hydrate_node } from '../hydration.js';
import { create_fragment_from_html } from '../reconciler.js';
import { assign_nodes } from '../template.js';
import * as w from '../../warnings.js';
import { hash, sanitize_location } from '../../../../utils.js';
import { DEV } from 'esm-env';
import { dev_current_component_function } from '../../context.js';
import { get_first_child, get_next_sibling } from '../operations.js';
/**
* @param {Element} element
* @param {string | null} server_hash
* @param {string} value
*/
function check_hash(element, server_hash, value) {
if (!server_hash || server_hash === hash(String(value ?? ''))) return;
let location;
// @ts-expect-error
const loc = element.__svelte_meta?.loc;
if (loc) {
location = `near ${loc.file}:${loc.line}:${loc.column}`;
} else if (dev_current_component_function?.[FILENAME]) {
location = `in ${dev_current_component_function[FILENAME]}`;
}
w.hydration_html_changed(sanitize_location(location));
}
/**
* @param {Element | Text | Comment} node
* @param {() => string} get_value
* @param {boolean} svg
* @param {boolean} mathml
* @param {boolean} [skip_warning]
* @returns {void}
*/
export function html(node, get_value, svg, mathml, skip_warning) {
var anchor = node;
var value = '';
/** @type {Effect | undefined} */
var effect;
block(() => {
if (value === (value = get_value() ?? '')) {
if (hydrating) {
hydrate_next();
}
return;
}
if (effect !== undefined) {
destroy_effect(effect);
effect = undefined;
}
if (value === '') return;
effect = branch(() => {
if (hydrating) {
// We're deliberately not trying to repair mismatches between server and client,
// as it's costly and error-prone (and it's an edge case to have a mismatch anyway)
var hash = /** @type {Comment} */ (hydrate_node).data;
var next = hydrate_next();
var last = next;
while (
next !== null &&
(next.nodeType !== 8 || /** @type {Comment} */ (next).data !== '')
) {
last = next;
next = /** @type {TemplateNode} */ (get_next_sibling(next));
}
if (next === null) {
w.hydration_mismatch();
throw HYDRATION_ERROR;
}
if (DEV && !skip_warning) {
check_hash(/** @type {Element} */ (next.parentNode), hash, value);
}
assign_nodes(hydrate_node, last);
anchor = set_hydrate_node(next);
return;
}
var html = value + '';
if (svg) html = `<svg>${html}</svg>`;
else if (mathml) html = `<math>${html}</math>`;
// Don't use create_fragment_with_script_from_html here because that would mean script tags are executed.
// @html is basically `.innerHTML = ...` and that doesn't execute scripts either due to security reasons.
/** @type {DocumentFragment | Element} */
var node = create_fragment_from_html(html);
if (svg || mathml) {
node = /** @type {Element} */ (get_first_child(node));
}
assign_nodes(
/** @type {TemplateNode} */ (get_first_child(node)),
/** @type {TemplateNode} */ (node.lastChild)
);
if (svg || mathml) {
while (get_first_child(node)) {
anchor.before(/** @type {Node} */ (get_first_child(node)));
}
} else {
anchor.before(node);
}
});
});
}