diff --git a/.changeset/flat-jars-search.md b/.changeset/flat-jars-search.md new file mode 100644 index 0000000000..fc0de76f95 --- /dev/null +++ b/.changeset/flat-jars-search.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: memoize `clsx` calls 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 6122dc4e0e..9b3ecc922d 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 @@ -511,22 +511,21 @@ function setup_select_synchronization(value_binding, context) { /** * @param {AST.ClassDirective[]} class_directives * @param {ComponentContext} context - * @return {ObjectExpression} + * @return {ObjectExpression | Identifier} */ export function build_class_directives_object(class_directives, context) { let properties = []; + let has_call_or_state = false; for (const d of class_directives) { - let expression = /** @type Expression */ (context.visit(d.expression)); - - if (d.metadata.expression.has_call) { - expression = get_expression_id(context.state, expression); - } - + const expression = /** @type Expression */ (context.visit(d.expression)); properties.push(b.init(d.name, expression)); + has_call_or_state ||= d.metadata.expression.has_call || d.metadata.expression.has_state; } - return b.object(properties); + const directives = b.object(properties); + + return has_call_or_state ? get_expression_id(context.state, directives) : directives; } /** diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/element.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/element.js index e0eb04d823..084c1e7c67 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/element.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/element.js @@ -162,13 +162,13 @@ export function get_attribute_name(element, attribute) { * @param {boolean} is_html */ export function build_set_class(element, node_id, attribute, class_directives, context, is_html) { - let { value, has_state } = build_attribute_value(attribute.value, context, (value, metadata) => - metadata.has_call ? get_expression_id(context.state, value) : value - ); + let { value, has_state } = build_attribute_value(attribute.value, context, (value, metadata) => { + if (attribute.metadata.needs_clsx) { + value = b.call('$.clsx', value); + } - if (attribute && attribute.metadata.needs_clsx) { - value = b.call('$.clsx', value); - } + return metadata.has_call ? get_expression_id(context.state, value) : value; + }); /** @type {Identifier | undefined} */ let previous_id; @@ -176,7 +176,7 @@ export function build_set_class(element, node_id, attribute, class_directives, c /** @type {ObjectExpression | Identifier | undefined} */ let prev; - /** @type {ObjectExpression | undefined} */ + /** @type {ObjectExpression | Identifier | undefined} */ let next; if (class_directives.length) { diff --git a/packages/svelte/src/internal/client/dom/elements/class.js b/packages/svelte/src/internal/client/dom/elements/class.js index 7027c84f62..ecbfcbc010 100644 --- a/packages/svelte/src/internal/client/dom/elements/class.js +++ b/packages/svelte/src/internal/client/dom/elements/class.js @@ -33,7 +33,7 @@ export function set_class(dom, is_html, value, hash, prev_classes, next_classes) // @ts-expect-error need to add __className to patched prototype dom.__className = value; - } else if (next_classes) { + } else if (next_classes && prev_classes !== next_classes) { for (var key in next_classes) { var is_present = !!next_classes[key];