Skip to content

Commit 5f218b5

Browse files
authored
chore: improve $state.frozen performance in prod (#11852)
* chore: improve $state.frozen performance in prod * lint * feedback
1 parent f411f77 commit 5f218b5

File tree

4 files changed

+38
-13
lines changed

4 files changed

+38
-13
lines changed

.changeset/silver-sheep-knock.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte": patch
3+
---
4+
5+
chore: improve $state.frozen performance in prod

packages/svelte/src/internal/client/constants.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@ export const EFFECT_TRANSPARENT = 1 << 15;
1818
export const LEGACY_DERIVED_PROP = 1 << 16;
1919

2020
export const STATE_SYMBOL = Symbol('$state');
21+
export const STATE_FROZEN_SYMBOL = Symbol('$state.frozen');
2122
export const LOADING_ATTR_SYMBOL = Symbol('');

packages/svelte/src/internal/client/proxy.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,25 @@ import {
1818
} from './utils.js';
1919
import { check_ownership, widen_ownership } from './dev/ownership.js';
2020
import { mutable_source, source, set } from './reactivity/sources.js';
21-
import { STATE_SYMBOL } from './constants.js';
21+
import { STATE_FROZEN_SYMBOL, STATE_SYMBOL } from './constants.js';
2222
import { UNINITIALIZED } from '../../constants.js';
2323
import * as e from './errors.js';
2424

2525
/**
2626
* @template T
27-
* @param {T} value
27+
* @param {T} initial_value
2828
* @param {boolean} [immutable]
2929
* @param {import('#client').ProxyMetadata | null} [parent]
3030
* @param {import('#client').Source<T>} [prev] dev mode only
3131
* @returns {import('#client').ProxyStateObject<T> | T}
3232
*/
33-
export function proxy(value, immutable = true, parent = null, prev) {
34-
if (typeof value === 'object' && value != null && !is_frozen(value)) {
33+
export function proxy(initial_value, immutable = true, parent = null, prev) {
34+
if (typeof initial_value === 'object' && initial_value != null) {
35+
let value = initial_value;
36+
// If the object is frozen then snapshot the value
37+
if (is_frozen(value) || STATE_FROZEN_SYMBOL in value) {
38+
value = snapshot(value);
39+
}
3540
// If we have an existing proxy, return it...
3641
if (STATE_SYMBOL in value) {
3742
const metadata = /** @type {import('#client').ProxyMetadata<T>} */ (value[STATE_SYMBOL]);
@@ -94,7 +99,7 @@ export function proxy(value, immutable = true, parent = null, prev) {
9499
}
95100
}
96101

97-
return value;
102+
return initial_value;
98103
}
99104

100105
/**

packages/svelte/src/internal/client/runtime.js

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import { DEV } from 'esm-env';
2-
import { get_descriptors, get_prototype_of, is_frozen, object_freeze } from './utils.js';
2+
import {
3+
define_property,
4+
get_descriptors,
5+
get_prototype_of,
6+
is_frozen,
7+
object_freeze
8+
} from './utils.js';
39
import { snapshot } from './proxy.js';
410
import { destroy_effect, effect, execute_effect_teardown } from './reactivity/effects.js';
511
import {
@@ -17,7 +23,8 @@ import {
1723
BLOCK_EFFECT,
1824
ROOT_EFFECT,
1925
LEGACY_DERIVED_PROP,
20-
DISCONNECTED
26+
DISCONNECTED,
27+
STATE_FROZEN_SYMBOL
2128
} from './constants.js';
2229
import { flush_tasks } from './dom/task.js';
2330
import { add_owner } from './dev/ownership.js';
@@ -1353,19 +1360,26 @@ if (DEV) {
13531360
}
13541361

13551362
/**
1356-
* Expects a value that was wrapped with `freeze` and makes it frozen.
1363+
* Expects a value that was wrapped with `freeze` and makes it frozen in DEV.
13571364
* @template T
13581365
* @param {T} value
13591366
* @returns {Readonly<T>}
13601367
*/
13611368
export function freeze(value) {
1362-
if (typeof value === 'object' && value != null && !is_frozen(value)) {
1369+
if (typeof value === 'object' && value != null && !(STATE_FROZEN_SYMBOL in value)) {
13631370
// If the object is already proxified, then snapshot the value
1364-
if (STATE_SYMBOL in value) {
1365-
return object_freeze(snapshot(value));
1371+
if (STATE_SYMBOL in value || is_frozen(value)) {
1372+
value = snapshot(value);
1373+
}
1374+
define_property(value, STATE_FROZEN_SYMBOL, {
1375+
value: true,
1376+
writable: true,
1377+
enumerable: false
1378+
});
1379+
// Freeze the object in DEV
1380+
if (DEV) {
1381+
object_freeze(value);
13661382
}
1367-
// Otherwise freeze the object
1368-
object_freeze(value);
13691383
}
13701384
return value;
13711385
}

0 commit comments

Comments
 (0)