diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js
index d442cee77d..4d047b4970 100644
--- a/packages/svelte/src/compiler/phases/2-analyze/index.js
+++ b/packages/svelte/src/compiler/phases/2-analyze/index.js
@@ -546,7 +546,6 @@ export function analyze_component(root, source, options) {
component_slots: new Set(),
expression: null,
render_tag: null,
- private_derived_state: [],
function_depth: scope.function_depth,
instance_scope: instance.scope,
reactive_statement: null,
@@ -618,7 +617,6 @@ export function analyze_component(root, source, options) {
component_slots: new Set(),
expression: null,
render_tag: null,
- private_derived_state: [],
function_depth: scope.function_depth
};
diff --git a/packages/svelte/src/compiler/phases/2-analyze/types.d.ts b/packages/svelte/src/compiler/phases/2-analyze/types.d.ts
index 2cfe76b61a..56e8a0b05b 100644
--- a/packages/svelte/src/compiler/phases/2-analyze/types.d.ts
+++ b/packages/svelte/src/compiler/phases/2-analyze/types.d.ts
@@ -17,7 +17,6 @@ export interface AnalysisState {
expression: ExpressionMetadata | null;
/** The current {@render ...} tag, if any */
render_tag: null | RenderTag;
- private_derived_state: string[];
function_depth: number;
// legacy stuff
diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/ClassBody.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/ClassBody.js
index d445af0ebf..a3e3765934 100644
--- a/packages/svelte/src/compiler/phases/2-analyze/visitors/ClassBody.js
+++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/ClassBody.js
@@ -1,27 +1,10 @@
/** @import { ClassBody } from 'estree' */
/** @import { Context } from '../types' */
-import { get_rune } from '../../scope.js';
/**
* @param {ClassBody} node
* @param {Context} context
*/
export function ClassBody(node, context) {
- /** @type {string[]} */
- const private_derived_state = [];
-
- for (const definition of node.body) {
- if (
- definition.type === 'PropertyDefinition' &&
- definition.key.type === 'PrivateIdentifier' &&
- definition.value?.type === 'CallExpression'
- ) {
- const rune = get_rune(definition.value, context.state.scope);
- if (rune === '$derived' || rune === '$derived.by') {
- private_derived_state.push(definition.key.name);
- }
- }
- }
-
- context.next({ ...context.state, private_derived_state });
+ context.next({ ...context.state });
}
diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/utils.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/utils.js
index f6df4292bc..95916f8614 100644
--- a/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/utils.js
+++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/utils.js
@@ -51,12 +51,6 @@ export function validate_assignment(node, argument, state) {
property = object.property;
object = object.object;
}
-
- if (object.type === 'ThisExpression' && property?.type === 'PrivateIdentifier') {
- if (state.private_derived_state.includes(property.name)) {
- e.constant_assignment(node, 'derived state');
- }
- }
}
/**
diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/AssignmentExpression.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/AssignmentExpression.js
index 288f2d0cfa..2ec5127eec 100644
--- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/AssignmentExpression.js
+++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/AssignmentExpression.js
@@ -46,7 +46,7 @@ function build_assignment(operator, left, right, context) {
if (should_proxy(value, context.state.scope)) {
transformed = true;
value =
- private_state.kind === 'raw_state'
+ private_state.kind === 'raw_state' || private_state.kind === 'derived'
? value
: build_proxy_reassignment(value, private_state.id);
}
diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/AssignmentExpression.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/AssignmentExpression.js
index 2988c590fd..451ed14162 100644
--- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/AssignmentExpression.js
+++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/AssignmentExpression.js
@@ -24,6 +24,23 @@ export function AssignmentExpression(node, context) {
function build_assignment(operator, left, right, context) {
let object = left;
+ if (
+ context.state.analysis.runes &&
+ left.type === 'MemberExpression' &&
+ left.object.type === 'ThisExpression' &&
+ left.property.type === 'PrivateIdentifier'
+ ) {
+ const field = context.state.private_derived.get(left.property.name);
+
+ if (field) {
+ return b.assignment(
+ operator,
+ left,
+ b.call('$.once', b.thunk(/** @type {Expression} */ (context.visit(right))))
+ );
+ }
+ }
+
while (object.type === 'MemberExpression') {
// @ts-expect-error
object = object.object;
diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/ClassBody.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/ClassBody.js
index 365084a284..4e9d35531e 100644
--- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/ClassBody.js
+++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/ClassBody.js
@@ -97,17 +97,6 @@ export function ClassBody(node, context) {
// get foo() { return this.#foo; }
body.push(b.method('get', definition.key, [], [b.return(b.call(member))]));
-
- if (dev && (field.kind === 'derived' || field.kind === 'derived_by')) {
- body.push(
- b.method(
- 'set',
- definition.key,
- [b.id('_')],
- [b.throw_error(`Cannot update a derived property ('${name}')`)]
- )
- );
- }
}
continue;
diff --git a/packages/svelte/tests/compiler-errors/samples/runes-no-derived-state-field-assignment/_config.js b/packages/svelte/tests/compiler-errors/samples/runes-no-derived-state-field-assignment/_config.js
deleted file mode 100644
index 94985a9939..0000000000
--- a/packages/svelte/tests/compiler-errors/samples/runes-no-derived-state-field-assignment/_config.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import { test } from '../../test';
-
-export default test({
- error: {
- code: 'constant_assignment',
- message: 'Cannot assign to derived state'
- }
-});
diff --git a/packages/svelte/tests/compiler-errors/samples/runes-no-derived-state-field-assignment/main.svelte b/packages/svelte/tests/compiler-errors/samples/runes-no-derived-state-field-assignment/main.svelte
deleted file mode 100644
index d44806757e..0000000000
--- a/packages/svelte/tests/compiler-errors/samples/runes-no-derived-state-field-assignment/main.svelte
+++ /dev/null
@@ -1,10 +0,0 @@
-
diff --git a/packages/svelte/tests/compiler-errors/samples/runes-no-derived-state-field-update/_config.js b/packages/svelte/tests/compiler-errors/samples/runes-no-derived-state-field-update/_config.js
deleted file mode 100644
index 94985a9939..0000000000
--- a/packages/svelte/tests/compiler-errors/samples/runes-no-derived-state-field-update/_config.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import { test } from '../../test';
-
-export default test({
- error: {
- code: 'constant_assignment',
- message: 'Cannot assign to derived state'
- }
-});
diff --git a/packages/svelte/tests/compiler-errors/samples/runes-no-derived-state-field-update/main.svelte b/packages/svelte/tests/compiler-errors/samples/runes-no-derived-state-field-update/main.svelte
deleted file mode 100644
index e4ee2e8635..0000000000
--- a/packages/svelte/tests/compiler-errors/samples/runes-no-derived-state-field-update/main.svelte
+++ /dev/null
@@ -1,10 +0,0 @@
-