diff --git a/packages/svelte/src/compiler/phases/3-transform/client/utils.js b/packages/svelte/src/compiler/phases/3-transform/client/utils.js
index eed663846b..1194cffcde 100644
--- a/packages/svelte/src/compiler/phases/3-transform/client/utils.js
+++ b/packages/svelte/src/compiler/phases/3-transform/client/utils.js
@@ -251,6 +251,8 @@ export const function_visitor = (node, context) => {
const in_constructor = parent.type === 'MethodDefinition' && parent.kind === 'constructor';
state = { ...context.state, in_constructor };
+ } else {
+ state = { ...context.state, in_constructor: false };
}
if (metadata?.hoistable === true) {
diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js
index b5fddc4489..1a217c5626 100644
--- a/packages/svelte/src/internal/client/runtime.js
+++ b/packages/svelte/src/internal/client/runtime.js
@@ -343,7 +343,13 @@ function destroy_references(signal) {
if (references !== null) {
let i;
for (i = 0; i < references.length; i++) {
- destroy_signal(references[i]);
+ const reference = references[i];
+ if ((reference.flags & IS_EFFECT) !== 0) {
+ destroy_signal(reference);
+ } else {
+ remove_consumer(reference, 0, true);
+ reference.dependencies = null;
+ }
}
}
}
@@ -710,7 +716,7 @@ export function exposable(fn) {
export function get(signal) {
const flags = signal.flags;
if ((flags & DESTROYED) !== 0) {
- return /** @type {V} */ (UNINITIALIZED);
+ return signal.value;
}
if (is_signal_exposed && current_should_capture_signal) {
@@ -1156,6 +1162,11 @@ export function managed_pre_effect(init, sync) {
* @returns {import('./types.js').EffectSignal}
*/
export function pre_effect(init) {
+ if (current_effect === null) {
+ throw new Error(
+ 'The Svelte $effect.pre rune can only be used during component initialisation.'
+ );
+ }
const sync = current_effect !== null && (current_effect.flags & RENDER_EFFECT) !== 0;
return internal_create_effect(
PRE_EFFECT,
diff --git a/packages/svelte/tests/runtime-runes/samples/class-state-constructor-closure-private/_config.js b/packages/svelte/tests/runtime-runes/samples/class-state-constructor-closure-private/_config.js
new file mode 100644
index 0000000000..dd847ce2f2
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/class-state-constructor-closure-private/_config.js
@@ -0,0 +1,13 @@
+import { flushSync } from 'svelte';
+import { test } from '../../test';
+
+export default test({
+ html: ``,
+ ssrHtml: ``,
+
+ async test({ assert, target }) {
+ flushSync();
+
+ assert.htmlEqual(target.innerHTML, ``);
+ }
+});
diff --git a/packages/svelte/tests/runtime-runes/samples/class-state-constructor-closure-private/main.svelte b/packages/svelte/tests/runtime-runes/samples/class-state-constructor-closure-private/main.svelte
new file mode 100644
index 0000000000..88b0398943
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/class-state-constructor-closure-private/main.svelte
@@ -0,0 +1,14 @@
+
+
+
diff --git a/packages/svelte/tests/runtime-runes/samples/class-state-constructor-closure/_config.js b/packages/svelte/tests/runtime-runes/samples/class-state-constructor-closure/_config.js
new file mode 100644
index 0000000000..dd847ce2f2
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/class-state-constructor-closure/_config.js
@@ -0,0 +1,13 @@
+import { flushSync } from 'svelte';
+import { test } from '../../test';
+
+export default test({
+ html: ``,
+ ssrHtml: ``,
+
+ async test({ assert, target }) {
+ flushSync();
+
+ assert.htmlEqual(target.innerHTML, ``);
+ }
+});
diff --git a/packages/svelte/tests/runtime-runes/samples/class-state-constructor-closure/main.svelte b/packages/svelte/tests/runtime-runes/samples/class-state-constructor-closure/main.svelte
new file mode 100644
index 0000000000..fe7fcf1aa3
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/class-state-constructor-closure/main.svelte
@@ -0,0 +1,22 @@
+
+
+
diff --git a/packages/svelte/tests/runtime-runes/samples/effect-cleanup/_config.js b/packages/svelte/tests/runtime-runes/samples/effect-cleanup/_config.js
new file mode 100644
index 0000000000..ee690418d6
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/effect-cleanup/_config.js
@@ -0,0 +1,19 @@
+import { test } from '../../test';
+import { flushSync } from 'svelte';
+
+export default test({
+ get props() {
+ return { log: [] };
+ },
+
+ async test({ assert, target, component }) {
+ const [b1] = target.querySelectorAll('button');
+ flushSync(() => {
+ b1.click();
+ });
+ flushSync(() => {
+ b1.click();
+ });
+ assert.deepEqual(component.log, ['init 0', 'cleanup 2', 'init 2', 'cleanup 4', 'init 4']);
+ }
+});
diff --git a/packages/svelte/tests/runtime-runes/samples/effect-cleanup/main.svelte b/packages/svelte/tests/runtime-runes/samples/effect-cleanup/main.svelte
new file mode 100644
index 0000000000..7c84aeddff
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/effect-cleanup/main.svelte
@@ -0,0 +1,17 @@
+
+
+