From f2eb632bc9e9483f4663277fa9e500d6e1d25b42 Mon Sep 17 00:00:00 2001 From: Pontus Lundin Date: Wed, 18 Dec 2019 12:34:55 +0000 Subject: [PATCH 01/13] pseudo code --- src/runtime/internal/lifecycle.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/runtime/internal/lifecycle.ts b/src/runtime/internal/lifecycle.ts index a8e37e9632a3..809a39d717f5 100644 --- a/src/runtime/internal/lifecycle.ts +++ b/src/runtime/internal/lifecycle.ts @@ -28,6 +28,8 @@ export function onDestroy(fn) { } export function createEventDispatcher() { + // is compile target customElement? + // always dispatch! const component = get_current_component(); return (type: string, detail?: any) => { @@ -61,4 +63,4 @@ export function bubble(component, event) { if (callbacks) { callbacks.slice().forEach(fn => fn(event)); } -} \ No newline at end of file +} From 6ebffd2882576aa23cda26b9dd193217ffcf51d5 Mon Sep 17 00:00:00 2001 From: Pontus Lundin Date: Wed, 18 Dec 2019 12:37:34 +0000 Subject: [PATCH 02/13] pseudo code --- src/runtime/internal/dom.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/runtime/internal/dom.ts b/src/runtime/internal/dom.ts index c641315bc37b..5b3c70261d98 100644 --- a/src/runtime/internal/dom.ts +++ b/src/runtime/internal/dom.ts @@ -268,6 +268,9 @@ export function toggle_class(element, name, toggle) { } export function custom_event(type: string, detail?: T) { + // is compile target customElement? + // is event not a Svelte event? + // use new CustomEvent with bubbles/composed = true for non, svelte event const e: CustomEvent = document.createEvent('CustomEvent'); e.initCustomEvent(type, false, false, detail); return e; @@ -307,4 +310,4 @@ export class HtmlTag { d() { this.n.forEach(detach); } -} \ No newline at end of file +} From 0245239eaabfef656c7dcf7e69ea8e857b4ef674 Mon Sep 17 00:00:00 2001 From: hontas Date: Sat, 7 Mar 2020 23:50:40 +0100 Subject: [PATCH 03/13] cleanup --- src/runtime/internal/dom.ts | 5 +---- src/runtime/internal/lifecycle.ts | 4 +--- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/runtime/internal/dom.ts b/src/runtime/internal/dom.ts index 9745e4a50896..9ab9a4395f40 100644 --- a/src/runtime/internal/dom.ts +++ b/src/runtime/internal/dom.ts @@ -273,9 +273,6 @@ export function toggle_class(element, name, toggle) { } export function custom_event(type: string, detail?: T) { - // is compile target customElement? - // is event not a Svelte event? - // use new CustomEvent with bubbles/composed = true for non, svelte event const e: CustomEvent = document.createEvent('CustomEvent'); e.initCustomEvent(type, false, false, detail); return e; @@ -319,4 +316,4 @@ export class HtmlTag { d() { this.n.forEach(detach); } -} +} \ No newline at end of file diff --git a/src/runtime/internal/lifecycle.ts b/src/runtime/internal/lifecycle.ts index 809a39d717f5..a8e37e9632a3 100644 --- a/src/runtime/internal/lifecycle.ts +++ b/src/runtime/internal/lifecycle.ts @@ -28,8 +28,6 @@ export function onDestroy(fn) { } export function createEventDispatcher() { - // is compile target customElement? - // always dispatch! const component = get_current_component(); return (type: string, detail?: any) => { @@ -63,4 +61,4 @@ export function bubble(component, event) { if (callbacks) { callbacks.slice().forEach(fn => fn(event)); } -} +} \ No newline at end of file From 9e78f39212e6023527819766e45646c428199a5b Mon Sep 17 00:00:00 2001 From: hontas Date: Sat, 7 Mar 2020 07:04:20 +0100 Subject: [PATCH 04/13] get console output from puppeteer --- test/custom-elements/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/custom-elements/index.ts b/test/custom-elements/index.ts index d3644a314283..35df15687959 100644 --- a/test/custom-elements/index.ts +++ b/test/custom-elements/index.ts @@ -110,8 +110,8 @@ describe('custom-elements', function() { const page = await browser.newPage(); - page.on('console', (type, ...args) => { - console[type](...args); + page.on('console', (type) => { + console[type._type](type._text); }); page.on('error', error => { From 18334b4477371a43727ed9f6850c50f563ed14c8 Mon Sep 17 00:00:00 2001 From: hontas Date: Sat, 7 Mar 2020 07:05:34 +0100 Subject: [PATCH 05/13] custom element call onDestroy when disconnected --- src/runtime/internal/Component.ts | 4 ++++ .../samples/ondestroy/main.svelte | 22 +++++++++++++++++++ .../custom-elements/samples/ondestroy/test.js | 11 ++++++++++ 3 files changed, 37 insertions(+) create mode 100644 test/custom-elements/samples/ondestroy/main.svelte create mode 100644 test/custom-elements/samples/ondestroy/test.js diff --git a/src/runtime/internal/Component.ts b/src/runtime/internal/Component.ts index 6d211dfedd74..0078b78c0404 100644 --- a/src/runtime/internal/Component.ts +++ b/src/runtime/internal/Component.ts @@ -184,6 +184,10 @@ if (typeof HTMLElement === 'function') { this[attr] = newValue; } + disconnectedCallback() { + this.$destroy(); + } + $destroy() { destroy_component(this, 1); this.$destroy = noop; diff --git a/test/custom-elements/samples/ondestroy/main.svelte b/test/custom-elements/samples/ondestroy/main.svelte new file mode 100644 index 000000000000..aa945ca60202 --- /dev/null +++ b/test/custom-elements/samples/ondestroy/main.svelte @@ -0,0 +1,22 @@ + + + + +
diff --git a/test/custom-elements/samples/ondestroy/test.js b/test/custom-elements/samples/ondestroy/test.js new file mode 100644 index 000000000000..91aff740e797 --- /dev/null +++ b/test/custom-elements/samples/ondestroy/test.js @@ -0,0 +1,11 @@ +import * as assert from 'assert'; +import './main.svelte'; + +export default function (target) { + target.innerHTML = ''; + const el = target.querySelector('my-app'); + target.removeChild(el); + + assert.ok(target.dataset.onMountDestroyed); + assert.ok(target.dataset.destroyed); +} \ No newline at end of file From a493b57518cc0a05e37daa65b9dfe9d591fa536d Mon Sep 17 00:00:00 2001 From: hontas Date: Sat, 7 Mar 2020 07:32:01 +0100 Subject: [PATCH 06/13] only call onDestroy callbacks --- src/runtime/internal/Component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/internal/Component.ts b/src/runtime/internal/Component.ts index 0078b78c0404..7be9f4a06519 100644 --- a/src/runtime/internal/Component.ts +++ b/src/runtime/internal/Component.ts @@ -185,7 +185,7 @@ if (typeof HTMLElement === 'function') { } disconnectedCallback() { - this.$destroy(); + run_all(this.$$.on_destroy); } $destroy() { From 7d9636f75c26924dda29771ca8297d7215710435 Mon Sep 17 00:00:00 2001 From: Pontus Lundin Date: Wed, 3 Jun 2020 23:57:00 +0200 Subject: [PATCH 07/13] lifecycle hooks and custom elements - Call onMount in connectedCallback for customElements - register onMount return values as on_disconnect-callbacks for customElements - run on_disconnect callbacks in disconnectedCallback --- src/runtime/internal/Component.ts | 43 +++++++++++++------ .../samples/oncreate/main.svelte | 13 +++--- test/custom-elements/samples/oncreate/test.js | 4 +- .../custom-elements/samples/ondestroy/test.js | 6 +-- 4 files changed, 44 insertions(+), 22 deletions(-) diff --git a/src/runtime/internal/Component.ts b/src/runtime/internal/Component.ts index 7be9f4a06519..82d9f290a8ac 100644 --- a/src/runtime/internal/Component.ts +++ b/src/runtime/internal/Component.ts @@ -34,6 +34,7 @@ interface T$$ { on_mount: any[]; on_destroy: any[]; skip_bound: boolean; + on_disconnect: any[]; } export function bind(component, name, callback) { @@ -54,21 +55,25 @@ export function claim_component(block, parent_nodes) { export function mount_component(component, target, anchor) { const { fragment, on_mount, on_destroy, after_update } = component.$$; + const isCustomElement = typeof SvelteElement !== 'undefined' && component instanceof SvelteElement; fragment && fragment.m(target, anchor); - // onMount happens before the initial afterUpdate - add_render_callback(() => { - const new_on_destroy = on_mount.map(run).filter(is_function); - if (on_destroy) { - on_destroy.push(...new_on_destroy); - } else { - // Edge case - component was destroyed immediately, - // most likely as a result of a binding initialising - run_all(new_on_destroy); - } - component.$$.on_mount = []; - }); + // custom element on_mount is called in connectedCallback + if (!isCustomElement) { + // onMount happens before the initial afterUpdate + add_render_callback(() => { + const new_on_destroy = on_mount.map(run).filter(is_function); + if (on_destroy) { + on_destroy.push(...new_on_destroy); + } else { + // Edge case - component was destroyed immediately, + // most likely as a result of a binding initialising + run_all(new_on_destroy); + } + component.$$.on_mount = []; + }); + } after_update.forEach(add_render_callback); } @@ -113,6 +118,7 @@ export function init(component, options, instance, create_fragment, not_equal, p // lifecycle on_mount: [], on_destroy: [], + on_disconnect: [], before_update: [], after_update: [], context: new Map(parent_component ? parent_component.$$.context : []), @@ -178,6 +184,17 @@ if (typeof HTMLElement === 'function') { // @ts-ignore todo: improve typings this.appendChild(this.$$.slotted[key]); } + + const { on_mount, on_disconnect, on_destroy } = this.$$; + const new_on_disconnect = on_mount.map(run).filter(is_function); + if (on_destroy) { + on_disconnect.push(...new_on_disconnect); + } else { + // Edge case - component was destroyed immediately, + // most likely as a result of a binding initialising + run_all(new_on_disconnect); + } + this.$$.on_mount = []; } attributeChangedCallback(attr, _oldValue, newValue) { @@ -185,7 +202,7 @@ if (typeof HTMLElement === 'function') { } disconnectedCallback() { - run_all(this.$$.on_destroy); + run_all(this.$$.on_disconnect); } $destroy() { diff --git a/test/custom-elements/samples/oncreate/main.svelte b/test/custom-elements/samples/oncreate/main.svelte index ed3980a28ecf..885f66621802 100644 --- a/test/custom-elements/samples/oncreate/main.svelte +++ b/test/custom-elements/samples/oncreate/main.svelte @@ -1,11 +1,14 @@ diff --git a/test/custom-elements/samples/oncreate/test.js b/test/custom-elements/samples/oncreate/test.js index c33f8a6a1038..f451979976c6 100644 --- a/test/custom-elements/samples/oncreate/test.js +++ b/test/custom-elements/samples/oncreate/test.js @@ -2,7 +2,9 @@ import * as assert from 'assert'; import './main.svelte'; export default function (target) { - target.innerHTML = ''; + target.innerHTML = ''; const el = target.querySelector('my-app'); + assert.ok(el.wasCreated); + assert.ok(el.propsInitialized); } diff --git a/test/custom-elements/samples/ondestroy/test.js b/test/custom-elements/samples/ondestroy/test.js index 91aff740e797..61375bfa966a 100644 --- a/test/custom-elements/samples/ondestroy/test.js +++ b/test/custom-elements/samples/ondestroy/test.js @@ -3,9 +3,9 @@ import './main.svelte'; export default function (target) { target.innerHTML = ''; - const el = target.querySelector('my-app'); + const el = target.querySelector('my-app'); target.removeChild(el); assert.ok(target.dataset.onMountDestroyed); - assert.ok(target.dataset.destroyed); -} \ No newline at end of file + assert.equal(target.dataset.destroyed, undefined); +} From 95ad63fecfdf9e739b474e878051a64ac5baaab0 Mon Sep 17 00:00:00 2001 From: Pontus Lundin Date: Thu, 4 Jun 2020 07:45:06 +0200 Subject: [PATCH 08/13] simplify logic, trigger tests --- src/runtime/internal/Component.ts | 48 ++++++++++++++----------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/src/runtime/internal/Component.ts b/src/runtime/internal/Component.ts index 82d9f290a8ac..633bfc28ca4a 100644 --- a/src/runtime/internal/Component.ts +++ b/src/runtime/internal/Component.ts @@ -55,25 +55,25 @@ export function claim_component(block, parent_nodes) { export function mount_component(component, target, anchor) { const { fragment, on_mount, on_destroy, after_update } = component.$$; - const isCustomElement = typeof SvelteElement !== 'undefined' && component instanceof SvelteElement; + const isCustomElement = ['connectedCallback', 'attributeChangedCallback', 'disconnectedCallback'].every((method) => typeof component[method] === 'function'); fragment && fragment.m(target, anchor); - // custom element on_mount is called in connectedCallback - if (!isCustomElement) { - // onMount happens before the initial afterUpdate - add_render_callback(() => { - const new_on_destroy = on_mount.map(run).filter(is_function); - if (on_destroy) { - on_destroy.push(...new_on_destroy); - } else { - // Edge case - component was destroyed immediately, - // most likely as a result of a binding initialising - run_all(new_on_destroy); - } - component.$$.on_mount = []; - }); - } + // onMount happens before the initial afterUpdate + add_render_callback(() => { + // custom element on_mount is called in connectedCallback + if (isCustomElement) return; + + const new_on_destroy = on_mount.map(run).filter(is_function); + if (on_destroy) { + on_destroy.push(...new_on_destroy); + } else { + // Edge case - component was destroyed immediately, + // most likely as a result of a binding initialising + run_all(new_on_destroy); + } + component.$$.on_mount = []; + }); after_update.forEach(add_render_callback); } @@ -179,22 +179,16 @@ if (typeof HTMLElement === 'function') { } connectedCallback() { + const { on_mount } = this.$$; + + this.$$.on_disconnect = on_mount.map(run).filter(is_function); + this.$$.on_mount = []; + // @ts-ignore todo: improve typings for (const key in this.$$.slotted) { // @ts-ignore todo: improve typings this.appendChild(this.$$.slotted[key]); } - - const { on_mount, on_disconnect, on_destroy } = this.$$; - const new_on_disconnect = on_mount.map(run).filter(is_function); - if (on_destroy) { - on_disconnect.push(...new_on_disconnect); - } else { - // Edge case - component was destroyed immediately, - // most likely as a result of a binding initialising - run_all(new_on_disconnect); - } - this.$$.on_mount = []; } attributeChangedCallback(attr, _oldValue, newValue) { From 90f5c0a7ba2efebffa784f161e460375f09bece3 Mon Sep 17 00:00:00 2001 From: Pontus Lundin Date: Thu, 4 Jun 2020 07:47:15 +0200 Subject: [PATCH 09/13] fix whitespace, trigger tests --- test/custom-elements/samples/oncreate/main.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/custom-elements/samples/oncreate/main.svelte b/test/custom-elements/samples/oncreate/main.svelte index 885f66621802..23819e660f15 100644 --- a/test/custom-elements/samples/oncreate/main.svelte +++ b/test/custom-elements/samples/oncreate/main.svelte @@ -1,7 +1,7 @@