pull/18466/merge
adiGuba 4 days ago committed by GitHub
commit 3e571bd518
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
distinct memoizer on style/class directives

@ -4,7 +4,6 @@
/** @import { Scope } from '../../../scope' */
import {
cannot_be_set_statically,
is_boolean_attribute,
is_dom_property,
is_load_error_element
} from '../../../../../utils.js';
@ -13,7 +12,6 @@ import { is_event_attribute, is_text_attribute } from '../../../../utils/ast.js'
import * as b from '#compiler/builders';
import {
create_attribute,
ExpressionMetadata,
is_custom_element_node,
is_customizable_select_element
} from '../../../nodes.js';
@ -528,18 +526,12 @@ export function build_class_directives_object(
) {
let properties = [];
const metadata = new ExpressionMetadata();
for (const d of class_directives) {
metadata.merge(d.metadata.expression);
const expression = /** @type Expression */ (context.visit(d.expression));
properties.push(b.init(d.name, expression));
properties.push(b.init(d.name, memoizer.add(expression, d.metadata.expression)));
}
const directives = b.object(properties);
return memoizer.add(directives, metadata);
return b.object(properties);
}
/**
@ -555,23 +547,17 @@ export function build_style_directives_object(
const normal = b.object([]);
const important = b.object([]);
const metadata = new ExpressionMetadata();
for (const d of style_directives) {
metadata.merge(d.metadata.expression);
const expression =
d.value === true
? build_getter(b.id(d.name), context.state)
: build_attribute_value(d.value, context).value;
const object = d.modifiers.includes('important') ? important : normal;
object.properties.push(b.init(d.name, expression));
object.properties.push(b.init(d.name, memoizer.add(expression, d.metadata.expression)));
}
const directives = important.properties.length ? b.array([normal, important]) : normal;
return memoizer.add(directives, metadata);
return important.properties.length ? b.array([normal, important]) : normal;
}
/**

@ -0,0 +1,38 @@
import { flushSync, tick } from 'svelte';
import { test } from '../../test';
// This test counts mutations on hydration
// set_style() should not mutate style on hydration, except if mismatch
export default test({
mode: ['server', 'hydrate', 'client'],
ssrHtml: `
<button>click</button>
<div class="red"></div>
`,
html: `
<button>click</button>
<div class="red"></div>
`,
async test({ target, assert, logs }) {
flushSync();
tick();
assert.deepEqual(logs, ['is_red()']);
const btn = target.querySelector('button');
const div = target.querySelector('div');
assert.equal(div?.className, 'red');
btn?.click();
flushSync();
assert.equal(div?.className, 'red active');
// only one call here
assert.deepEqual(logs, ['is_red()']);
}
});

@ -0,0 +1,10 @@
<script>
function is_red() {
console.log("is_red()");
return "red";
}
let active = $state(false);
</script>
<button onclick={() => active = true}>click</button>
<div class:red={is_red()} class:active></div>

@ -0,0 +1,43 @@
import { flushSync, tick } from 'svelte';
import { test } from '../../test';
// This test counts mutations on hydration
// set_style() should not mutate style on hydration, except if mismatch
export default test({
mode: ['server', 'hydrate', 'client'],
ssrHtml: `
<button>click</button>
<div style="background-color: red; font-size: 1em;"></div>
`,
html: `
<button>click</button>
<div style="background-color: red; font-size: 1em;"></div>
`,
async test({ target, assert, component, logs }) {
flushSync();
tick();
assert.deepEqual(logs, ['makeColor()']);
const btn = target.querySelector('button');
const div = target.querySelector('div');
// Note : we cannot compare HTML because set_style() use dom.style.cssText
// which can alter the format of the attribute...
assert.equal(div?.style.backgroundColor, 'red');
assert.equal(div?.style.fontSize, '1em');
btn?.click();
flushSync();
assert.equal(div?.style.backgroundColor, 'red');
assert.equal(div?.style.fontSize, '2em');
// only one call here
assert.deepEqual(logs, ['makeColor()']);
}
});

@ -0,0 +1,10 @@
<script>
function makeColor() {
console.log("makeColor()");
return "red";
}
let size = $state('1em');
</script>
<button onclick={() => size = '2em'}>click</button>
<div style:background-color={makeColor()} style:font-size={size}></div>
Loading…
Cancel
Save