Repository: sveltejs/svelte (JavaScript)
Date: 2018-03-30 19:50:32+00:00
Task type: Bug Fix

Issue:
`.destroy()` vs `.teardown()` for custom events
in the [custom methods documentation](https://svelte.technology/guide#custom-methods) the event `longpress` returns `{destroy}` but the generated code in the REPL has `longpress_handler.teardown()` called in the destroy method. The longpress event would never get removed.

From #365 I understand `component.destroy()` is the retained convention and I am assuming the documentation is correct but the generated code is not?

(sorry if I am raising this as an issue instead of a PR but I am still trying to figure out the vision and conventions)


Issue discussion:
I believe this is a docs issue, not a codegen issue. After `teardown` was renamed to `destroy` for components, the docs were updated ([link](https://github.com/sveltejs/svelte.technology/pull/71)), but the update was overenthusiastic in scope, as `teardown` was still used for custom event definitions ([link](https://github.com/sveltejs/svelte.technology/commit/86fc6da0e90945e5e7ef01df773b549bbb83065c)), but I guess not all of the mistakes were caught.

That said, I'm not sure why custom event handlers do still use `teardown`. Because they're seen as something conceptually different than destroying a component? Or because of the technical difficulty of deprecating `teardown` while still keeping old code working? Either way, this also seems ripe for a runtime `dev: true` check and warning.
Yeah, I think we *should* rename it to `destroy`, but for now the docs are just wrong. Have just pushed a fix. Will leave this open so that we can address the underlying issue. It'd be nice to deprecate this gracefully — remove `teardown` in v2, but support both until then with a dev warning.

For event handlers that are declared inline, like the one in the docs example, we could catch it at compile time in most cases.

Solution patch:
diff --git a/src/generators/nodes/Element.ts b/src/generators/nodes/Element.ts
--- a/src/generators/nodes/Element.ts
+++ b/src/generators/nodes/Element.ts
@@ -516,8 +516,16 @@ export default class Element extends Node {
 					});
 				`);
 
+
+				block.builders.hydrate.addBlock(deindent`
+					if (${handlerName}.teardown) {
+						${handlerName}.destroy = ${handlerName}.teardown;
+						${generator.options.dev && `console.warn("Return 'destroy()' from custom event handlers. Returning 'teardown()' has been deprecated and will be unsupported in Svelte 2");`}
+					}
+				`);
+
 				block.builders.destroy.addLine(deindent`
-					${handlerName}.teardown();
+					${handlerName}.destroy();
 				`);
 			} else {
 				const handler = deindent`


Test patch:
diff --git a/test/js/samples/event-handlers-custom/expected-bundle.js b/test/js/samples/event-handlers-custom/expected-bundle.js
--- a/test/js/samples/event-handlers-custom/expected-bundle.js
+++ b/test/js/samples/event-handlers-custom/expected-bundle.js
@@ -199,6 +199,10 @@ function create_main_fragment(component, state) {
 				var state = component.get();
 				component.foo( state.bar );
 			});
+
+			if (foo_handler.teardown) {
+				foo_handler.destroy = foo_handler.teardown;
+			}
 		},
 
 		m: function mount(target, anchor) {
@@ -212,7 +216,7 @@ function create_main_fragment(component, state) {
 		},
 
 		d: function destroy$$1() {
-			foo_handler.teardown();
+			foo_handler.destroy();
 		}
 	};
 }
diff --git a/test/js/samples/event-handlers-custom/expected.js b/test/js/samples/event-handlers-custom/expected.js
--- a/test/js/samples/event-handlers-custom/expected.js
+++ b/test/js/samples/event-handlers-custom/expected.js
@@ -26,6 +26,10 @@ function create_main_fragment(component, state) {
 				var state = component.get();
 				component.foo( state.bar );
 			});
+
+			if (foo_handler.teardown) {
+				foo_handler.destroy = foo_handler.teardown;
+			}
 		},
 
 		m: function mount(target, anchor) {
@@ -39,7 +43,7 @@ function create_main_fragment(component, state) {
 		},
 
 		d: function destroy() {
-			foo_handler.teardown();
+			foo_handler.destroy();
 		}
 	};
 }
diff --git a/test/runtime/samples/dev-warning-custom-event-destroy-not-teardown/_config.js b/test/runtime/samples/dev-warning-custom-event-destroy-not-teardown/_config.js
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/dev-warning-custom-event-destroy-not-teardown/_config.js
@@ -0,0 +1,7 @@
+export default {
+	dev: true,
+
+	warnings: [
+		`Return 'destroy()' from custom event handlers. Returning 'teardown()' has been deprecated and will be unsupported in Svelte 2`
+	]
+};
\ No newline at end of file
diff --git a/test/runtime/samples/dev-warning-custom-event-destroy-not-teardown/main.html b/test/runtime/samples/dev-warning-custom-event-destroy-not-teardown/main.html
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/dev-warning-custom-event-destroy-not-teardown/main.html
@@ -0,0 +1,16 @@
+<button on:foo='foo()'>foo</button>
+
+<script>
+	export default {
+		methods: {
+			foo() {}
+		},
+		events: {
+			foo(node, callback) {
+				return {
+					teardown() {}
+				}
+			}
+		}
+	};
+</script>
\ No newline at end of file