Skip to content

Commit 1809747

Browse files
trueadmRich-Harris
andauthored
breaking: remove unstate(), replace with $state.snapshot rune (#11180)
* breaking: remove untrack(), replace with $state.clean rune * lol * update types * update types * undo * undo * rename to raw * rename to snapshot * fix * tweak docs, to make it explicitly that we're converting to and from proxies * remove vestiges * validation * tweak --------- Co-authored-by: Rich Harris <[email protected]>
1 parent cd7c3fe commit 1809747

File tree

20 files changed

+117
-59
lines changed

20 files changed

+117
-59
lines changed

.changeset/clever-sloths-push.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+
breaking: remove unstate(), replace with $state.snapshot rune

packages/svelte/src/ambient.d.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,26 @@ declare namespace $state {
4242
*/
4343
export function frozen<T>(initial: T): Readonly<T>;
4444
export function frozen<T>(): Readonly<T> | undefined;
45+
/**
46+
* To take a static snapshot of a deeply reactive `$state` proxy, use `$state.snapshot`:
47+
*
48+
* Example:
49+
* ```ts
50+
* <script>
51+
* let counter = $state({ count: 0 });
52+
*
53+
* function onclick() {
54+
* // Will log `{ count: ... }` rather than `Proxy { ... }`
55+
* console.log($state.snapshot(counter));
56+
* };
57+
* </script>
58+
* ```
59+
*
60+
* https://svelte-5-preview.vercel.app/docs/runes#$state.snapshot
61+
*
62+
* @param state The value to snapshot
63+
*/
64+
export function snapshot<T>(state: T): T;
4565
}
4666

4767
/**

packages/svelte/src/compiler/phases/2-analyze/validation.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,12 @@ function validate_call_expression(node, scope, path) {
865865
error(node, 'invalid-rune-args-length', rune, [1]);
866866
}
867867
}
868+
869+
if (rune === '$state.snapshot') {
870+
if (node.arguments.length !== 1) {
871+
error(node, 'invalid-rune-args-length', rune, [1]);
872+
}
873+
}
868874
}
869875

870876
/**

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,13 @@ export const javascript_visitors_runes = {
388388
return b.call('$.effect_active');
389389
}
390390

391+
if (rune === '$state.snapshot') {
392+
return b.call(
393+
'$.snapshot',
394+
/** @type {import('estree').Expression} */ (context.visit(node.arguments[0]))
395+
);
396+
}
397+
391398
if (rune === '$effect.root') {
392399
const args = /** @type {import('estree').Expression[]} */ (
393400
node.arguments.map((arg) => context.visit(arg))

packages/svelte/src/compiler/phases/3-transform/server/transform-server.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,10 @@ const javascript_visitors_runes = {
794794
return b.literal(false);
795795
}
796796

797+
if (rune === '$state.snapshot') {
798+
return /** @type {import('estree').Expression} */ (context.visit(node.arguments[0]));
799+
}
800+
797801
if (rune === '$inspect' || rune === '$inspect().with') {
798802
return transform_inspect_rune(node, context);
799803
}

packages/svelte/src/compiler/phases/constants.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export const PassiveEvents = ['wheel', 'touchstart', 'touchmove', 'touchend', 't
3131
export const Runes = /** @type {const} */ ([
3232
'$state',
3333
'$state.frozen',
34+
'$state.snapshot',
3435
'$props',
3536
'$bindable',
3637
'$derived',

packages/svelte/src/index-client.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,6 @@ export function flushSync(fn) {
177177
flush_sync(fn);
178178
}
179179

180-
export { unstate } from './internal/client/proxy.js';
181-
182180
export { hydrate, mount, unmount } from './internal/client/render.js';
183181

184182
export {

packages/svelte/src/index-server.js

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,4 @@ export function unmount() {
3333

3434
export async function tick() {}
3535

36-
/**
37-
* @template T
38-
* @param {T} value
39-
* @returns {T}
40-
*/
41-
export function unstate(value) {
42-
// There's no signals/proxies on the server, so just return the value
43-
return value;
44-
}
45-
4636
export { getAllContexts, getContext, hasContext, setContext } from './internal/server/context.js';

packages/svelte/src/internal/client/dom/blocks/each.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
resume_effect
2424
} from '../../reactivity/effects.js';
2525
import { source, mutable_source, set } from '../../reactivity/sources.js';
26-
import { is_array, is_frozen, map_get, map_set } from '../../utils.js';
26+
import { is_array, is_frozen } from '../../utils.js';
2727
import { STATE_SYMBOL } from '../../constants.js';
2828

2929
/**

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ export {
128128
validate_store
129129
} from './validate.js';
130130
export { raf } from './timing.js';
131-
export { proxy, unstate } from './proxy.js';
131+
export { proxy, snapshot } from './proxy.js';
132132
export { create_custom_element } from './dom/elements/custom-element.js';
133133
export {
134134
child,

0 commit comments

Comments
 (0)