Repository: sveltejs/svelte (JavaScript)
Date: 2021-01-26 01:12:47+00:00
Task type: Bug Fix

Issue:
Store get from import statement called twice in SSR
**Describe the bug**
While debugging memory leak issue in my playing around svelte-kit repo, I ran into this issue (not related to svelte-kit), the store still log current time after prerender request done.

**To Reproduce**
[Repl](https://svelte.dev/repl/5b9b1dfae2554744bf2b35ab846472b1?version=3.31.2)
Open that link and switch to Js Output tab and choose `generate`: `ssr`:

Store declare inside component look good:
```js
let $now, $$unsubscribe_now;
$$unsubscribe_now = subscribe(now, value => $now = value);
$$unsubscribe_now();
```
But store get from import statement, subscribed 2 times before unsubscribe
```js
let $now_from_import, $$unsubscribe_now_from_import;
$$unsubscribe_now_from_import = subscribe(now_from_import, value => $now_from_import = value);
now_from_import.subscribe($$value => $now_from_import = $$value);
$$unsubscribe_now_from_import();
```





Issue discussion:

Solution patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@
 ## Unreleased
 
 * Throw a parser error for `class:` directives with an empty class name ([#5858](https://github.com/sveltejs/svelte/issues/5858))
+* Fix extraneous store subscription in SSR mode ([#5883](https://github.com/sveltejs/svelte/issues/5883))
 * Fix type inference for derived stores ([#5935](https://github.com/sveltejs/svelte/pull/5935))
 * Make parameters of built-in animations and transitions optional ([#5936](https://github.com/sveltejs/svelte/pull/5936))
 * Make `SvelteComponentDev` typings more forgiving ([#5937](https://github.com/sveltejs/svelte/pull/5937))
diff --git a/src/compiler/compile/render_ssr/index.ts b/src/compiler/compile/render_ssr/index.ts
--- a/src/compiler/compile/render_ssr/index.ts
+++ b/src/compiler/compile/render_ssr/index.ts
@@ -51,7 +51,6 @@ export default function ssr(
 			return b`
 				${component.compile_options.dev && b`@validate_store(${store_name}, '${store_name}');`}
 				${`$$unsubscribe_${store_name}`} = @subscribe(${store_name}, #value => ${name} = #value)
-				${store_name}.subscribe($$value => ${name} = $$value);
 			`;
 		});
 	const reactive_store_unsubscriptions = reactive_stores.map(


Test patch:
diff --git a/test/runtime/samples/reactive-assignment-in-complex-declaration-with-store-3/_config.js b/test/runtime/samples/reactive-assignment-in-complex-declaration-with-store-3/_config.js
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/reactive-assignment-in-complex-declaration-with-store-3/_config.js
@@ -0,0 +1,20 @@
+import { store } from './store.js';
+
+export default {
+	html: '<h1>0</h1>',
+	before_test() {
+		store.reset();
+	},
+	async test({ assert, target, component }) {
+		store.set(42);
+
+		await Promise.resolve();
+
+		assert.htmlEqual(target.innerHTML, '<h1>42</h1>');
+
+		assert.equal(store.numberOfTimesSubscribeCalled(), 1);
+	},
+	test_ssr({ assert }) {
+		assert.equal(store.numberOfTimesSubscribeCalled(), 1);
+	}
+};
diff --git a/test/runtime/samples/reactive-assignment-in-complex-declaration-with-store-3/main.svelte b/test/runtime/samples/reactive-assignment-in-complex-declaration-with-store-3/main.svelte
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/reactive-assignment-in-complex-declaration-with-store-3/main.svelte
@@ -0,0 +1,5 @@
+<script>
+	import { store } from './store';
+</script>
+
+<h1>{$store}</h1>
diff --git a/test/runtime/samples/reactive-assignment-in-complex-declaration-with-store-3/store.js b/test/runtime/samples/reactive-assignment-in-complex-declaration-with-store-3/store.js
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/reactive-assignment-in-complex-declaration-with-store-3/store.js
@@ -0,0 +1,18 @@
+import { writable } from '../../../../store';
+const _store = writable(0);
+let count = 0;
+
+export const store = {
+	..._store,
+	subscribe(fn) {
+		count++;
+		return _store.subscribe(fn);
+	},
+	reset() {
+		count = 0;
+		_store.set(0);
+	},
+	numberOfTimesSubscribeCalled() {
+		return count;
+	}
+};
diff --git a/test/server-side-rendering/index.ts b/test/server-side-rendering/index.ts
--- a/test/server-side-rendering/index.ts
+++ b/test/server-side-rendering/index.ts
@@ -201,6 +201,10 @@ describe('ssr', () => {
 					assert.htmlEqual(html, config.html);
 				}
 
+				if (config.test_ssr) {
+					config.test_ssr({ assert });
+				}
+
 				if (config.after_test) config.after_test();
 
 				if (config.show) {