Skip to content

Commit ae615ae

Browse files
adigubaRich-Harris
andauthored
chore: memoize clsx() (alternative) (#15456)
* memoize clsx + directives * changeset * unused * tweak * tweak changeset --------- Co-authored-by: Rich Harris <rich.harris@vercel.com>
1 parent 30562b8 commit ae615ae

File tree

4 files changed

+20
-16
lines changed

4 files changed

+20
-16
lines changed

.changeset/flat-jars-search.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: memoize `clsx` calls

packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js

+7-8
Original file line numberDiff line numberDiff line change
@@ -511,22 +511,21 @@ function setup_select_synchronization(value_binding, context) {
511511
/**
512512
* @param {AST.ClassDirective[]} class_directives
513513
* @param {ComponentContext} context
514-
* @return {ObjectExpression}
514+
* @return {ObjectExpression | Identifier}
515515
*/
516516
export function build_class_directives_object(class_directives, context) {
517517
let properties = [];
518+
let has_call_or_state = false;
518519

519520
for (const d of class_directives) {
520-
let expression = /** @type Expression */ (context.visit(d.expression));
521-
522-
if (d.metadata.expression.has_call) {
523-
expression = get_expression_id(context.state, expression);
524-
}
525-
521+
const expression = /** @type Expression */ (context.visit(d.expression));
526522
properties.push(b.init(d.name, expression));
523+
has_call_or_state ||= d.metadata.expression.has_call || d.metadata.expression.has_state;
527524
}
528525

529-
return b.object(properties);
526+
const directives = b.object(properties);
527+
528+
return has_call_or_state ? get_expression_id(context.state, directives) : directives;
530529
}
531530

532531
/**

packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/element.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -162,21 +162,21 @@ export function get_attribute_name(element, attribute) {
162162
* @param {boolean} is_html
163163
*/
164164
export function build_set_class(element, node_id, attribute, class_directives, context, is_html) {
165-
let { value, has_state } = build_attribute_value(attribute.value, context, (value, metadata) =>
166-
metadata.has_call ? get_expression_id(context.state, value) : value
167-
);
165+
let { value, has_state } = build_attribute_value(attribute.value, context, (value, metadata) => {
166+
if (attribute.metadata.needs_clsx) {
167+
value = b.call('$.clsx', value);
168+
}
168169

169-
if (attribute && attribute.metadata.needs_clsx) {
170-
value = b.call('$.clsx', value);
171-
}
170+
return metadata.has_call ? get_expression_id(context.state, value) : value;
171+
});
172172

173173
/** @type {Identifier | undefined} */
174174
let previous_id;
175175

176176
/** @type {ObjectExpression | Identifier | undefined} */
177177
let prev;
178178

179-
/** @type {ObjectExpression | undefined} */
179+
/** @type {ObjectExpression | Identifier | undefined} */
180180
let next;
181181

182182
if (class_directives.length) {

packages/svelte/src/internal/client/dom/elements/class.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export function set_class(dom, is_html, value, hash, prev_classes, next_classes)
3333

3434
// @ts-expect-error need to add __className to patched prototype
3535
dom.__className = value;
36-
} else if (next_classes) {
36+
} else if (next_classes && prev_classes !== next_classes) {
3737
for (var key in next_classes) {
3838
var is_present = !!next_classes[key];
3939

0 commit comments

Comments
 (0)