chore: skip over static elements during CSR

pull/12855/head
Dominic Gannaway 2 years ago
parent 45da5a426f
commit f573ef6c17

@ -9,11 +9,11 @@ import { build_template_literal, build_update } from './utils.js';
* (e.g. `{a} b {c}`) into a single update function. Along the way it creates * (e.g. `{a} b {c}`) into a single update function. Along the way it creates
* corresponding template node references these updates are applied to. * corresponding template node references these updates are applied to.
* @param {SvelteNode[]} nodes * @param {SvelteNode[]} nodes
* @param {(is_text: boolean) => Expression} expression * @param {(is_text: boolean, is_last?: boolean) => Expression} expression
* @param {boolean} is_element * @param {boolean} is_element
* @param {ComponentContext} context * @param {ComponentContext} context
*/ */
export function process_children(nodes, expression, is_element, { visit, state }) { export function process_children(nodes, expression, is_element, { visit, state, path }) {
const within_bound_contenteditable = state.metadata.bound_contenteditable; const within_bound_contenteditable = state.metadata.bound_contenteditable;
/** @typedef {Array<Text | ExpressionTag>} Sequence */ /** @typedef {Array<Text | ExpressionTag>} Sequence */
@ -30,7 +30,14 @@ export function process_children(nodes, expression, is_element, { visit, state }
if (node.type === 'Text') { if (node.type === 'Text') {
let prev = expression; let prev = expression;
expression = () => b.call('$.sibling', prev(true)); expression = (_, is_last) =>
is_last
? b.conditional(
b.id('$.hydrating'),
b.call('$.sibling', prev(true)),
b.call('$.sibling_dangle', prev(true))
)
: b.call('$.sibling', prev(true));
state.template.push(node.raw); state.template.push(node.raw);
return; return;
} }
@ -108,14 +115,30 @@ export function process_children(nodes, expression, is_element, { visit, state }
node.metadata.is_controlled = true; node.metadata.is_controlled = true;
visit(node, state); visit(node, state);
} else { } else {
const is_last =
node.type === 'RegularElement' &&
path.at(-1)?.type === 'Fragment' &&
!node.fragment.metadata.dynamic &&
nodes.length - 1 === i;
const id = get_node_id( const id = get_node_id(
expression(false), expression(false, is_last),
state, state,
node.type === 'RegularElement' ? node.name : 'node' node.type === 'RegularElement' ? node.name : 'node'
); );
expression = (is_text) => expression = (is_text, is_last) => {
is_text ? b.call('$.sibling', id, b.true) : b.call('$.sibling', id); if (is_text) {
return is_text ? b.call('$.sibling', id, b.true) : b.call('$.sibling', id);
}
return is_last
? b.conditional(
b.id('$.hydrating'),
b.call('$.sibling', id),
b.call('$.sibling_dangle', id)
)
: b.call('$.sibling', id);
};
visit(node, { visit(node, {
...state, ...state,

@ -131,6 +131,16 @@ export function sibling(node, is_text = false) {
return /** @type {TemplateNode} */ (next_sibling); return /** @type {TemplateNode} */ (next_sibling);
} }
/**
* @template {Node} N
* @param {N} node
* @returns {Node | null}
*/
/*#__NO_SIDE_EFFECTS__*/
export function sibling_dangle(node) {
return node.nextSibling;
}
/** /**
* @template {Node} N * @template {Node} N
* @param {N} node * @param {N} node

@ -66,7 +66,7 @@ export {
bind_focused bind_focused
} from './dom/elements/bindings/universal.js'; } from './dom/elements/bindings/universal.js';
export { bind_window_scroll, bind_window_size } from './dom/elements/bindings/window.js'; export { bind_window_scroll, bind_window_size } from './dom/elements/bindings/window.js';
export { hydrate_template, next, reset } from './dom/hydration.js'; export { hydrate_template, next, reset, hydrating } from './dom/hydration.js';
export { export {
once, once,
preventDefault, preventDefault,
@ -156,6 +156,7 @@ export {
child, child,
first_child, first_child,
sibling, sibling,
sibling_dangle,
$window as window, $window as window,
$document as document $document as document
} from './dom/operations.js'; } from './dom/operations.js';

Loading…
Cancel
Save