diff --git a/.changeset/hot-tips-appear.md b/.changeset/hot-tips-appear.md new file mode 100644 index 0000000000..52a19c2632 --- /dev/null +++ b/.changeset/hot-tips-appear.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +feat: more efficient text-only fragments diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/Fragment.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/Fragment.js index e7312d15aa..a20e2d56b8 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/Fragment.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/Fragment.js @@ -128,6 +128,14 @@ export function Fragment(node, context) { } else if (is_single_child_not_needing_template) { context.visit(trimmed[0], state); body.push(...state.before_init, ...state.init); + } else if (trimmed.length === 1 && trimmed[0].type === 'Text') { + const id = b.id(context.state.scope.generate('text')); + body.push( + b.var(id, b.call('$.text', b.literal(trimmed[0].data))), + ...state.before_init, + ...state.init + ); + close = b.stmt(b.call('$.append', b.id('$$anchor'), id)); } else if (trimmed.length > 0) { const id = b.id(context.state.scope.generate('fragment')); diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js index 4625195f63..f05514a6a2 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js @@ -27,7 +27,12 @@ import { build_style_directives } from './shared/element.js'; import { process_children } from './shared/fragment.js'; -import { build_render_statement, build_update, build_update_assignment } from './shared/utils.js'; +import { + build_render_statement, + build_template_literal, + build_update, + build_update_assignment +} from './shared/utils.js'; import { visit_event_attribute } from './shared/events.js'; /** @@ -320,28 +325,43 @@ export function RegularElement(node, context) { context.visit(node, child_state); } - /** @type {Expression} */ - let arg = context.state.node; - - // If `hydrate_node` is set inside the element, we need to reset it - // after the element has been hydrated - let needs_reset = trimmed.some((node) => node.type !== 'Text'); + // special case — if an element that only contains text, we don't need + // to descend into it if the text is non-reactive + const text_content = + trimmed.every((node) => node.type === 'Text' || node.type === 'ExpressionTag') && + trimmed.some((node) => node.type === 'ExpressionTag') && + build_template_literal(trimmed, context.visit, child_state); - // The same applies if it's a `