From a422d2aba5661d9f9ca54db8a1e7b11692d4cde4 Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Sat, 11 Jan 2020 22:01:40 +0800 Subject: [PATCH 1/5] fix actions having no access to parent nodes (#4252) --- CHANGELOG.md | 1 + src/compiler/compile/render_dom/Block.ts | 4 ++-- .../action-custom-event-handler/expected.js | 4 ++-- test/js/samples/action/expected.js | 2 +- test/js/samples/bind-online/expected.js | 4 ++-- test/js/samples/bind-open/expected.js | 3 +-- .../bindings-readonly-order/expected.js | 10 ++++----- .../capture-inject-dev-only/expected.js | 2 +- .../samples/component-static-var/expected.js | 2 +- .../expected.js | 2 +- .../samples/dont-invalidate-this/expected.js | 2 +- .../samples/event-handler-dynamic/expected.js | 16 +++++++------- .../event-handler-no-passive/expected.js | 2 +- test/js/samples/event-modifiers/expected.js | 14 ++++++------ test/js/samples/input-files/expected.js | 2 +- .../input-no-initial-value/expected.js | 10 ++++----- test/js/samples/input-range/expected.js | 8 +++---- test/js/samples/input-value/expected.js | 2 +- .../input-without-blowback-guard/expected.js | 2 +- .../expected.js | 2 +- .../expected.js | 2 +- .../expected.js | 2 +- .../expected.js | 2 +- test/js/samples/media-bindings/expected.js | 22 +++++++++---------- test/js/samples/video-bindings/expected.js | 8 +++---- .../samples/window-binding-online/expected.js | 4 ++-- .../samples/window-binding-scroll/expected.js | 10 ++++----- .../_config.js | 8 +++++++ .../main.svelte | 8 +++++++ 29 files changed, 88 insertions(+), 72 deletions(-) create mode 100644 test/runtime/samples/action-receives-element-mounted/_config.js create mode 100644 test/runtime/samples/action-receives-element-mounted/main.svelte diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e5d5df95f..f6af419913 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * Prevent text input cursor jumping in Safari with one-way binding ([#3449](https://github.com/sveltejs/svelte/issues/3449)) * Expose compiler version in dev events ([#4047](https://github.com/sveltejs/svelte/issues/4047)) +* Don't run actions before their element is in the document ([#4166](https://github.com/sveltejs/svelte/issues/4166)) * Fix reactive assignments with destructuring and stores where the destructured value should be undefined ([#4170](https://github.com/sveltejs/svelte/issues/4170)) * Do not automatically declare variables in reactive declarations when assigning to a member expression ([#4212](https://github.com/sveltejs/svelte/issues/4212)) diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts index c8fa884721..68d28024fe 100644 --- a/src/compiler/compile/render_dom/Block.ts +++ b/src/compiler/compile/render_dom/Block.ts @@ -450,7 +450,7 @@ export default class Block { this.add_variable(dispose); if (this.event_listeners.length === 1) { - this.chunks.hydrate.push( + this.chunks.mount.push( b`${dispose} = ${this.event_listeners[0]};` ); @@ -458,7 +458,7 @@ export default class Block { b`${dispose}();` ); } else { - this.chunks.hydrate.push(b` + this.chunks.mount.push(b` ${dispose} = [ ${this.event_listeners} ]; diff --git a/test/js/samples/action-custom-event-handler/expected.js b/test/js/samples/action-custom-event-handler/expected.js index da42603895..968b5965d5 100644 --- a/test/js/samples/action-custom-event-handler/expected.js +++ b/test/js/samples/action-custom-event-handler/expected.js @@ -20,10 +20,10 @@ function create_fragment(ctx) { c() { button = element("button"); button.textContent = "foo"; - dispose = action_destroyer(foo_action = foo.call(null, button, /*foo_function*/ ctx[1])); }, m(target, anchor) { insert(target, button, anchor); + dispose = action_destroyer(foo_action = foo.call(null, button, /*foo_function*/ ctx[1])); }, p(ctx, [dirty]) { if (foo_action && is_function(foo_action.update) && dirty & /*bar*/ 1) foo_action.update.call(null, /*foo_function*/ ctx[1]); @@ -42,7 +42,7 @@ function handleFoo(bar) { } function foo(node, callback) { - + } function instance($$self, $$props, $$invalidate) { diff --git a/test/js/samples/action/expected.js b/test/js/samples/action/expected.js index dc3ebb5cf8..22d9cd939c 100644 --- a/test/js/samples/action/expected.js +++ b/test/js/samples/action/expected.js @@ -21,10 +21,10 @@ function create_fragment(ctx) { a = element("a"); a.textContent = "Test"; attr(a, "href", "#"); - dispose = action_destroyer(link_action = link.call(null, a)); }, m(target, anchor) { insert(target, a, anchor); + dispose = action_destroyer(link_action = link.call(null, a)); }, p: noop, i: noop, diff --git a/test/js/samples/bind-online/expected.js b/test/js/samples/bind-online/expected.js index 8285646481..e129e66d71 100644 --- a/test/js/samples/bind-online/expected.js +++ b/test/js/samples/bind-online/expected.js @@ -14,13 +14,13 @@ function create_fragment(ctx) { add_render_callback(/*onlinestatuschanged*/ ctx[1]); return { - c() { + c: noop, + m(target, anchor) { dispose = [ listen(window, "online", /*onlinestatuschanged*/ ctx[1]), listen(window, "offline", /*onlinestatuschanged*/ ctx[1]) ]; }, - m: noop, p: noop, i: noop, o: noop, diff --git a/test/js/samples/bind-open/expected.js b/test/js/samples/bind-open/expected.js index d4f148cac9..7d66145f0a 100644 --- a/test/js/samples/bind-open/expected.js +++ b/test/js/samples/bind-open/expected.js @@ -20,12 +20,11 @@ function create_fragment(ctx) { details.innerHTML = `summarycontent `; - - dispose = listen(details, "toggle", /*details_toggle_handler*/ ctx[1]); }, m(target, anchor) { insert(target, details, anchor); details.open = /*open*/ ctx[0]; + dispose = listen(details, "toggle", /*details_toggle_handler*/ ctx[1]); }, p(ctx, [dirty]) { if (dirty & /*open*/ 1) { diff --git a/test/js/samples/bindings-readonly-order/expected.js b/test/js/samples/bindings-readonly-order/expected.js index cf30686662..db0e7cb007 100644 --- a/test/js/samples/bindings-readonly-order/expected.js +++ b/test/js/samples/bindings-readonly-order/expected.js @@ -26,16 +26,16 @@ function create_fragment(ctx) { input1 = element("input"); attr(input0, "type", "file"); attr(input1, "type", "file"); - - dispose = [ - listen(input0, "change", /*input0_change_handler*/ ctx[1]), - listen(input1, "change", /*input1_change_handler*/ ctx[2]) - ]; }, m(target, anchor) { insert(target, input0, anchor); insert(target, t, anchor); insert(target, input1, anchor); + + dispose = [ + listen(input0, "change", /*input0_change_handler*/ ctx[1]), + listen(input1, "change", /*input1_change_handler*/ ctx[2]) + ]; }, p: noop, i: noop, diff --git a/test/js/samples/capture-inject-dev-only/expected.js b/test/js/samples/capture-inject-dev-only/expected.js index 6c639d9207..a314b0cff3 100644 --- a/test/js/samples/capture-inject-dev-only/expected.js +++ b/test/js/samples/capture-inject-dev-only/expected.js @@ -28,7 +28,6 @@ function create_fragment(ctx) { t0 = text(/*foo*/ ctx[0]); t1 = space(); input = element("input"); - dispose = listen(input, "input", /*input_input_handler*/ ctx[1]); }, m(target, anchor) { insert(target, p, anchor); @@ -36,6 +35,7 @@ function create_fragment(ctx) { insert(target, t1, anchor); insert(target, input, anchor); set_input_value(input, /*foo*/ ctx[0]); + dispose = listen(input, "input", /*input_input_handler*/ ctx[1]); }, p(ctx, [dirty]) { if (dirty & /*foo*/ 1) set_data(t0, /*foo*/ ctx[0]); diff --git a/test/js/samples/component-static-var/expected.js b/test/js/samples/component-static-var/expected.js index e01402b6d4..a65d9186a7 100644 --- a/test/js/samples/component-static-var/expected.js +++ b/test/js/samples/component-static-var/expected.js @@ -35,7 +35,6 @@ function create_fragment(ctx) { create_component(bar.$$.fragment); t1 = space(); input = element("input"); - dispose = listen(input, "input", /*input_input_handler*/ ctx[1]); }, m(target, anchor) { mount_component(foo, target, anchor); @@ -45,6 +44,7 @@ function create_fragment(ctx) { insert(target, input, anchor); set_input_value(input, /*z*/ ctx[0]); current = true; + dispose = listen(input, "input", /*input_input_handler*/ ctx[1]); }, p(ctx, [dirty]) { const bar_changes = {}; diff --git a/test/js/samples/component-store-reassign-invalidate/expected.js b/test/js/samples/component-store-reassign-invalidate/expected.js index 02a74cf22e..771b20dec4 100644 --- a/test/js/samples/component-store-reassign-invalidate/expected.js +++ b/test/js/samples/component-store-reassign-invalidate/expected.js @@ -31,13 +31,13 @@ function create_fragment(ctx) { t1 = space(); button = element("button"); button.textContent = "reset"; - dispose = listen(button, "click", /*click_handler*/ ctx[2]); }, m(target, anchor) { insert(target, h1, anchor); append(h1, t0); insert(target, t1, anchor); insert(target, button, anchor); + dispose = listen(button, "click", /*click_handler*/ ctx[2]); }, p(ctx, [dirty]) { if (dirty & /*$foo*/ 2) set_data(t0, /*$foo*/ ctx[1]); diff --git a/test/js/samples/dont-invalidate-this/expected.js b/test/js/samples/dont-invalidate-this/expected.js index 98f638dfcf..f5f6d07812 100644 --- a/test/js/samples/dont-invalidate-this/expected.js +++ b/test/js/samples/dont-invalidate-this/expected.js @@ -17,10 +17,10 @@ function create_fragment(ctx) { return { c() { input = element("input"); - dispose = listen(input, "input", make_uppercase); }, m(target, anchor) { insert(target, input, anchor); + dispose = listen(input, "input", make_uppercase); }, p: noop, i: noop, diff --git a/test/js/samples/event-handler-dynamic/expected.js b/test/js/samples/event-handler-dynamic/expected.js index 42c6b2951a..16b4a3f626 100644 --- a/test/js/samples/event-handler-dynamic/expected.js +++ b/test/js/samples/event-handler-dynamic/expected.js @@ -42,14 +42,6 @@ function create_fragment(ctx) { t5 = space(); button2 = element("button"); button2.textContent = "click"; - - dispose = [ - listen(button0, "click", /*updateHandler1*/ ctx[2]), - listen(button1, "click", /*updateHandler2*/ ctx[3]), - listen(button2, "click", function () { - if (is_function(/*clickHandler*/ ctx[0])) /*clickHandler*/ ctx[0].apply(this, arguments); - }) - ]; }, m(target, anchor) { insert(target, p0, anchor); @@ -61,6 +53,14 @@ function create_fragment(ctx) { append(p1, t4); insert(target, t5, anchor); insert(target, button2, anchor); + + dispose = [ + listen(button0, "click", /*updateHandler1*/ ctx[2]), + listen(button1, "click", /*updateHandler2*/ ctx[3]), + listen(button2, "click", function () { + if (is_function(/*clickHandler*/ ctx[0])) /*clickHandler*/ ctx[0].apply(this, arguments); + }) + ]; }, p(new_ctx, [dirty]) { ctx = new_ctx; diff --git a/test/js/samples/event-handler-no-passive/expected.js b/test/js/samples/event-handler-no-passive/expected.js index 6f04e67808..c519fac668 100644 --- a/test/js/samples/event-handler-no-passive/expected.js +++ b/test/js/samples/event-handler-no-passive/expected.js @@ -20,10 +20,10 @@ function create_fragment(ctx) { a = element("a"); a.textContent = "this should not navigate to example.com"; attr(a, "href", "https://example.com"); - dispose = listen(a, "touchstart", touchstart_handler); }, m(target, anchor) { insert(target, a, anchor); + dispose = listen(a, "touchstart", touchstart_handler); }, p: noop, i: noop, diff --git a/test/js/samples/event-modifiers/expected.js b/test/js/samples/event-modifiers/expected.js index 3f324bb76d..252034a431 100644 --- a/test/js/samples/event-modifiers/expected.js +++ b/test/js/samples/event-modifiers/expected.js @@ -35,13 +35,6 @@ function create_fragment(ctx) { t3 = space(); button2 = element("button"); button2.textContent = "or me!"; - - dispose = [ - listen(button0, "click", stop_propagation(prevent_default(handleClick))), - listen(button1, "click", handleClick, { once: true, capture: true }), - listen(button2, "click", handleClick, true), - listen(div, "touchstart", handleTouchstart, { passive: true }) - ]; }, m(target, anchor) { insert(target, div, anchor); @@ -50,6 +43,13 @@ function create_fragment(ctx) { append(div, button1); append(div, t3); append(div, button2); + + dispose = [ + listen(button0, "click", stop_propagation(prevent_default(handleClick))), + listen(button1, "click", handleClick, { once: true, capture: true }), + listen(button2, "click", handleClick, true), + listen(div, "touchstart", handleTouchstart, { passive: true }) + ]; }, p: noop, i: noop, diff --git a/test/js/samples/input-files/expected.js b/test/js/samples/input-files/expected.js index c3e46f0c79..2a2254fbd7 100644 --- a/test/js/samples/input-files/expected.js +++ b/test/js/samples/input-files/expected.js @@ -20,10 +20,10 @@ function create_fragment(ctx) { input = element("input"); attr(input, "type", "file"); input.multiple = true; - dispose = listen(input, "change", /*input_change_handler*/ ctx[1]); }, m(target, anchor) { insert(target, input, anchor); + dispose = listen(input, "change", /*input_change_handler*/ ctx[1]); }, p: noop, i: noop, diff --git a/test/js/samples/input-no-initial-value/expected.js b/test/js/samples/input-no-initial-value/expected.js index 8ff2b2798b..d588f0bf73 100644 --- a/test/js/samples/input-no-initial-value/expected.js +++ b/test/js/samples/input-no-initial-value/expected.js @@ -31,11 +31,6 @@ function create_fragment(ctx) { button.textContent = "Store"; attr(input, "type", "text"); input.required = true; - - dispose = [ - listen(input, "input", /*input_input_handler*/ ctx[2]), - listen(form, "submit", /*handleSubmit*/ ctx[1]) - ]; }, m(target, anchor) { insert(target, form, anchor); @@ -43,6 +38,11 @@ function create_fragment(ctx) { set_input_value(input, /*test*/ ctx[0]); append(form, t0); append(form, button); + + dispose = [ + listen(input, "input", /*input_input_handler*/ ctx[2]), + listen(form, "submit", /*handleSubmit*/ ctx[1]) + ]; }, p(ctx, [dirty]) { if (dirty & /*test*/ 1 && input.value !== /*test*/ ctx[0]) { diff --git a/test/js/samples/input-range/expected.js b/test/js/samples/input-range/expected.js index 5a074d9754..12dfd3e90e 100644 --- a/test/js/samples/input-range/expected.js +++ b/test/js/samples/input-range/expected.js @@ -22,16 +22,16 @@ function create_fragment(ctx) { c() { input = element("input"); attr(input, "type", "range"); + }, + m(target, anchor) { + insert(target, input, anchor); + set_input_value(input, /*value*/ ctx[0]); dispose = [ listen(input, "change", /*input_change_input_handler*/ ctx[1]), listen(input, "input", /*input_change_input_handler*/ ctx[1]) ]; }, - m(target, anchor) { - insert(target, input, anchor); - set_input_value(input, /*value*/ ctx[0]); - }, p(ctx, [dirty]) { if (dirty & /*value*/ 1) { set_input_value(input, /*value*/ ctx[0]); diff --git a/test/js/samples/input-value/expected.js b/test/js/samples/input-value/expected.js index 81753441e4..21c7bfc83b 100644 --- a/test/js/samples/input-value/expected.js +++ b/test/js/samples/input-value/expected.js @@ -30,7 +30,6 @@ function create_fragment(ctx) { t1 = text(/*name*/ ctx[0]); t2 = text("!"); input.value = /*name*/ ctx[0]; - dispose = listen(input, "input", /*onInput*/ ctx[1]); }, m(target, anchor) { insert(target, input, anchor); @@ -38,6 +37,7 @@ function create_fragment(ctx) { insert(target, h1, anchor); append(h1, t1); append(h1, t2); + dispose = listen(input, "input", /*onInput*/ ctx[1]); }, p(ctx, [dirty]) { if (dirty & /*name*/ 1 && input.value !== /*name*/ ctx[0]) { diff --git a/test/js/samples/input-without-blowback-guard/expected.js b/test/js/samples/input-without-blowback-guard/expected.js index 344976ade6..fefe867e14 100644 --- a/test/js/samples/input-without-blowback-guard/expected.js +++ b/test/js/samples/input-without-blowback-guard/expected.js @@ -19,11 +19,11 @@ function create_fragment(ctx) { c() { input = element("input"); attr(input, "type", "checkbox"); - dispose = listen(input, "change", /*input_change_handler*/ ctx[1]); }, m(target, anchor) { insert(target, input, anchor); input.checked = /*foo*/ ctx[0]; + dispose = listen(input, "change", /*input_change_handler*/ ctx[1]); }, p(ctx, [dirty]) { if (dirty & /*foo*/ 1) { diff --git a/test/js/samples/instrumentation-script-if-no-block/expected.js b/test/js/samples/instrumentation-script-if-no-block/expected.js index 4127a6d7d6..7634481a2d 100644 --- a/test/js/samples/instrumentation-script-if-no-block/expected.js +++ b/test/js/samples/instrumentation-script-if-no-block/expected.js @@ -30,7 +30,6 @@ function create_fragment(ctx) { p = element("p"); t2 = text("x: "); t3 = text(/*x*/ ctx[0]); - dispose = listen(button, "click", /*foo*/ ctx[1]); }, m(target, anchor) { insert(target, button, anchor); @@ -38,6 +37,7 @@ function create_fragment(ctx) { insert(target, p, anchor); append(p, t2); append(p, t3); + dispose = listen(button, "click", /*foo*/ ctx[1]); }, p(ctx, [dirty]) { if (dirty & /*x*/ 1) set_data(t3, /*x*/ ctx[0]); diff --git a/test/js/samples/instrumentation-script-x-equals-x/expected.js b/test/js/samples/instrumentation-script-x-equals-x/expected.js index 0d4493baf3..c154608cd5 100644 --- a/test/js/samples/instrumentation-script-x-equals-x/expected.js +++ b/test/js/samples/instrumentation-script-x-equals-x/expected.js @@ -31,7 +31,6 @@ function create_fragment(ctx) { p = element("p"); t2 = text("number of things: "); t3 = text(t3_value); - dispose = listen(button, "click", /*foo*/ ctx[1]); }, m(target, anchor) { insert(target, button, anchor); @@ -39,6 +38,7 @@ function create_fragment(ctx) { insert(target, p, anchor); append(p, t2); append(p, t3); + dispose = listen(button, "click", /*foo*/ ctx[1]); }, p(ctx, [dirty]) { if (dirty & /*things*/ 1 && t3_value !== (t3_value = /*things*/ ctx[0].length + "")) set_data(t3, t3_value); diff --git a/test/js/samples/instrumentation-template-if-no-block/expected.js b/test/js/samples/instrumentation-template-if-no-block/expected.js index 0bd627eb87..77780baa99 100644 --- a/test/js/samples/instrumentation-template-if-no-block/expected.js +++ b/test/js/samples/instrumentation-template-if-no-block/expected.js @@ -30,7 +30,6 @@ function create_fragment(ctx) { p = element("p"); t2 = text("x: "); t3 = text(/*x*/ ctx[0]); - dispose = listen(button, "click", /*click_handler*/ ctx[1]); }, m(target, anchor) { insert(target, button, anchor); @@ -38,6 +37,7 @@ function create_fragment(ctx) { insert(target, p, anchor); append(p, t2); append(p, t3); + dispose = listen(button, "click", /*click_handler*/ ctx[1]); }, p(ctx, [dirty]) { if (dirty & /*x*/ 1) set_data(t3, /*x*/ ctx[0]); diff --git a/test/js/samples/instrumentation-template-x-equals-x/expected.js b/test/js/samples/instrumentation-template-x-equals-x/expected.js index e049a6d39b..4fe45616c7 100644 --- a/test/js/samples/instrumentation-template-x-equals-x/expected.js +++ b/test/js/samples/instrumentation-template-x-equals-x/expected.js @@ -31,7 +31,6 @@ function create_fragment(ctx) { p = element("p"); t2 = text("number of things: "); t3 = text(t3_value); - dispose = listen(button, "click", /*click_handler*/ ctx[1]); }, m(target, anchor) { insert(target, button, anchor); @@ -39,6 +38,7 @@ function create_fragment(ctx) { insert(target, p, anchor); append(p, t2); append(p, t3); + dispose = listen(button, "click", /*click_handler*/ ctx[1]); }, p(ctx, [dirty]) { if (dirty & /*things*/ 1 && t3_value !== (t3_value = /*things*/ ctx[0].length + "")) set_data(t3, t3_value); diff --git a/test/js/samples/media-bindings/expected.js b/test/js/samples/media-bindings/expected.js index b5548a3efe..52fef36792 100644 --- a/test/js/samples/media-bindings/expected.js +++ b/test/js/samples/media-bindings/expected.js @@ -41,6 +41,17 @@ function create_fragment(ctx) { if (/*duration*/ ctx[4] === void 0) add_render_callback(() => /*audio_durationchange_handler*/ ctx[13].call(audio)); if (/*seeking*/ ctx[8] === void 0) add_render_callback(() => /*audio_seeking_seeked_handler*/ ctx[17].call(audio)); if (/*ended*/ ctx[9] === void 0) add_render_callback(() => /*audio_ended_handler*/ ctx[18].call(audio)); + }, + m(target, anchor) { + insert(target, audio, anchor); + + if (!isNaN(/*volume*/ ctx[6])) { + audio.volume = /*volume*/ ctx[6]; + } + + if (!isNaN(/*playbackRate*/ ctx[7])) { + audio.playbackRate = /*playbackRate*/ ctx[7]; + } dispose = [ listen(audio, "progress", /*audio_progress_handler*/ ctx[10]), @@ -56,17 +67,6 @@ function create_fragment(ctx) { listen(audio, "ended", /*audio_ended_handler*/ ctx[18]) ]; }, - m(target, anchor) { - insert(target, audio, anchor); - - if (!isNaN(/*volume*/ ctx[6])) { - audio.volume = /*volume*/ ctx[6]; - } - - if (!isNaN(/*playbackRate*/ ctx[7])) { - audio.playbackRate = /*playbackRate*/ ctx[7]; - } - }, p(ctx, [dirty]) { if (!audio_updating && dirty & /*currentTime*/ 8 && !isNaN(/*currentTime*/ ctx[3])) { audio.currentTime = /*currentTime*/ ctx[3]; diff --git a/test/js/samples/video-bindings/expected.js b/test/js/samples/video-bindings/expected.js index 5b734a70a6..c8cd1d84ce 100644 --- a/test/js/samples/video-bindings/expected.js +++ b/test/js/samples/video-bindings/expected.js @@ -37,16 +37,16 @@ function create_fragment(ctx) { video = element("video"); if (/*videoHeight*/ ctx[1] === void 0 || /*videoWidth*/ ctx[2] === void 0) add_render_callback(() => /*video_resize_handler*/ ctx[5].call(video)); add_render_callback(() => /*video_elementresize_handler*/ ctx[6].call(video)); + }, + m(target, anchor) { + insert(target, video, anchor); + video_resize_listener = add_resize_listener(video, /*video_elementresize_handler*/ ctx[6].bind(video)); dispose = [ listen(video, "timeupdate", video_timeupdate_handler), listen(video, "resize", /*video_resize_handler*/ ctx[5]) ]; }, - m(target, anchor) { - insert(target, video, anchor); - video_resize_listener = add_resize_listener(video, /*video_elementresize_handler*/ ctx[6].bind(video)); - }, p(ctx, [dirty]) { if (!video_updating && dirty & /*currentTime*/ 1 && !isNaN(/*currentTime*/ ctx[0])) { video.currentTime = /*currentTime*/ ctx[0]; diff --git a/test/js/samples/window-binding-online/expected.js b/test/js/samples/window-binding-online/expected.js index 8285646481..e129e66d71 100644 --- a/test/js/samples/window-binding-online/expected.js +++ b/test/js/samples/window-binding-online/expected.js @@ -14,13 +14,13 @@ function create_fragment(ctx) { add_render_callback(/*onlinestatuschanged*/ ctx[1]); return { - c() { + c: noop, + m(target, anchor) { dispose = [ listen(window, "online", /*onlinestatuschanged*/ ctx[1]), listen(window, "offline", /*onlinestatuschanged*/ ctx[1]) ]; }, - m: noop, p: noop, i: noop, o: noop, diff --git a/test/js/samples/window-binding-scroll/expected.js b/test/js/samples/window-binding-scroll/expected.js index f79212e25e..70c39eedd2 100644 --- a/test/js/samples/window-binding-scroll/expected.js +++ b/test/js/samples/window-binding-scroll/expected.js @@ -33,6 +33,11 @@ function create_fragment(ctx) { p = element("p"); t0 = text("scrolled to "); t1 = text(/*y*/ ctx[0]); + }, + m(target, anchor) { + insert(target, p, anchor); + append(p, t0); + append(p, t1); dispose = listen(window, "scroll", () => { scrolling = true; @@ -41,11 +46,6 @@ function create_fragment(ctx) { /*onwindowscroll*/ ctx[1](); }); }, - m(target, anchor) { - insert(target, p, anchor); - append(p, t0); - append(p, t1); - }, p(ctx, [dirty]) { if (dirty & /*y*/ 1 && !scrolling) { scrolling = true; diff --git a/test/runtime/samples/action-receives-element-mounted/_config.js b/test/runtime/samples/action-receives-element-mounted/_config.js new file mode 100644 index 0000000000..0806d0fa90 --- /dev/null +++ b/test/runtime/samples/action-receives-element-mounted/_config.js @@ -0,0 +1,8 @@ +const result = {}; + +export default { + props: { result }, + async test({ assert, component, target, window }) { + assert.notEqual(result.parentElement, null); + } +}; diff --git a/test/runtime/samples/action-receives-element-mounted/main.svelte b/test/runtime/samples/action-receives-element-mounted/main.svelte new file mode 100644 index 0000000000..a53ce81de0 --- /dev/null +++ b/test/runtime/samples/action-receives-element-mounted/main.svelte @@ -0,0 +1,8 @@ + + +

Hello!

\ No newline at end of file From 7c3e34c00bb585b05104c13a03d3606427cb0457 Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Mon, 13 Jan 2020 04:42:45 +0800 Subject: [PATCH 2/5] fix hydrating each else (#4253) --- CHANGELOG.md | 1 + .../compile/render_dom/wrappers/EachBlock.ts | 13 +++++++++++++ test/hydration/samples/each-else/_after.html | 4 ++++ test/hydration/samples/each-else/_before.html | 4 ++++ test/hydration/samples/each-else/main.svelte | 15 +++++++++++++++ 5 files changed, 37 insertions(+) create mode 100644 test/hydration/samples/each-else/_after.html create mode 100644 test/hydration/samples/each-else/_before.html create mode 100644 test/hydration/samples/each-else/main.svelte diff --git a/CHANGELOG.md b/CHANGELOG.md index f6af419913..25c0aa2093 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * Expose compiler version in dev events ([#4047](https://github.com/sveltejs/svelte/issues/4047)) * Don't run actions before their element is in the document ([#4166](https://github.com/sveltejs/svelte/issues/4166)) * Fix reactive assignments with destructuring and stores where the destructured value should be undefined ([#4170](https://github.com/sveltejs/svelte/issues/4170)) +* Fix hydrating `{:else}` in `{#each}` ([#4202](https://github.com/sveltejs/svelte/issues/4202)) * Do not automatically declare variables in reactive declarations when assigning to a member expression ([#4212](https://github.com/sveltejs/svelte/issues/4212)) ## 3.16.7 diff --git a/src/compiler/compile/render_dom/wrappers/EachBlock.ts b/src/compiler/compile/render_dom/wrappers/EachBlock.ts index 5b13b486e6..4928b5a38c 100644 --- a/src/compiler/compile/render_dom/wrappers/EachBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/EachBlock.ts @@ -264,10 +264,23 @@ export default class EachBlockWrapper extends Wrapper { block.chunks.init.push(b` if (!${this.vars.data_length}) { ${each_block_else} = ${this.else.block.name}(#ctx); + } + `); + + block.chunks.create.push(b` + if (${each_block_else}) { ${each_block_else}.c(); } `); + if (this.renderer.options.hydratable) { + block.chunks.claim.push(b` + if (${each_block_else}) { + ${each_block_else}.l(${parent_nodes}); + } + `); + } + block.chunks.mount.push(b` if (${each_block_else}) { ${each_block_else}.m(${initial_mount_node}, ${initial_anchor_node}); diff --git a/test/hydration/samples/each-else/_after.html b/test/hydration/samples/each-else/_after.html new file mode 100644 index 0000000000..7920500ec3 --- /dev/null +++ b/test/hydration/samples/each-else/_after.html @@ -0,0 +1,4 @@ +

Hello, world

+

+ weird +

\ No newline at end of file diff --git a/test/hydration/samples/each-else/_before.html b/test/hydration/samples/each-else/_before.html new file mode 100644 index 0000000000..7920500ec3 --- /dev/null +++ b/test/hydration/samples/each-else/_before.html @@ -0,0 +1,4 @@ +

Hello, world

+

+ weird +

\ No newline at end of file diff --git a/test/hydration/samples/each-else/main.svelte b/test/hydration/samples/each-else/main.svelte new file mode 100644 index 0000000000..64d3a37c58 --- /dev/null +++ b/test/hydration/samples/each-else/main.svelte @@ -0,0 +1,15 @@ + + +

Hello, {name}

+{#each array as elem} +

+ item +

+{:else} +

+ weird +

+{/each} From ef56a70acbe484bf1be9787ae63ae5102ee275ea Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Tue, 14 Jan 2020 00:13:54 +0800 Subject: [PATCH 3/5] SSR should only render one (#4250) --- CHANGELOG.md | 1 + src/compiler/compile/render_ssr/handlers/Title.ts | 6 ++++++ src/runtime/internal/ssr.ts | 5 +++-- .../samples/head-multiple-title/A.svelte | 3 +++ .../samples/head-multiple-title/B.svelte | 3 +++ .../samples/head-multiple-title/_expected-head.html | 1 + .../samples/head-multiple-title/_expected.html | 0 .../samples/head-multiple-title/data.json | 3 +++ .../samples/head-multiple-title/main.svelte | 10 ++++++++++ 9 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 test/server-side-rendering/samples/head-multiple-title/A.svelte create mode 100644 test/server-side-rendering/samples/head-multiple-title/B.svelte create mode 100644 test/server-side-rendering/samples/head-multiple-title/_expected-head.html create mode 100644 test/server-side-rendering/samples/head-multiple-title/_expected.html create mode 100644 test/server-side-rendering/samples/head-multiple-title/data.json create mode 100644 test/server-side-rendering/samples/head-multiple-title/main.svelte diff --git a/CHANGELOG.md b/CHANGELOG.md index 25c0aa2093..8d69c6194b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ * Fix reactive assignments with destructuring and stores where the destructured value should be undefined ([#4170](https://github.com/sveltejs/svelte/issues/4170)) * Fix hydrating `{:else}` in `{#each}` ([#4202](https://github.com/sveltejs/svelte/issues/4202)) * Do not automatically declare variables in reactive declarations when assigning to a member expression ([#4212](https://github.com/sveltejs/svelte/issues/4212)) +* Only render one `<title>` in SSR mode when multiple components provide one ([#4250](https://github.com/sveltejs/svelte/pull/4250)) ## 3.16.7 diff --git a/src/compiler/compile/render_ssr/handlers/Title.ts b/src/compiler/compile/render_ssr/handlers/Title.ts index 62d49d461a..f1f458ed5b 100644 --- a/src/compiler/compile/render_ssr/handlers/Title.ts +++ b/src/compiler/compile/render_ssr/handlers/Title.ts @@ -1,10 +1,16 @@ import Renderer, { RenderOptions } from '../Renderer'; import Title from '../../nodes/Title'; +import { x } from 'code-red'; export default function(node: Title, renderer: Renderer, options: RenderOptions) { + renderer.push(); + renderer.add_string(`<title>`); renderer.render(node.children, options); renderer.add_string(``); + const result = renderer.pop(); + + renderer.add_expression(x`($$result.title = ${result}, "")`); } diff --git a/src/runtime/internal/ssr.ts b/src/runtime/internal/ssr.ts index 274006f243..b032284d52 100644 --- a/src/runtime/internal/ssr.ts +++ b/src/runtime/internal/ssr.ts @@ -103,12 +103,13 @@ export function create_ssr_component(fn) { on_destroy = []; const result: { + title: string; head: string; css: Set<{ map: null; code: string; }>; - } = { head: '', css: new Set() }; + } = { title: '', head: '', css: new Set() }; const html = $$render(result, props, {}, options); @@ -120,7 +121,7 @@ export function create_ssr_component(fn) { code: Array.from(result.css).map(css => css.code).join('\n'), map: null // TODO }, - head: result.head + head: result.title + result.head }; }, diff --git a/test/server-side-rendering/samples/head-multiple-title/A.svelte b/test/server-side-rendering/samples/head-multiple-title/A.svelte new file mode 100644 index 0000000000..b139b4ff77 --- /dev/null +++ b/test/server-side-rendering/samples/head-multiple-title/A.svelte @@ -0,0 +1,3 @@ + + A + diff --git a/test/server-side-rendering/samples/head-multiple-title/B.svelte b/test/server-side-rendering/samples/head-multiple-title/B.svelte new file mode 100644 index 0000000000..4a29ecb04c --- /dev/null +++ b/test/server-side-rendering/samples/head-multiple-title/B.svelte @@ -0,0 +1,3 @@ + + B + diff --git a/test/server-side-rendering/samples/head-multiple-title/_expected-head.html b/test/server-side-rendering/samples/head-multiple-title/_expected-head.html new file mode 100644 index 0000000000..af5c5feba4 --- /dev/null +++ b/test/server-side-rendering/samples/head-multiple-title/_expected-head.html @@ -0,0 +1 @@ +B \ No newline at end of file diff --git a/test/server-side-rendering/samples/head-multiple-title/_expected.html b/test/server-side-rendering/samples/head-multiple-title/_expected.html new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/server-side-rendering/samples/head-multiple-title/data.json b/test/server-side-rendering/samples/head-multiple-title/data.json new file mode 100644 index 0000000000..eab238e816 --- /dev/null +++ b/test/server-side-rendering/samples/head-multiple-title/data.json @@ -0,0 +1,3 @@ +{ + "adjective": "custom" +} \ No newline at end of file diff --git a/test/server-side-rendering/samples/head-multiple-title/main.svelte b/test/server-side-rendering/samples/head-multiple-title/main.svelte new file mode 100644 index 0000000000..fb9a70b923 --- /dev/null +++ b/test/server-side-rendering/samples/head-multiple-title/main.svelte @@ -0,0 +1,10 @@ + + + + Main + + + From e3d66869df5b75b81da6183c5d68cde53b2439aa Mon Sep 17 00:00:00 2001 From: Jesse Skinner Date: Mon, 13 Jan 2020 11:24:34 -0500 Subject: [PATCH 4/5] fix stringifying of attributes in presence of spread in SSR (#4247) --- src/runtime/internal/ssr.ts | 4 +--- .../spread-attributes-white-space/_expected.html | 8 ++++++++ .../spread-attributes-white-space/main.svelte | 12 ++++++++++++ 3 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 test/server-side-rendering/samples/spread-attributes-white-space/_expected.html create mode 100644 test/server-side-rendering/samples/spread-attributes-white-space/main.svelte diff --git a/src/runtime/internal/ssr.ts b/src/runtime/internal/ssr.ts index b032284d52..646a81d817 100644 --- a/src/runtime/internal/ssr.ts +++ b/src/runtime/internal/ssr.ts @@ -25,9 +25,7 @@ export function spread(args, classes_to_add) { else if (boolean_attributes.has(name.toLowerCase())) { if (value) str += " " + name; } else if (value != null) { - str += " " + name + "=" + JSON.stringify(String(value) - .replace(/"/g, '"') - .replace(/'/g, ''')); + str += ` ${name}="${String(value).replace(/"/g, '"').replace(/'/g, ''')}"`; } }); diff --git a/test/server-side-rendering/samples/spread-attributes-white-space/_expected.html b/test/server-side-rendering/samples/spread-attributes-white-space/_expected.html new file mode 100644 index 0000000000..a73bb17e8c --- /dev/null +++ b/test/server-side-rendering/samples/spread-attributes-white-space/_expected.html @@ -0,0 +1,8 @@ + + + \ No newline at end of file diff --git a/test/server-side-rendering/samples/spread-attributes-white-space/main.svelte b/test/server-side-rendering/samples/spread-attributes-white-space/main.svelte new file mode 100644 index 0000000000..6919d9ea54 --- /dev/null +++ b/test/server-side-rendering/samples/spread-attributes-white-space/main.svelte @@ -0,0 +1,12 @@ + + + + + From d7d7ce1e6c4ab0166eb5f40e5f2dad6a49dd0fe3 Mon Sep 17 00:00:00 2001 From: Conduitry Date: Mon, 13 Jan 2020 11:25:48 -0500 Subject: [PATCH 5/5] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d69c6194b..a2db4470d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ * Fix reactive assignments with destructuring and stores where the destructured value should be undefined ([#4170](https://github.com/sveltejs/svelte/issues/4170)) * Fix hydrating `{:else}` in `{#each}` ([#4202](https://github.com/sveltejs/svelte/issues/4202)) * Do not automatically declare variables in reactive declarations when assigning to a member expression ([#4212](https://github.com/sveltejs/svelte/issues/4212)) +* Fix stringifying of attributes in SSR mode when there are spread attributes ([#4240](https://github.com/sveltejs/svelte/issues/4240)) * Only render one `` in SSR mode when multiple components provide one ([#4250](https://github.com/sveltejs/svelte/pull/4250)) ## 3.16.7