From 12c51f3f84fc3eeb09e761be9b1281f19064c99e Mon Sep 17 00:00:00 2001 From: Luca Bonavita Date: Mon, 13 Jul 2020 16:40:33 +0100 Subject: [PATCH 01/21] site: remove an obsolete TODO in blog post (#5135) --- site/content/blog/2019-04-16-svelte-for-new-developers.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/site/content/blog/2019-04-16-svelte-for-new-developers.md b/site/content/blog/2019-04-16-svelte-for-new-developers.md index 796a6c11ab..fd7a88e6f1 100644 --- a/site/content/blog/2019-04-16-svelte-for-new-developers.md +++ b/site/content/blog/2019-04-16-svelte-for-new-developers.md @@ -74,8 +74,6 @@ This creates a new directory, `my-svelte-project`, adds files from the [sveltejs In the `package.json` file, there is a section called `"scripts"`. These scripts define shortcuts for working with your application — `dev`, `build` and `start`. To launch your app in development mode, type the following: -> TODO update the template, it needs... some work - ```bash npm run dev ``` From 04871ae70c3ee4b907715c690a53fe1b9471b877 Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Mon, 13 Jul 2020 11:46:24 -0400 Subject: [PATCH 02/21] site: add FAQ entry for how to document a svelte component (#5131) --- .../450-how-do-i-document-my-components.md | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 site/content/faq/450-how-do-i-document-my-components.md diff --git a/site/content/faq/450-how-do-i-document-my-components.md b/site/content/faq/450-how-do-i-document-my-components.md new file mode 100644 index 0000000000..78177abd54 --- /dev/null +++ b/site/content/faq/450-how-do-i-document-my-components.md @@ -0,0 +1,32 @@ +--- +question: How do I document my components? +--- + +In editors which use the Svelte Language Server you can document Components, functions and exports using specially formatted comments. + +````svelte + + + +
+

+ Hello, {name} +

+
+```` + +Note: The `@component` is necessary in the HTML comment which describes your component. From 2d6324ed4a720d1d87f05b694ad50823ca1e844c Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Tue, 14 Jul 2020 00:03:12 +0800 Subject: [PATCH 03/21] fix $$props reactive for slots (#5125) --- CHANGELOG.md | 4 +++ .../compile/render_dom/wrappers/Slot.ts | 26 +++++++++---------- .../samples/props-reactive-slot/Comp.svelte | 1 + .../samples/props-reactive-slot/_config.js | 21 +++++++++++++++ .../samples/props-reactive-slot/main.svelte | 13 ++++++++++ 5 files changed, 51 insertions(+), 14 deletions(-) create mode 100644 test/runtime/samples/props-reactive-slot/Comp.svelte create mode 100644 test/runtime/samples/props-reactive-slot/_config.js create mode 100644 test/runtime/samples/props-reactive-slot/main.svelte diff --git a/CHANGELOG.md b/CHANGELOG.md index cc53511860..63f4f0fa2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Svelte changelog +## Unreleased + +* Fix reactivity when passing `$$props` to a `` ([#3364](https://github.com/sveltejs/svelte/issues/3364)) + ## 3.24.0 * Support nullish coalescing (`??`) and optional chaining (`?.`) operators ([#1972](https://github.com/sveltejs/svelte/issues/1972)) diff --git a/src/compiler/compile/render_dom/wrappers/Slot.ts b/src/compiler/compile/render_dom/wrappers/Slot.ts index 268875acaf..bf808196c0 100644 --- a/src/compiler/compile/render_dom/wrappers/Slot.ts +++ b/src/compiler/compile/render_dom/wrappers/Slot.ts @@ -7,6 +7,7 @@ import { b, p, x } from 'code-red'; import { sanitize } from '../../../utils/names'; import add_to_set from '../../utils/add_to_set'; import get_slot_data from '../../utils/get_slot_data'; +import { is_reserved_keyword } from '../../utils/reserved_keywords'; import Expression from '../../nodes/shared/Expression'; import is_dynamic from './shared/is_dynamic'; import { Identifier, ObjectExpression } from 'estree'; @@ -94,11 +95,7 @@ export default class SlotWrapper extends Wrapper { } }); - const dynamic_dependencies = Array.from(attribute.dependencies).filter(name => { - if (this.node.scope.is_let(name)) return true; - const variable = renderer.component.var_lookup.get(name); - return is_dynamic(variable); - }); + const dynamic_dependencies = Array.from(attribute.dependencies).filter((name) => this.is_dependency_dynamic(name)); if (dynamic_dependencies.length > 0) { changes.properties.push(p`${attribute.name}: ${renderer.dirty(dynamic_dependencies)}`); @@ -157,17 +154,10 @@ export default class SlotWrapper extends Wrapper { b`@transition_out(${slot_or_fallback}, #local);` ); - const is_dependency_dynamic = name => { - if (name === '$$scope') return true; - if (this.node.scope.is_let(name)) return true; - const variable = renderer.component.var_lookup.get(name); - return is_dynamic(variable); - }; - - const dynamic_dependencies = Array.from(this.dependencies).filter(is_dependency_dynamic); + const dynamic_dependencies = Array.from(this.dependencies).filter((name) => this.is_dependency_dynamic(name)); const fallback_dynamic_dependencies = has_fallback - ? Array.from(this.fallback.dependencies).filter(is_dependency_dynamic) + ? Array.from(this.fallback.dependencies).filter((name) => this.is_dependency_dynamic(name)) : []; const slot_update = b` @@ -201,4 +191,12 @@ export default class SlotWrapper extends Wrapper { b`if (${slot_or_fallback}) ${slot_or_fallback}.d(detaching);` ); } + + is_dependency_dynamic(name: string) { + if (name === '$$scope') return true; + if (this.node.scope.is_let(name)) return true; + if (is_reserved_keyword(name)) return true; + const variable = this.renderer.component.var_lookup.get(name); + return is_dynamic(variable); + } } diff --git a/test/runtime/samples/props-reactive-slot/Comp.svelte b/test/runtime/samples/props-reactive-slot/Comp.svelte new file mode 100644 index 0000000000..bf9e12a58a --- /dev/null +++ b/test/runtime/samples/props-reactive-slot/Comp.svelte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/runtime/samples/props-reactive-slot/_config.js b/test/runtime/samples/props-reactive-slot/_config.js new file mode 100644 index 0000000000..286bba2f08 --- /dev/null +++ b/test/runtime/samples/props-reactive-slot/_config.js @@ -0,0 +1,21 @@ +export default { + html: ` +

hi

+ + `, + + async test({ assert, component, target, window }) { + const btn = target.querySelector("button"); + const clickEvent = new window.MouseEvent("click"); + + await btn.dispatchEvent(clickEvent); + + assert.htmlEqual( + target.innerHTML, + ` +

changed

+ + ` + ); + }, +}; diff --git a/test/runtime/samples/props-reactive-slot/main.svelte b/test/runtime/samples/props-reactive-slot/main.svelte new file mode 100644 index 0000000000..84777bf8ab --- /dev/null +++ b/test/runtime/samples/props-reactive-slot/main.svelte @@ -0,0 +1,13 @@ + + + +

+ {props.someprop} +

+
+ + \ No newline at end of file From fda1b3581661dd88b3e45976c4a71412a866ac00 Mon Sep 17 00:00:00 2001 From: Stanislav Lashmanov Date: Tue, 14 Jul 2020 20:27:42 +0300 Subject: [PATCH 04/21] Simplify each block bindings example (#5094) No need for CSS here, the same effect could be achieved with just a `disabled` binding. --- .../05-bindings/07-each-block-bindings/App.svelte | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/site/content/examples/05-bindings/07-each-block-bindings/App.svelte b/site/content/examples/05-bindings/07-each-block-bindings/App.svelte index ff91612ec5..4d3d75420c 100644 --- a/site/content/examples/05-bindings/07-each-block-bindings/App.svelte +++ b/site/content/examples/05-bindings/07-each-block-bindings/App.svelte @@ -16,16 +16,10 @@ $: remaining = todos.filter(t => !t.done).length; - -

Todos

{#each todos as todo} -
+
{/each} From 471c0d24849d7400080431db72eaba08c9d96def Mon Sep 17 00:00:00 2001 From: Lev Maximov Date: Wed, 15 Jul 2020 03:13:19 +0700 Subject: [PATCH 05/21] site: use https in link in blog (#5148) --- .../content/blog/2016-11-26-frameworks-without-the-framework.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/content/blog/2016-11-26-frameworks-without-the-framework.md b/site/content/blog/2016-11-26-frameworks-without-the-framework.md index 4efac90b52..76c8b90ab3 100644 --- a/site/content/blog/2016-11-26-frameworks-without-the-framework.md +++ b/site/content/blog/2016-11-26-frameworks-without-the-framework.md @@ -30,7 +30,7 @@ Given that, what if the framework *didn't actually run in the browser*? What if, Svelte is a new framework that does exactly that. You write your components using HTML, CSS and JavaScript (plus a few extra bits you can [learn in under 5 minutes](https://v2.svelte.dev/guide)), and during your build process Svelte compiles them into tiny standalone JavaScript modules. By statically analysing the component template, we can make sure that the browser does as little work as possible. -The [Svelte implementation of TodoMVC](http://svelte-todomvc.surge.sh/) weighs 3.6kb zipped. For comparison, React plus ReactDOM *without any app code* weighs about 45kb zipped. It takes about 10x as long for the browser just to evaluate React as it does for Svelte to be up and running with an interactive TodoMVC. +The [Svelte implementation of TodoMVC](https://svelte-todomvc.surge.sh/) weighs 3.6kb zipped. For comparison, React plus ReactDOM *without any app code* weighs about 45kb zipped. It takes about 10x as long for the browser just to evaluate React as it does for Svelte to be up and running with an interactive TodoMVC. And once your app *is* up and running, according to [js-framework-benchmark](https://github.com/krausest/js-framework-benchmark) **Svelte is fast as heck**. It's faster than React. It's faster than Vue. It's faster than Angular, or Ember, or Ractive, or Preact, or Riot, or Mithril. It's competitive with Inferno, which is probably the fastest UI framework in the world, for now, because [Dominic Gannaway](https://twitter.com/trueadm) is a wizard. (Svelte is slower at removing elements. We're [working on it](https://github.com/sveltejs/svelte/issues/26).) From f59a8a8ec2bef34957d3a9bde3ea5bdb3645671d Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Wed, 15 Jul 2020 05:32:24 +0800 Subject: [PATCH 06/21] invalidate $$props and $$restProps only when there are changes (#5123) --- CHANGELOG.md | 1 + src/compiler/compile/render_dom/index.ts | 1 + .../wrappers/InlineComponent/index.ts | 2 +- src/runtime/internal/utils.ts | 4 +++ .../Comp.svelte | 6 ++++ .../_config.js | 30 +++++++++++++++++++ .../main.svelte | 8 +++++ 7 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 test/runtime/samples/props-reactive-only-with-change/Comp.svelte create mode 100644 test/runtime/samples/props-reactive-only-with-change/_config.js create mode 100644 test/runtime/samples/props-reactive-only-with-change/main.svelte diff --git a/CHANGELOG.md b/CHANGELOG.md index 63f4f0fa2a..61b4c36842 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unreleased * Fix reactivity when passing `$$props` to a `` ([#3364](https://github.com/sveltejs/svelte/issues/3364)) +* Fix unneeded invalidation of `$$props` and `$$restProps` ([#4993](https://github.com/sveltejs/svelte/issues/4993), [#5118](https://github.com/sveltejs/svelte/issues/5118)) ## 3.24.0 diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index 3b5001d483..f6ffd8f2a6 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -86,6 +86,7 @@ export default function dom( const set = (uses_props || uses_rest || writable_props.length > 0 || component.slots.size > 0) ? x` ${$$props} => { + ${(uses_props || uses_rest) && b`if (@is_empty(${$$props})) return;`} ${uses_props && renderer.invalidate('$$props', x`$$props = @assign(@assign({}, $$props), @exclude_internal_props($$new_props))`)} ${uses_rest && !uses_props && x`$$props = @assign(@assign({}, $$props), @exclude_internal_props($$new_props))`} ${uses_rest && renderer.invalidate('$$restProps', x`$$restProps = ${compute_rest}`)} diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index 271b3de1e1..814f365a84 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -468,7 +468,7 @@ export default class InlineComponentWrapper extends Wrapper { ${name} = null; } } else if (${switch_value}) { - ${updates.length && b`${name}.$set(${name_changes});`} + ${updates.length > 0 && b`${name}.$set(${name_changes});`} } `); diff --git a/src/runtime/internal/utils.ts b/src/runtime/internal/utils.ts index d752c9de9d..3fd0a2b701 100644 --- a/src/runtime/internal/utils.ts +++ b/src/runtime/internal/utils.ts @@ -42,6 +42,10 @@ export function not_equal(a, b) { return a != a ? b == b : a !== b; } +export function is_empty(obj) { + return Object.keys(obj).length === 0; +} + export function validate_store(store, name) { if (store != null && typeof store.subscribe !== 'function') { throw new Error(`'${name}' is not a store with a 'subscribe' method`); diff --git a/test/runtime/samples/props-reactive-only-with-change/Comp.svelte b/test/runtime/samples/props-reactive-only-with-change/Comp.svelte new file mode 100644 index 0000000000..0eaf8a40d4 --- /dev/null +++ b/test/runtime/samples/props-reactive-only-with-change/Comp.svelte @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/test/runtime/samples/props-reactive-only-with-change/_config.js b/test/runtime/samples/props-reactive-only-with-change/_config.js new file mode 100644 index 0000000000..04170620c8 --- /dev/null +++ b/test/runtime/samples/props-reactive-only-with-change/_config.js @@ -0,0 +1,30 @@ +let callbacks = []; + +export default { + props: { + callback: (value) => callbacks.push(value), + val1: "1", + val2: "2", + }, + + before_test() { + callbacks = []; + }, + + async test({ assert, component, target }) { + assert.equal(callbacks.length, 2); + assert.equal(JSON.stringify(callbacks), '["1","2"]'); + + component.val1 = "3"; + assert.equal(callbacks.length, 3); + assert.equal(JSON.stringify(callbacks), '["1","2","1"]'); + + component.val1 = "4"; + assert.equal(callbacks.length, 4); + assert.equal(JSON.stringify(callbacks), '["1","2","1","1"]'); + + component.val2 = "5"; + assert.equal(callbacks.length, 5); + assert.equal(JSON.stringify(callbacks), '["1","2","1","1","2"]'); + }, +}; diff --git a/test/runtime/samples/props-reactive-only-with-change/main.svelte b/test/runtime/samples/props-reactive-only-with-change/main.svelte new file mode 100644 index 0000000000..73ddd137f5 --- /dev/null +++ b/test/runtime/samples/props-reactive-only-with-change/main.svelte @@ -0,0 +1,8 @@ + + + + \ No newline at end of file From 269354a395c7ce9b7dfbddd145e3ce64da86acc0 Mon Sep 17 00:00:00 2001 From: Wolfr Date: Fri, 17 Jul 2020 12:54:41 +0200 Subject: [PATCH 07/21] Fixes #5153 (#5154) --- site/src/routes/repl/[id]/_components/AppControls/index.svelte | 1 + 1 file changed, 1 insertion(+) diff --git a/site/src/routes/repl/[id]/_components/AppControls/index.svelte b/site/src/routes/repl/[id]/_components/AppControls/index.svelte index 10639e91c0..1d4e6b3f03 100644 --- a/site/src/routes/repl/[id]/_components/AppControls/index.svelte +++ b/site/src/routes/repl/[id]/_components/AppControls/index.svelte @@ -227,6 +227,7 @@ export default app;` }); padding: .6rem var(--side-nav); background-color: var(--second); color: white; + white-space: nowrap; } .icon { From 4bd1de654fb28c738d401d39c55cb140c65f7bd2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2020 11:57:30 +0100 Subject: [PATCH 08/21] Bump lodash from 4.17.15 to 4.17.19 in /site (#5155) Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- site/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/site/package-lock.json b/site/package-lock.json index b3d12343f1..1132b9f324 100644 --- a/site/package-lock.json +++ b/site/package-lock.json @@ -2404,9 +2404,9 @@ } }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", "dev": true }, "lodash.deburr": { From 179d9ff17af550a584cd5a3a5e8a91ef0c535f39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2020 15:47:14 -0400 Subject: [PATCH 09/21] Bump lodash from 4.17.15 to 4.17.19 (#5152) Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 68f251c605..82ad8fb6f6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2527,9 +2527,9 @@ } }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", "dev": true }, "lodash.sortby": { From c3da9e4ae976c70a99c713189af76d960a422cda Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Sat, 18 Jul 2020 04:12:26 +0800 Subject: [PATCH 10/21] add updating guard to binding callback (#5126) --- CHANGELOG.md | 1 + src/compiler/compile/render_dom/index.ts | 3 +- src/runtime/internal/Component.ts | 26 +++++--- .../action-custom-event-handler/expected.js | 2 +- test/js/samples/bind-open/expected.js | 2 +- test/js/samples/bind-width-height/expected.js | 2 +- .../bindings-readonly-order/expected.js | 2 +- .../samples/capture-inject-state/expected.js | 2 +- .../expected.js | 2 +- .../samples/computed-collapsed-if/expected.js | 2 +- test/js/samples/data-attribute/expected.js | 2 +- test/js/samples/debug-empty/expected.js | 2 +- .../debug-foo-bar-baz-things/expected.js | 2 +- test/js/samples/debug-foo/expected.js | 2 +- .../samples/deconflict-builtins/expected.js | 2 +- .../js/samples/deconflict-globals/expected.js | 2 +- .../expected.js | 2 +- .../each-block-array-literal/expected.js | 2 +- .../each-block-changed-check/expected.js | 2 +- .../each-block-keyed-animated/expected.js | 2 +- test/js/samples/each-block-keyed/expected.js | 2 +- .../js/samples/if-block-no-update/expected.js | 2 +- test/js/samples/if-block-simple/expected.js | 2 +- .../expected.js | 2 +- .../inline-style-optimized-url/expected.js | 2 +- .../inline-style-optimized/expected.js | 2 +- .../inline-style-unoptimized/expected.js | 2 +- test/js/samples/input-files/expected.js | 2 +- test/js/samples/input-range/expected.js | 2 +- .../input-without-blowback-guard/expected.js | 2 +- test/js/samples/media-bindings/expected.js | 2 +- test/js/samples/optional-chaining/expected.js | 2 +- .../expected.js | 2 +- .../expected.js | 2 +- .../samples/select-dynamic-value/expected.js | 2 +- .../samples/src-attribute-check/expected.js | 2 +- test/js/samples/title/expected.js | 2 +- test/js/samples/transition-local/expected.js | 2 +- .../transition-repeated-outro/expected.js | 2 +- .../use-elements-as-anchors/expected.js | 2 +- test/js/samples/video-bindings/expected.js | 2 +- .../samples/window-binding-scroll/expected.js | 2 +- .../component-binding-store/Input.svelte | 5 ++ .../component-binding-store/_config.js | 61 +++++++++++++++++++ .../component-binding-store/main.svelte | 18 ++++++ 45 files changed, 144 insertions(+), 48 deletions(-) create mode 100644 test/runtime/samples/component-binding-store/Input.svelte create mode 100644 test/runtime/samples/component-binding-store/_config.js create mode 100644 test/runtime/samples/component-binding-store/main.svelte diff --git a/CHANGELOG.md b/CHANGELOG.md index 61b4c36842..bd070862f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unreleased +* Prevent duplicate invalidation with certain two-way component bindings ([#3180](https://github.com/sveltejs/svelte/issues/3180), [#5117](https://github.com/sveltejs/svelte/issues/5117), [#5144](https://github.com/sveltejs/svelte/issues/5144)) * Fix reactivity when passing `$$props` to a `` ([#3364](https://github.com/sveltejs/svelte/issues/3364)) * Fix unneeded invalidation of `$$props` and `$$restProps` ([#4993](https://github.com/sveltejs/svelte/issues/4993), [#5118](https://github.com/sveltejs/svelte/issues/5118)) diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index f6ffd8f2a6..7d0dce8315 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -86,7 +86,6 @@ export default function dom( const set = (uses_props || uses_rest || writable_props.length > 0 || component.slots.size > 0) ? x` ${$$props} => { - ${(uses_props || uses_rest) && b`if (@is_empty(${$$props})) return;`} ${uses_props && renderer.invalidate('$$props', x`$$props = @assign(@assign({}, $$props), @exclude_internal_props($$new_props))`)} ${uses_rest && !uses_props && x`$$props = @assign(@assign({}, $$props), @exclude_internal_props($$new_props))`} ${uses_rest && renderer.invalidate('$$restProps', x`$$restProps = ${compute_rest}`)} @@ -421,7 +420,7 @@ export default function dom( ${component.partly_hoisted} - ${set && b`$$self.$set = ${set};`} + ${set && b`$$self.$$set = ${set};`} ${capture_state && b`$$self.$capture_state = ${capture_state};`} diff --git a/src/runtime/internal/Component.ts b/src/runtime/internal/Component.ts index c0f6facdd2..459a78031a 100644 --- a/src/runtime/internal/Component.ts +++ b/src/runtime/internal/Component.ts @@ -1,6 +1,6 @@ import { add_render_callback, flush, schedule_update, dirty_components } from './scheduler'; import { current_component, set_current_component } from './lifecycle'; -import { blank_object, is_function, run, run_all, noop } from './utils'; +import { blank_object, is_empty, is_function, run, run_all, noop } from './utils'; import { children, detach } from './dom'; import { transition_in } from './transitions'; @@ -33,6 +33,7 @@ interface T$$ { context: Map; on_mount: any[]; on_destroy: any[]; + skip_bound: boolean; } export function bind(component, name, callback) { @@ -120,7 +121,8 @@ export function init(component, options, instance, create_fragment, not_equal, p // everything else callbacks: blank_object(), - dirty + dirty, + skip_bound: false }; let ready = false; @@ -129,7 +131,7 @@ export function init(component, options, instance, create_fragment, not_equal, p ? instance(component, prop_values, (i, ret, ...rest) => { const value = rest.length ? rest[0] : ret; if ($$.ctx && not_equal($$.ctx[i], $$.ctx[i] = value)) { - if ($$.bound[i]) $$.bound[i](value); + if (!$$.skip_bound && $$.bound[i]) $$.bound[i](value); if (ready) make_dirty(component, i); } return ret; @@ -166,6 +168,7 @@ export let SvelteElement; if (typeof HTMLElement === 'function') { SvelteElement = class extends HTMLElement { $$: T$$; + $$set?: ($$props: any) => void; constructor() { super(); this.attachShadow({ mode: 'open' }); @@ -199,14 +202,19 @@ if (typeof HTMLElement === 'function') { }; } - $set() { - // overridden by instance, if it has props + $set($$props) { + if (this.$$set && !is_empty($$props)) { + this.$$.skip_bound = true; + this.$$set($$props); + this.$$.skip_bound = false; + } } }; } export class SvelteComponent { $$: T$$; + $$set?: ($$props: any) => void; $destroy() { destroy_component(this, 1); @@ -223,7 +231,11 @@ export class SvelteComponent { }; } - $set() { - // overridden by instance, if it has props + $set($$props) { + if (this.$$set && !is_empty($$props)) { + this.$$.skip_bound = true; + this.$$set($$props); + this.$$.skip_bound = false; + } } } diff --git a/test/js/samples/action-custom-event-handler/expected.js b/test/js/samples/action-custom-event-handler/expected.js index cac2f61b44..51656290d6 100644 --- a/test/js/samples/action-custom-event-handler/expected.js +++ b/test/js/samples/action-custom-event-handler/expected.js @@ -55,7 +55,7 @@ function instance($$self, $$props, $$invalidate) { let { bar } = $$props; const foo_function = () => handleFoo(bar); - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("bar" in $$props) $$invalidate(0, bar = $$props.bar); }; diff --git a/test/js/samples/bind-open/expected.js b/test/js/samples/bind-open/expected.js index 30387d505d..56ff302845 100644 --- a/test/js/samples/bind-open/expected.js +++ b/test/js/samples/bind-open/expected.js @@ -52,7 +52,7 @@ function instance($$self, $$props, $$invalidate) { $$invalidate(0, open); } - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("open" in $$props) $$invalidate(0, open = $$props.open); }; diff --git a/test/js/samples/bind-width-height/expected.js b/test/js/samples/bind-width-height/expected.js index 4848704c4b..f23c20b683 100644 --- a/test/js/samples/bind-width-height/expected.js +++ b/test/js/samples/bind-width-height/expected.js @@ -46,7 +46,7 @@ function instance($$self, $$props, $$invalidate) { $$invalidate(1, h); } - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("w" in $$props) $$invalidate(0, w = $$props.w); if ("h" in $$props) $$invalidate(1, h = $$props.h); }; diff --git a/test/js/samples/bindings-readonly-order/expected.js b/test/js/samples/bindings-readonly-order/expected.js index 0e845c65b8..78a71dcd84 100644 --- a/test/js/samples/bindings-readonly-order/expected.js +++ b/test/js/samples/bindings-readonly-order/expected.js @@ -68,7 +68,7 @@ function instance($$self, $$props, $$invalidate) { $$invalidate(0, files); } - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("files" in $$props) $$invalidate(0, files = $$props.files); }; diff --git a/test/js/samples/capture-inject-state/expected.js b/test/js/samples/capture-inject-state/expected.js index cd719ac5d2..6aa93b9c5a 100644 --- a/test/js/samples/capture-inject-state/expected.js +++ b/test/js/samples/capture-inject-state/expected.js @@ -118,7 +118,7 @@ function instance($$self, $$props, $$invalidate) { let { $$slots = {}, $$scope } = $$props; validate_slots("Component", $$slots, []); - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("prop" in $$props) $$subscribe_prop($$invalidate(0, prop = $$props.prop)); if ("alias" in $$props) $$invalidate(1, realName = $$props.alias); }; diff --git a/test/js/samples/collapses-text-around-comments/expected.js b/test/js/samples/collapses-text-around-comments/expected.js index 6fef0f9490..67335ce246 100644 --- a/test/js/samples/collapses-text-around-comments/expected.js +++ b/test/js/samples/collapses-text-around-comments/expected.js @@ -48,7 +48,7 @@ function create_fragment(ctx) { function instance($$self, $$props, $$invalidate) { let { foo = 42 } = $$props; - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("foo" in $$props) $$invalidate(0, foo = $$props.foo); }; diff --git a/test/js/samples/computed-collapsed-if/expected.js b/test/js/samples/computed-collapsed-if/expected.js index 8e5964f8a6..3e70d6a7ae 100644 --- a/test/js/samples/computed-collapsed-if/expected.js +++ b/test/js/samples/computed-collapsed-if/expected.js @@ -12,7 +12,7 @@ function instance($$self, $$props, $$invalidate) { return x * 3; } - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("x" in $$props) $$invalidate(0, x = $$props.x); }; diff --git a/test/js/samples/data-attribute/expected.js b/test/js/samples/data-attribute/expected.js index 49ad2f2626..8c30e6f6db 100644 --- a/test/js/samples/data-attribute/expected.js +++ b/test/js/samples/data-attribute/expected.js @@ -47,7 +47,7 @@ function create_fragment(ctx) { function instance($$self, $$props, $$invalidate) { let { bar } = $$props; - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("bar" in $$props) $$invalidate(0, bar = $$props.bar); }; diff --git a/test/js/samples/debug-empty/expected.js b/test/js/samples/debug-empty/expected.js index dd142adb26..6781e5333c 100644 --- a/test/js/samples/debug-empty/expected.js +++ b/test/js/samples/debug-empty/expected.js @@ -79,7 +79,7 @@ function instance($$self, $$props, $$invalidate) { let { $$slots = {}, $$scope } = $$props; validate_slots("Component", $$slots, []); - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("name" in $$props) $$invalidate(0, name = $$props.name); }; diff --git a/test/js/samples/debug-foo-bar-baz-things/expected.js b/test/js/samples/debug-foo-bar-baz-things/expected.js index 977702b99f..087d2e399d 100644 --- a/test/js/samples/debug-foo-bar-baz-things/expected.js +++ b/test/js/samples/debug-foo-bar-baz-things/expected.js @@ -183,7 +183,7 @@ function instance($$self, $$props, $$invalidate) { let { $$slots = {}, $$scope } = $$props; validate_slots("Component", $$slots, []); - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("things" in $$props) $$invalidate(0, things = $$props.things); if ("foo" in $$props) $$invalidate(1, foo = $$props.foo); if ("bar" in $$props) $$invalidate(2, bar = $$props.bar); diff --git a/test/js/samples/debug-foo/expected.js b/test/js/samples/debug-foo/expected.js index fe62ff77bf..9f12bfb807 100644 --- a/test/js/samples/debug-foo/expected.js +++ b/test/js/samples/debug-foo/expected.js @@ -175,7 +175,7 @@ function instance($$self, $$props, $$invalidate) { let { $$slots = {}, $$scope } = $$props; validate_slots("Component", $$slots, []); - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("things" in $$props) $$invalidate(0, things = $$props.things); if ("foo" in $$props) $$invalidate(1, foo = $$props.foo); }; diff --git a/test/js/samples/deconflict-builtins/expected.js b/test/js/samples/deconflict-builtins/expected.js index fb98844ef7..6bc60194aa 100644 --- a/test/js/samples/deconflict-builtins/expected.js +++ b/test/js/samples/deconflict-builtins/expected.js @@ -104,7 +104,7 @@ function create_fragment(ctx) { function instance($$self, $$props, $$invalidate) { let { createElement } = $$props; - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("createElement" in $$props) $$invalidate(0, createElement = $$props.createElement); }; diff --git a/test/js/samples/deconflict-globals/expected.js b/test/js/samples/deconflict-globals/expected.js index 7e83c21f0e..7168eba6a5 100644 --- a/test/js/samples/deconflict-globals/expected.js +++ b/test/js/samples/deconflict-globals/expected.js @@ -10,7 +10,7 @@ function instance($$self, $$props, $$invalidate) { alert(JSON.stringify(data())); }); - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("foo" in $$props) $$invalidate(0, foo = $$props.foo); }; diff --git a/test/js/samples/dev-warning-missing-data-computed/expected.js b/test/js/samples/dev-warning-missing-data-computed/expected.js index 0a50e2cd97..fd34778f8d 100644 --- a/test/js/samples/dev-warning-missing-data-computed/expected.js +++ b/test/js/samples/dev-warning-missing-data-computed/expected.js @@ -76,7 +76,7 @@ function instance($$self, $$props, $$invalidate) { let { $$slots = {}, $$scope } = $$props; validate_slots("Component", $$slots, []); - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("foo" in $$props) $$invalidate(0, foo = $$props.foo); }; diff --git a/test/js/samples/each-block-array-literal/expected.js b/test/js/samples/each-block-array-literal/expected.js index 10d835cf78..fe51ac5bc3 100644 --- a/test/js/samples/each-block-array-literal/expected.js +++ b/test/js/samples/each-block-array-literal/expected.js @@ -106,7 +106,7 @@ function instance($$self, $$props, $$invalidate) { let { d } = $$props; let { e } = $$props; - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("a" in $$props) $$invalidate(0, a = $$props.a); if ("b" in $$props) $$invalidate(1, b = $$props.b); if ("c" in $$props) $$invalidate(2, c = $$props.c); diff --git a/test/js/samples/each-block-changed-check/expected.js b/test/js/samples/each-block-changed-check/expected.js index f4f9df0de9..63bc1d8607 100644 --- a/test/js/samples/each-block-changed-check/expected.js +++ b/test/js/samples/each-block-changed-check/expected.js @@ -152,7 +152,7 @@ function instance($$self, $$props, $$invalidate) { let { time } = $$props; let { foo } = $$props; - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("comments" in $$props) $$invalidate(0, comments = $$props.comments); if ("elapsed" in $$props) $$invalidate(1, elapsed = $$props.elapsed); if ("time" in $$props) $$invalidate(2, time = $$props.time); diff --git a/test/js/samples/each-block-keyed-animated/expected.js b/test/js/samples/each-block-keyed-animated/expected.js index 7fb81c27a2..46ef63ee7f 100644 --- a/test/js/samples/each-block-keyed-animated/expected.js +++ b/test/js/samples/each-block-keyed-animated/expected.js @@ -128,7 +128,7 @@ function foo(node, animation, params) { function instance($$self, $$props, $$invalidate) { let { things } = $$props; - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("things" in $$props) $$invalidate(0, things = $$props.things); }; diff --git a/test/js/samples/each-block-keyed/expected.js b/test/js/samples/each-block-keyed/expected.js index ad8c074e99..71853cf295 100644 --- a/test/js/samples/each-block-keyed/expected.js +++ b/test/js/samples/each-block-keyed/expected.js @@ -97,7 +97,7 @@ function create_fragment(ctx) { function instance($$self, $$props, $$invalidate) { let { things } = $$props; - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("things" in $$props) $$invalidate(0, things = $$props.things); }; diff --git a/test/js/samples/if-block-no-update/expected.js b/test/js/samples/if-block-no-update/expected.js index f225c221bf..c67b33fa85 100644 --- a/test/js/samples/if-block-no-update/expected.js +++ b/test/js/samples/if-block-no-update/expected.js @@ -88,7 +88,7 @@ function create_fragment(ctx) { function instance($$self, $$props, $$invalidate) { let { foo } = $$props; - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("foo" in $$props) $$invalidate(0, foo = $$props.foo); }; diff --git a/test/js/samples/if-block-simple/expected.js b/test/js/samples/if-block-simple/expected.js index eb6c8e8949..4cdd73cddb 100644 --- a/test/js/samples/if-block-simple/expected.js +++ b/test/js/samples/if-block-simple/expected.js @@ -66,7 +66,7 @@ function create_fragment(ctx) { function instance($$self, $$props, $$invalidate) { let { foo } = $$props; - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("foo" in $$props) $$invalidate(0, foo = $$props.foo); }; diff --git a/test/js/samples/inline-style-optimized-multiple/expected.js b/test/js/samples/inline-style-optimized-multiple/expected.js index 84a38abd7b..0a9d0a1e8e 100644 --- a/test/js/samples/inline-style-optimized-multiple/expected.js +++ b/test/js/samples/inline-style-optimized-multiple/expected.js @@ -44,7 +44,7 @@ function instance($$self, $$props, $$invalidate) { let { x } = $$props; let { y } = $$props; - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("color" in $$props) $$invalidate(0, color = $$props.color); if ("x" in $$props) $$invalidate(1, x = $$props.x); if ("y" in $$props) $$invalidate(2, y = $$props.y); diff --git a/test/js/samples/inline-style-optimized-url/expected.js b/test/js/samples/inline-style-optimized-url/expected.js index 77870348a5..0debb03585 100644 --- a/test/js/samples/inline-style-optimized-url/expected.js +++ b/test/js/samples/inline-style-optimized-url/expected.js @@ -37,7 +37,7 @@ function create_fragment(ctx) { function instance($$self, $$props, $$invalidate) { let { data } = $$props; - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("data" in $$props) $$invalidate(0, data = $$props.data); }; diff --git a/test/js/samples/inline-style-optimized/expected.js b/test/js/samples/inline-style-optimized/expected.js index 5bef284f09..b7db0f1cf3 100644 --- a/test/js/samples/inline-style-optimized/expected.js +++ b/test/js/samples/inline-style-optimized/expected.js @@ -37,7 +37,7 @@ function create_fragment(ctx) { function instance($$self, $$props, $$invalidate) { let { color } = $$props; - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("color" in $$props) $$invalidate(0, color = $$props.color); }; diff --git a/test/js/samples/inline-style-unoptimized/expected.js b/test/js/samples/inline-style-unoptimized/expected.js index fdff685ead..0688f14b9b 100644 --- a/test/js/samples/inline-style-unoptimized/expected.js +++ b/test/js/samples/inline-style-unoptimized/expected.js @@ -54,7 +54,7 @@ function instance($$self, $$props, $$invalidate) { let { key } = $$props; let { value } = $$props; - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("style" in $$props) $$invalidate(0, style = $$props.style); if ("key" in $$props) $$invalidate(1, key = $$props.key); if ("value" in $$props) $$invalidate(2, value = $$props.value); diff --git a/test/js/samples/input-files/expected.js b/test/js/samples/input-files/expected.js index 0069c2e5f8..8adc7443f5 100644 --- a/test/js/samples/input-files/expected.js +++ b/test/js/samples/input-files/expected.js @@ -49,7 +49,7 @@ function instance($$self, $$props, $$invalidate) { $$invalidate(0, files); } - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("files" in $$props) $$invalidate(0, files = $$props.files); }; diff --git a/test/js/samples/input-range/expected.js b/test/js/samples/input-range/expected.js index 770baa29ed..a855ca3653 100644 --- a/test/js/samples/input-range/expected.js +++ b/test/js/samples/input-range/expected.js @@ -60,7 +60,7 @@ function instance($$self, $$props, $$invalidate) { $$invalidate(0, value); } - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("value" in $$props) $$invalidate(0, value = $$props.value); }; diff --git a/test/js/samples/input-without-blowback-guard/expected.js b/test/js/samples/input-without-blowback-guard/expected.js index f19f74dc1e..6c5b215623 100644 --- a/test/js/samples/input-without-blowback-guard/expected.js +++ b/test/js/samples/input-without-blowback-guard/expected.js @@ -53,7 +53,7 @@ function instance($$self, $$props, $$invalidate) { $$invalidate(0, foo); } - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("foo" in $$props) $$invalidate(0, foo = $$props.foo); }; diff --git a/test/js/samples/media-bindings/expected.js b/test/js/samples/media-bindings/expected.js index bcbc0647b8..867d4a7dad 100644 --- a/test/js/samples/media-bindings/expected.js +++ b/test/js/samples/media-bindings/expected.js @@ -173,7 +173,7 @@ function instance($$self, $$props, $$invalidate) { $$invalidate(10, ended); } - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("buffered" in $$props) $$invalidate(0, buffered = $$props.buffered); if ("seekable" in $$props) $$invalidate(1, seekable = $$props.seekable); if ("played" in $$props) $$invalidate(2, played = $$props.played); diff --git a/test/js/samples/optional-chaining/expected.js b/test/js/samples/optional-chaining/expected.js index a28dc129aa..8aa94796c1 100644 --- a/test/js/samples/optional-chaining/expected.js +++ b/test/js/samples/optional-chaining/expected.js @@ -167,7 +167,7 @@ function instance($$self, $$props, $$invalidate) { let { f } = $$props; let Component; - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("a" in $$props) $$invalidate(0, a = $$props.a); if ("b" in $$props) $$invalidate(1, b = $$props.b); if ("c" in $$props) $$invalidate(2, c = $$props.c); diff --git a/test/js/samples/reactive-values-non-topologically-ordered/expected.js b/test/js/samples/reactive-values-non-topologically-ordered/expected.js index 3d266f10ac..15290496d5 100644 --- a/test/js/samples/reactive-values-non-topologically-ordered/expected.js +++ b/test/js/samples/reactive-values-non-topologically-ordered/expected.js @@ -6,7 +6,7 @@ function instance($$self, $$props, $$invalidate) { let a; let b; - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("x" in $$props) $$invalidate(0, x = $$props.x); }; diff --git a/test/js/samples/reactive-values-non-writable-dependencies/expected.js b/test/js/samples/reactive-values-non-writable-dependencies/expected.js index 38bd356d85..5196a770d9 100644 --- a/test/js/samples/reactive-values-non-writable-dependencies/expected.js +++ b/test/js/samples/reactive-values-non-writable-dependencies/expected.js @@ -5,7 +5,7 @@ function instance($$self, $$props, $$invalidate) { let { a = 1 } = $$props; let { b = 2 } = $$props; - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("a" in $$props) $$invalidate(0, a = $$props.a); if ("b" in $$props) $$invalidate(1, b = $$props.b); }; diff --git a/test/js/samples/select-dynamic-value/expected.js b/test/js/samples/select-dynamic-value/expected.js index aa4e5004fd..8777cd2600 100644 --- a/test/js/samples/select-dynamic-value/expected.js +++ b/test/js/samples/select-dynamic-value/expected.js @@ -50,7 +50,7 @@ function create_fragment(ctx) { function instance($$self, $$props, $$invalidate) { let { current } = $$props; - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("current" in $$props) $$invalidate(0, current = $$props.current); }; diff --git a/test/js/samples/src-attribute-check/expected.js b/test/js/samples/src-attribute-check/expected.js index e03b3a6ba7..93638edfb4 100644 --- a/test/js/samples/src-attribute-check/expected.js +++ b/test/js/samples/src-attribute-check/expected.js @@ -67,7 +67,7 @@ function instance($$self, $$props, $$invalidate) { let { url } = $$props; let { slug } = $$props; - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("url" in $$props) $$invalidate(0, url = $$props.url); if ("slug" in $$props) $$invalidate(1, slug = $$props.slug); }; diff --git a/test/js/samples/title/expected.js b/test/js/samples/title/expected.js index d4e7e1a584..b10f569759 100644 --- a/test/js/samples/title/expected.js +++ b/test/js/samples/title/expected.js @@ -22,7 +22,7 @@ function create_fragment(ctx) { function instance($$self, $$props, $$invalidate) { let { custom } = $$props; - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("custom" in $$props) $$invalidate(0, custom = $$props.custom); }; diff --git a/test/js/samples/transition-local/expected.js b/test/js/samples/transition-local/expected.js index 25a03f026f..ea3d9db3d7 100644 --- a/test/js/samples/transition-local/expected.js +++ b/test/js/samples/transition-local/expected.js @@ -124,7 +124,7 @@ function instance($$self, $$props, $$invalidate) { let { x } = $$props; let { y } = $$props; - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("x" in $$props) $$invalidate(0, x = $$props.x); if ("y" in $$props) $$invalidate(1, y = $$props.y); }; diff --git a/test/js/samples/transition-repeated-outro/expected.js b/test/js/samples/transition-repeated-outro/expected.js index 1f76a93666..12483ab91a 100644 --- a/test/js/samples/transition-repeated-outro/expected.js +++ b/test/js/samples/transition-repeated-outro/expected.js @@ -102,7 +102,7 @@ function create_fragment(ctx) { function instance($$self, $$props, $$invalidate) { let { num = 1 } = $$props; - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("num" in $$props) $$invalidate(0, num = $$props.num); }; diff --git a/test/js/samples/use-elements-as-anchors/expected.js b/test/js/samples/use-elements-as-anchors/expected.js index 5be8808edb..d07411518e 100644 --- a/test/js/samples/use-elements-as-anchors/expected.js +++ b/test/js/samples/use-elements-as-anchors/expected.js @@ -243,7 +243,7 @@ function instance($$self, $$props, $$invalidate) { let { d } = $$props; let { e } = $$props; - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("a" in $$props) $$invalidate(0, a = $$props.a); if ("b" in $$props) $$invalidate(1, b = $$props.b); if ("c" in $$props) $$invalidate(2, c = $$props.c); diff --git a/test/js/samples/video-bindings/expected.js b/test/js/samples/video-bindings/expected.js index d3920ef8c2..8afa670bbb 100644 --- a/test/js/samples/video-bindings/expected.js +++ b/test/js/samples/video-bindings/expected.js @@ -93,7 +93,7 @@ function instance($$self, $$props, $$invalidate) { $$invalidate(3, offsetWidth); } - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("currentTime" in $$props) $$invalidate(0, currentTime = $$props.currentTime); if ("videoHeight" in $$props) $$invalidate(1, videoHeight = $$props.videoHeight); if ("videoWidth" in $$props) $$invalidate(2, videoWidth = $$props.videoWidth); diff --git a/test/js/samples/window-binding-scroll/expected.js b/test/js/samples/window-binding-scroll/expected.js index 45d992c721..09a4d3737d 100644 --- a/test/js/samples/window-binding-scroll/expected.js +++ b/test/js/samples/window-binding-scroll/expected.js @@ -78,7 +78,7 @@ function instance($$self, $$props, $$invalidate) { $$invalidate(0, y = window.pageYOffset) } - $$self.$set = $$props => { + $$self.$$set = $$props => { if ("y" in $$props) $$invalidate(0, y = $$props.y); }; diff --git a/test/runtime/samples/component-binding-store/Input.svelte b/test/runtime/samples/component-binding-store/Input.svelte new file mode 100644 index 0000000000..792104bec8 --- /dev/null +++ b/test/runtime/samples/component-binding-store/Input.svelte @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/test/runtime/samples/component-binding-store/_config.js b/test/runtime/samples/component-binding-store/_config.js new file mode 100644 index 0000000000..4dec41459f --- /dev/null +++ b/test/runtime/samples/component-binding-store/_config.js @@ -0,0 +1,61 @@ +export default { + html: ` + + +
+ `, + + async test({ assert, component, target, window }) { + let count = 0; + component.callback = () => { + count++; + }; + + const [input1, input2] = target.querySelectorAll("input"); + + input1.value = "1"; + await input1.dispatchEvent(new window.Event("input")); + + assert.htmlEqual( + target.innerHTML, + ` + + +
1
+ ` + ); + assert.equal(input1.value, "1"); + assert.equal(input2.value, "1"); + assert.equal(count, 1); + + input2.value = "123"; + await input2.dispatchEvent(new window.Event("input")); + + assert.htmlEqual( + target.innerHTML, + ` + + +
123
+ ` + ); + assert.equal(input1.value, "123"); + assert.equal(input2.value, "123"); + assert.equal(count, 2); + + input1.value = "456"; + await input1.dispatchEvent(new window.Event("input")); + + assert.htmlEqual( + target.innerHTML, + ` + + +
456
+ ` + ); + assert.equal(input1.value, "456"); + assert.equal(input2.value, "456"); + assert.equal(count, 3); + }, +}; diff --git a/test/runtime/samples/component-binding-store/main.svelte b/test/runtime/samples/component-binding-store/main.svelte new file mode 100644 index 0000000000..dba08e5276 --- /dev/null +++ b/test/runtime/samples/component-binding-store/main.svelte @@ -0,0 +1,18 @@ + + + + + + +
{$value.value}
\ No newline at end of file From 3d81b8cdf20d8f5c009541d5d3cf28e376cb0785 Mon Sep 17 00:00:00 2001 From: Benjamin Schachter Date: Mon, 20 Jul 2020 07:32:10 -0400 Subject: [PATCH 11/21] site: explain how to use `site-kit` and `site-repl` (#5163) Co-authored-by: Luca Bonavita --- site/README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/site/README.md b/site/README.md index 64ae22f9a8..892b8e1249 100644 --- a/site/README.md +++ b/site/README.md @@ -53,6 +53,26 @@ To build the website, run `npm run sapper`. The output can be found in `__sapper Tests can be run using `npm run test`. + +## Linking `@sveltejs/site-kit` and `@sveltejs/site-repl` + +This site depends on `@sveltejs/site-kit`, a collection of styles, components and icons used in common by *.svelte.dev websites, and `@sveltejs/site-repl`. + +In order to work on features that depend on those packages, you need to [link](https://docs.npmjs.com/cli/link) their repositories: + +- `cd ` +- `git clone https://github.com/sveltejs/site-kit` +- `git clone https://github.com/sveltejs/svelte-repl` +- `cd /site-kit` +- `npm link` +- `cd /svelte-repl` +- `npm link` +- `cd /site` +- `npm link @sveltejs/site-kit` +- `npm link @sveltejs/svelte-repl` + + + ## Translating the API docs Anchors are automatically generated using headings in the documentation and by default (for the english language) they are latinised to make sure the URL is always conforming to RFC3986. From 453c7270236aef9b6bab92f47124bf6d182fd484 Mon Sep 17 00:00:00 2001 From: Luca Bonavita Date: Tue, 21 Jul 2020 15:05:02 +0100 Subject: [PATCH 12/21] site: rephrase to clarify that actions can have just one parameter. Closes #5173 --- site/content/docs/02-template-syntax.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/content/docs/02-template-syntax.md b/site/content/docs/02-template-syntax.md index 070dc46687..6d0847eb41 100644 --- a/site/content/docs/02-template-syntax.md +++ b/site/content/docs/02-template-syntax.md @@ -773,7 +773,7 @@ Actions are functions that are called when an element is created. They can retur --- -An action can have parameters. If the returned value has an `update` method, it will be called whenever those parameters change, immediately after Svelte has applied updates to the markup. +An action can have a parameter. If the returned value has an `update` method, it will be called whenever that parameter changes, immediately after Svelte has applied updates to the markup. > Don't worry about the fact that we're redeclaring the `foo` function for every component instance — Svelte will hoist any functions that don't depend on local state out of the component definition. From b1c18c70dbdfd88c9dccfa67abad653a21c3cdb2 Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Tue, 21 Jul 2020 10:28:26 -0400 Subject: [PATCH 13/21] Initial stab at a TypeScript blog post (#5101) * Initial stab at a blog post * Update site/content/blog/2020-06-04-svelte-and-typescript.md Co-authored-by: pngwn * Update 2020-06-04-svelte-and-typescript.md * Apply suggestions from code review Co-authored-by: halfnelson Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com> * Tighten the post * Fix degit sample * Feedback * More feeedback * Handle feedback * Handle all the feedback in the PR * Add a note about the should work * Change date * code style consistency, fix syntax error Co-authored-by: pngwn Co-authored-by: halfnelson Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com> Co-authored-by: Rich Harris --- .../blog/2020-07-17-svelte-and-typescript.md | 141 ++++++++++++++++++ site/static/media/svelte-ts.png | Bin 0 -> 189664 bytes 2 files changed, 141 insertions(+) create mode 100644 site/content/blog/2020-07-17-svelte-and-typescript.md create mode 100644 site/static/media/svelte-ts.png diff --git a/site/content/blog/2020-07-17-svelte-and-typescript.md b/site/content/blog/2020-07-17-svelte-and-typescript.md new file mode 100644 index 0000000000..75f7cd250c --- /dev/null +++ b/site/content/blog/2020-07-17-svelte-and-typescript.md @@ -0,0 +1,141 @@ +--- +title: Svelte <3 TypeScript +description: Typernetically enhanced web apps +author: Orta Therox +authorURL: https://twitter.com/orta +--- + +It's been by far the most requested feature for a while, and it's finally here: Svelte officially supports TypeScript. + +We think it'll give you a much nicer development experience — one that also scales beautifully to larger Svelte code bases — regardless of whether you use TypeScript or JavaScript. + +
+ Screenshot of TypeScript in Svelte +
Image of TypeScript + Svelte in VS Code (theme is Kary Pro.)
+
+ + +## Try it now + +You can start a new Svelte TypeScript project using the [normal template](https://github.com/sveltejs/template) and by running `node scripts/setupTypeScript.js` before you do anything else: + +```bash +npx degit sveltejs/template svelte-typescript-app +cd svelte-typescript-app +node scripts/setupTypeScript.js +``` + +If you're a VS Code user, make sure you're using the (new) [official extension](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode), which replaces the popular extension by James Birtles. +Later in this blog post, we'll detail the individual steps involved in using TypeScript in an existing Svelte project. + +## What does it mean to support TypeScript in Svelte? + +TypeScript support in Svelte has been possible for a long time, but you had to mix a lot of disparate tools together and each project ran independently. Today, nearly all of these tools live under the Svelte organization and are maintained by a set of people who take responsibility over the whole pipeline and have common goals. + +A week before COVID was declared a pandemic, [I pitched a consolidation](https://github.com/sveltejs/svelte/issues/4518) of the best Svelte tools and ideas from similar dev-ecosystems and provided a set of steps to get first class TypeScript support. Since then, many people have pitched in and written the code to get us there. + +When we say that Svelte now supports TypeScript, we mean a few different things: + +* You can use TypeScript inside your ` + +{#each Object.keys(list) as key} + {#each values as value} + + {/each} +

{list[key].join(', ')}

+{/each} From 0b09c70c7308a76ac8b175fd3d37133a431f83c2 Mon Sep 17 00:00:00 2001 From: "M. Habib Rosyad" Date: Wed, 29 Jul 2020 01:48:16 +0700 Subject: [PATCH 19/21] site: fix escaping in RSS feed (#5214) --- site/src/routes/blog/rss.xml.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/site/src/routes/blog/rss.xml.js b/site/src/routes/blog/rss.xml.js index 974806ad44..544474b274 100644 --- a/site/src/routes/blog/rss.xml.js +++ b/site/src/routes/blog/rss.xml.js @@ -8,6 +8,18 @@ function formatPubdate(str) { return `${d} ${months[+m]} ${y} 12:00 +0000`; } +function escapeHTML(html) { + const chars = { + '"' : 'quot', + "'": '#39', + '&': 'amp', + '<' : 'lt', + '>' : 'gt' + }; + + return html.replace(/["'&<>]/g, c => `&${chars[c]};`); +} + const rss = ` @@ -23,9 +35,9 @@ const rss = ` ${get_posts().filter(post => !post.metadata.draft).map(post => ` - ${post.metadata.title} + ${escapeHTML(post.metadata.title)} https://svelte.dev/blog/${post.slug} - ${post.metadata.description} + ${escapeHTML(post.metadata.description)} ${formatPubdate(post.metadata.pubdate)} `).join('')} From 1955089a459003557a7131c829f1721b04979ec0 Mon Sep 17 00:00:00 2001 From: Conduitry Date: Tue, 28 Jul 2020 16:39:17 -0400 Subject: [PATCH 20/21] site: use relative link to tutorial in FAQ entry --- site/content/faq/100-im-new-to-svelte.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/content/faq/100-im-new-to-svelte.md b/site/content/faq/100-im-new-to-svelte.md index 18e4b6742f..0f1df9cff5 100644 --- a/site/content/faq/100-im-new-to-svelte.md +++ b/site/content/faq/100-im-new-to-svelte.md @@ -2,6 +2,6 @@ question: I'm new to Svelte. Where should I start? --- -We think the best way to get started is playing through the interactive [Tutorial](https://svelte.dev/tutorial). Each step there is mainly focused on one specific aspect and is easy to follow. You'll be editing and running real Svelte components right in your browser. +We think the best way to get started is playing through the interactive [Tutorial](tutorial). Each step there is mainly focused on one specific aspect and is easy to follow. You'll be editing and running real Svelte components right in your browser. Five to ten minutes should be enough to get you up and running. An hour and a half should get you through the entire tutorial. \ No newline at end of file From c906e21f7f81f90aa01e7e3864c897484847bb40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo?= <62244135+joaopaulobdac@users.noreply.github.com> Date: Thu, 30 Jul 2020 12:43:45 -0300 Subject: [PATCH 21/21] site: clarify file -> module in tutorial (#5171) --- .../tutorial/16-special-elements/01-svelte-self/text.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/content/tutorial/16-special-elements/01-svelte-self/text.md b/site/content/tutorial/16-special-elements/01-svelte-self/text.md index 773dded83e..c7946f6c6d 100644 --- a/site/content/tutorial/16-special-elements/01-svelte-self/text.md +++ b/site/content/tutorial/16-special-elements/01-svelte-self/text.md @@ -14,7 +14,7 @@ It's useful for things like this folder tree view, where folders can contain *ot {/if} ``` -...but that's impossible, because a file can't import itself. Instead, we use ``: +...but that's impossible, because a module can't import itself. Instead, we use ``: ```html {#if file.type === 'folder'} @@ -22,4 +22,4 @@ It's useful for things like this folder tree view, where folders can contain *ot {:else} {/if} -``` \ No newline at end of file +```