From 5c6730e3827e034bb8b2ec82b99725b524a40bd5 Mon Sep 17 00:00:00 2001 From: Stanislav Lashmanov Date: Tue, 14 Jul 2020 20:27:42 +0300 Subject: [PATCH 01/32] 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 fd0b47d0daa69d221f9d8451f41e73407bdfbd08 Mon Sep 17 00:00:00 2001 From: Lev Maximov Date: Wed, 15 Jul 2020 03:13:19 +0700 Subject: [PATCH 02/32] 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 d472bd2f5e91699f4e832b6b74bf84846c4d2cfc Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Wed, 15 Jul 2020 05:32:24 +0800 Subject: [PATCH 03/32] 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 b54538e44faf09b771ac12a93ac5877091ba4888 Mon Sep 17 00:00:00 2001 From: Wolfr Date: Fri, 17 Jul 2020 12:54:41 +0200 Subject: [PATCH 04/32] 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 8096bbd4a098eca908ef59a025895feb8d300a14 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 05/32] 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 5b80874cd4a9452793f706a316c970de5d059b35 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 06/32] 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 ec0f79c5af3113bedf0a5e9ae1f5f521328fcd30 Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Sat, 18 Jul 2020 04:12:26 +0800 Subject: [PATCH 07/32] 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 25e9e684f6906bf22b86f36535880f7583dceba5 Mon Sep 17 00:00:00 2001 From: Benjamin Schachter Date: Mon, 20 Jul 2020 07:32:10 -0400 Subject: [PATCH 08/32] 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 c31a4b56d04fbcd482e9cf899df4a542e2681de3 Mon Sep 17 00:00:00 2001 From: Luca Bonavita Date: Tue, 21 Jul 2020 15:05:02 +0100 Subject: [PATCH 09/32] 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 f6152002eb828fdc433e162bbad0c143a979c6c6 Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Tue, 21 Jul 2020 10:28:26 -0400 Subject: [PATCH 10/32] 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 1f87f5fb2043522b5889e06ced6a0cf7b02c1e25 Mon Sep 17 00:00:00 2001 From: "M. Habib Rosyad" Date: Wed, 29 Jul 2020 01:48:16 +0700 Subject: [PATCH 16/32] 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 f4f16da455952cb0b630f7494a0bbc4f4d4a4b4b Mon Sep 17 00:00:00 2001 From: Conduitry Date: Tue, 28 Jul 2020 16:39:17 -0400 Subject: [PATCH 17/32] 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 a0ed7040f1daa9d0d4d984ab7737ddce3755bf65 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 18/32] 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 +``` From 231e4a0b3c8887ae9c76e5fa03b00e2e97704a1a Mon Sep 17 00:00:00 2001 From: Charles Rosaaen Date: Mon, 3 Aug 2020 12:48:35 -0700 Subject: [PATCH 19/32] site: update link in blog for SCode extension (#5232) --- site/content/blog/2019-04-16-svelte-for-new-developers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 fd7a88e6f1..921e699842 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 @@ -51,7 +51,7 @@ Once installed, you'll have access to three new commands: ## Installing a text editor -To write code, you need a good editor. The most popular choice is [Visual Studio Code](https://code.visualstudio.com/) or VSCode, and justifiably so — it's well-designed and fully-featured, and has a wealth of extensions ([including one for Svelte](https://marketplace.visualstudio.com/items?itemName=JamesBirtles.svelte-vscode), which provides syntax highlighting and diagnostic messages when you're writing components). +To write code, you need a good editor. The most popular choice is [Visual Studio Code](https://code.visualstudio.com/) or VSCode, and justifiably so — it's well-designed and fully-featured, and has a wealth of extensions ([including one for Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode), which provides syntax highlighting and diagnostic messages when you're writing components). ## Creating a project From d81cb83ae00162351c7b902237d0412a8d6a7ba0 Mon Sep 17 00:00:00 2001 From: pngwn Date: Wed, 5 Aug 2020 14:29:26 +0100 Subject: [PATCH 20/32] Add type param to setContext and getContext (#5224) --- src/runtime/internal/lifecycle.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/internal/lifecycle.ts b/src/runtime/internal/lifecycle.ts index a8e37e9632..34d52672a2 100644 --- a/src/runtime/internal/lifecycle.ts +++ b/src/runtime/internal/lifecycle.ts @@ -44,11 +44,11 @@ export function createEventDispatcher() { }; } -export function setContext(key, context) { +export function setContext(key, context: T) { get_current_component().$$.context.set(key, context); } -export function getContext(key) { +export function getContext(key): T { return get_current_component().$$.context.get(key); } From fdf3ab88be411471422abdca40bdbac233bf5391 Mon Sep 17 00:00:00 2001 From: Carlos Roso Date: Wed, 5 Aug 2020 10:41:54 -0500 Subject: [PATCH 21/32] Fix transitions for each-else blocks (#5179) Co-authored-by: khang8591 --- .../compile/render_dom/wrappers/EachBlock.ts | 21 ++++++-- .../_config.js | 54 +++++++++++++++++++ .../main.svelte | 27 ++++++++++ .../_config.js | 22 ++++++++ .../main.svelte | 18 +++++++ .../_config.js | 20 +++++++ .../main.svelte | 18 +++++++ 7 files changed, 176 insertions(+), 4 deletions(-) create mode 100644 test/runtime/samples/transition-js-each-else-block-intro-outro/_config.js create mode 100644 test/runtime/samples/transition-js-each-else-block-intro-outro/main.svelte create mode 100644 test/runtime/samples/transition-js-each-else-block-intro/_config.js create mode 100644 test/runtime/samples/transition-js-each-else-block-intro/main.svelte create mode 100644 test/runtime/samples/transition-js-each-else-block-outro/_config.js create mode 100644 test/runtime/samples/transition-js-each-else-block-outro/main.svelte diff --git a/src/compiler/compile/render_dom/wrappers/EachBlock.ts b/src/compiler/compile/render_dom/wrappers/EachBlock.ts index bd981a0603..126b114487 100644 --- a/src/compiler/compile/render_dom/wrappers/EachBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/EachBlock.ts @@ -298,6 +298,19 @@ export default class EachBlockWrapper extends Wrapper { } `); + const has_transitions = !!(this.else.block.has_intro_method || this.else.block.has_outro_method); + + const destroy_block_else = this.else.block.has_outro_method + ? b` + @group_outros(); + @transition_out(${each_block_else}, 1, 1, () => { + ${each_block_else} = null; + }); + @check_outros();` + : b` + ${each_block_else}.d(1); + ${each_block_else} = null;`; + if (this.else.block.has_update_method) { this.updates.push(b` if (!${this.vars.data_length} && ${each_block_else}) { @@ -305,22 +318,22 @@ export default class EachBlockWrapper extends Wrapper { } else if (!${this.vars.data_length}) { ${each_block_else} = ${this.else.block.name}(#ctx); ${each_block_else}.c(); + ${has_transitions && b`@transition_in(${each_block_else}, 1);`} ${each_block_else}.m(${update_mount_node}, ${update_anchor_node}); } else if (${each_block_else}) { - ${each_block_else}.d(1); - ${each_block_else} = null; + ${destroy_block_else}; } `); } else { this.updates.push(b` if (${this.vars.data_length}) { if (${each_block_else}) { - ${each_block_else}.d(1); - ${each_block_else} = null; + ${destroy_block_else}; } } else if (!${each_block_else}) { ${each_block_else} = ${this.else.block.name}(#ctx); ${each_block_else}.c(); + ${has_transitions && b`@transition_in(${each_block_else}, 1);`} ${each_block_else}.m(${update_mount_node}, ${update_anchor_node}); } `); diff --git a/test/runtime/samples/transition-js-each-else-block-intro-outro/_config.js b/test/runtime/samples/transition-js-each-else-block-intro-outro/_config.js new file mode 100644 index 0000000000..13d0cf0b23 --- /dev/null +++ b/test/runtime/samples/transition-js-each-else-block-intro-outro/_config.js @@ -0,0 +1,54 @@ +export default { + props: { + things: ['a', 'b', 'c'] + }, + + test({ assert, component, target, window, raf }) { + component.things = []; + let div = target.querySelector('div'); + assert.equal(div.foo, 0); + + raf.tick(200); + assert.equal(div.foo, 0.5); + + raf.tick(300); + assert.equal(div.foo, 0.75); + + raf.tick(400); + assert.equal(div.foo, 1); + + raf.tick(600); + component.things = ['a', 'b', 'c']; + + raf.tick(700); + assert.equal(div.foo, 1); + assert.equal(div.bar, 0.75); + + raf.tick(800); + assert.equal(div.foo, 1); + assert.equal(div.bar, 0.5); + + raf.tick(900); + assert.equal(div.foo, 1); + assert.equal(div.bar, 0.25); + + // test outro before intro complete + raf.tick(1000); + component.things = []; + div = target.querySelector('div'); + + raf.tick(1200); + assert.equal(div.foo, 0.5); + + component.things = ['a', 'b', 'c']; + raf.tick(1300); + assert.equal(div.foo, 0.75); + assert.equal(div.bar, 0.75); + + raf.tick(1400); + assert.equal(div.foo, 1); + assert.equal(div.bar, 0.5); + + raf.tick(2000); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/transition-js-each-else-block-intro-outro/main.svelte b/test/runtime/samples/transition-js-each-else-block-intro-outro/main.svelte new file mode 100644 index 0000000000..1691e77f52 --- /dev/null +++ b/test/runtime/samples/transition-js-each-else-block-intro-outro/main.svelte @@ -0,0 +1,27 @@ + + +{#each things as thing} +

{thing}

+{:else} +
else
+{/each} \ No newline at end of file diff --git a/test/runtime/samples/transition-js-each-else-block-intro/_config.js b/test/runtime/samples/transition-js-each-else-block-intro/_config.js new file mode 100644 index 0000000000..f061e312ff --- /dev/null +++ b/test/runtime/samples/transition-js-each-else-block-intro/_config.js @@ -0,0 +1,22 @@ +export default { + props: { + things: ['a', 'b', 'c'] + }, + + test({ assert, component, target, window, raf }) { + component.things = []; + const div = target.querySelector('div'); + assert.equal(div.foo, 0); + + raf.tick(200); + assert.equal(div.foo, 0.5); + + raf.tick(300); + assert.equal(div.foo, 0.75); + + raf.tick(400); + assert.equal(div.foo, 1); + + raf.tick(500); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/transition-js-each-else-block-intro/main.svelte b/test/runtime/samples/transition-js-each-else-block-intro/main.svelte new file mode 100644 index 0000000000..bda8746c46 --- /dev/null +++ b/test/runtime/samples/transition-js-each-else-block-intro/main.svelte @@ -0,0 +1,18 @@ + + +{#each things as thing} +

{thing}

+{:else} +
else
+{/each} \ No newline at end of file diff --git a/test/runtime/samples/transition-js-each-else-block-outro/_config.js b/test/runtime/samples/transition-js-each-else-block-outro/_config.js new file mode 100644 index 0000000000..863753b34a --- /dev/null +++ b/test/runtime/samples/transition-js-each-else-block-outro/_config.js @@ -0,0 +1,20 @@ +export default { + props: { + things: [] + }, + test({ assert, component, target, window, raf }) { + const div = target.querySelector('div'); + component.things = ['a', 'b', 'c']; + + raf.tick(200); + assert.equal(div.foo, 0.5); + + raf.tick(300); + assert.equal(div.foo, 0.25); + + raf.tick(400); + assert.equal(div.foo, 0); + + raf.tick(500); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/transition-js-each-else-block-outro/main.svelte b/test/runtime/samples/transition-js-each-else-block-outro/main.svelte new file mode 100644 index 0000000000..246c146127 --- /dev/null +++ b/test/runtime/samples/transition-js-each-else-block-outro/main.svelte @@ -0,0 +1,18 @@ + + +{#each things as thing} +

{thing}

+{:else} +
else
+{/each} \ No newline at end of file From f0d586f4a400edaf59d52601f987283ca76be387 Mon Sep 17 00:00:00 2001 From: Conduitry Date: Wed, 5 Aug 2020 11:44:32 -0400 Subject: [PATCH 22/32] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index da084600b7..2c276db868 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * 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 transitions on `{#each}` `{:else}` ([#4970](https://github.com/sveltejs/svelte/issues/4970)) * Fix unneeded invalidation of `$$props` and `$$restProps` ([#4993](https://github.com/sveltejs/svelte/issues/4993), [#5118](https://github.com/sveltejs/svelte/issues/5118)) * Provide better compiler error message when mismatched tags are due to autoclosing of tags ([#5049](https://github.com/sveltejs/svelte/issues/5049)) * Fix `bind:group` when using contextual reference ([#5174](https://github.com/sveltejs/svelte/issues/5174)) From 62ab75e365c8185b3a6cb8a3f3e91c64908778b3 Mon Sep 17 00:00:00 2001 From: Bassam Ismail Date: Wed, 5 Aug 2020 21:27:20 +0530 Subject: [PATCH 23/32] add a11y-label-has-associated-control check (#5074) --- src/compiler/compile/nodes/Element.ts | 21 ++++++++++++ .../input.svelte | 6 ++++ .../warnings.json | 32 +++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 test/validator/samples/a11y-label-has-associated-control/input.svelte create mode 100644 test/validator/samples/a11y-label-has-associated-control/warnings.json diff --git a/src/compiler/compile/nodes/Element.ts b/src/compiler/compile/nodes/Element.ts index 7a70e603a7..ffcf0e51f2 100644 --- a/src/compiler/compile/nodes/Element.ts +++ b/src/compiler/compile/nodes/Element.ts @@ -61,6 +61,17 @@ const a11y_no_onchange = new Set([ 'option' ]); +const a11y_labelable = new Set([ + "button", + "input", + "keygen", + "meter", + "output", + "progress", + "select", + "textarea" +]); + const invisible_elements = new Set(['meta', 'html', 'script', 'style']); const valid_modifiers = new Set([ @@ -507,6 +518,16 @@ export default class Element extends Node { } } + if (this.name === 'label') { + const has_input_child = this.children.some(i => (i instanceof Element && a11y_labelable.has(i.name) )); + if (!attribute_map.has('for') && !has_input_child) { + component.warn(this, { + code: `a11y-label-has-associated-control`, + message: `A11y: A form label must be associated with a control.` + }); + } + } + if (a11y_no_onchange.has(this.name)) { if (handlers_map.has('change') && !handlers_map.has('blur')) { component.warn(this, { diff --git a/test/validator/samples/a11y-label-has-associated-control/input.svelte b/test/validator/samples/a11y-label-has-associated-control/input.svelte new file mode 100644 index 0000000000..43304689dc --- /dev/null +++ b/test/validator/samples/a11y-label-has-associated-control/input.svelte @@ -0,0 +1,6 @@ + + + + + + diff --git a/test/validator/samples/a11y-label-has-associated-control/warnings.json b/test/validator/samples/a11y-label-has-associated-control/warnings.json new file mode 100644 index 0000000000..b70a1a47de --- /dev/null +++ b/test/validator/samples/a11y-label-has-associated-control/warnings.json @@ -0,0 +1,32 @@ +[ + { + "code": "a11y-label-has-associated-control", + "end": { + "character": 16, + "column": 16, + "line": 1 + }, + "message": "A11y: A form label must be associated with a control.", + "pos": 0, + "start": { + "character": 0, + "column": 0, + "line": 1 + } + }, + { + "code": "a11y-label-has-associated-control", + "end": { + "character": 149, + "column": 30, + "line": 6 + }, + "message": "A11y: A form label must be associated with a control.", + "pos": 119, + "start": { + "character": 119, + "column": 0, + "line": 6 + } + } +] From 308f3c284dfb4ac86e16475798a77dc2f5dc930b Mon Sep 17 00:00:00 2001 From: Conduitry Date: Wed, 5 Aug 2020 11:58:38 -0400 Subject: [PATCH 24/32] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c276db868..ac39b41ee3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ * Fix transitions on `{#each}` `{:else}` ([#4970](https://github.com/sveltejs/svelte/issues/4970)) * Fix unneeded invalidation of `$$props` and `$$restProps` ([#4993](https://github.com/sveltejs/svelte/issues/4993), [#5118](https://github.com/sveltejs/svelte/issues/5118)) * Provide better compiler error message when mismatched tags are due to autoclosing of tags ([#5049](https://github.com/sveltejs/svelte/issues/5049)) +* Add `a11y-label-has-associated-control` warning ([#5074](https://github.com/sveltejs/svelte/pull/5074)) * Fix `bind:group` when using contextual reference ([#5174](https://github.com/sveltejs/svelte/issues/5174)) ## 3.24.0 From fb51dd8f072468aa81052e123d8fb6b2193d7489 Mon Sep 17 00:00:00 2001 From: Bassam Ismail Date: Wed, 5 Aug 2020 21:51:44 +0530 Subject: [PATCH 25/32] add a11y-media-has-caption check (#5075) --- src/compiler/compile/nodes/Element.ts | 19 +++++++++++ .../expected.html | 4 +-- .../input.svelte | 6 ++-- .../a11y-media-has-caption/input.svelte | 4 +++ .../a11y-media-has-caption/warnings.json | 32 +++++++++++++++++++ 5 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 test/validator/samples/a11y-media-has-caption/input.svelte create mode 100644 test/validator/samples/a11y-media-has-caption/warnings.json diff --git a/src/compiler/compile/nodes/Element.ts b/src/compiler/compile/nodes/Element.ts index ffcf0e51f2..145866cf4f 100644 --- a/src/compiler/compile/nodes/Element.ts +++ b/src/compiler/compile/nodes/Element.ts @@ -528,6 +528,25 @@ export default class Element extends Node { } } + if (this.is_media_node()) { + if (attribute_map.has('muted')) { + return; + } + + let has_caption; + const track = this.children.find((i: Element) => i.name === 'track'); + if (track) { + has_caption = track.attributes.find(a => a.name === 'kind' && a.get_static_value() === 'captions'); + } + + if (!has_caption) { + component.warn(this, { + code: `a11y-media-has-caption`, + message: `A11y: Media elements must have a ` + }); + } + } + if (a11y_no_onchange.has(this.name)) { if (handlers_map.has('change') && !handlers_map.has('blur')) { component.warn(this, { diff --git a/test/css/samples/omit-scoping-attribute-attribute-selector/expected.html b/test/css/samples/omit-scoping-attribute-attribute-selector/expected.html index 52175f98b6..f585d6bcdd 100644 --- a/test/css/samples/omit-scoping-attribute-attribute-selector/expected.html +++ b/test/css/samples/omit-scoping-attribute-attribute-selector/expected.html @@ -1,2 +1,2 @@ -
-
\ No newline at end of file +
+
diff --git a/test/css/samples/omit-scoping-attribute-attribute-selector/input.svelte b/test/css/samples/omit-scoping-attribute-attribute-selector/input.svelte index 6f4549ead8..af06836d29 100644 --- a/test/css/samples/omit-scoping-attribute-attribute-selector/input.svelte +++ b/test/css/samples/omit-scoping-attribute-attribute-selector/input.svelte @@ -1,10 +1,10 @@
- - + +
\ No newline at end of file + diff --git a/test/validator/samples/a11y-media-has-caption/input.svelte b/test/validator/samples/a11y-media-has-caption/input.svelte new file mode 100644 index 0000000000..105269cddb --- /dev/null +++ b/test/validator/samples/a11y-media-has-caption/input.svelte @@ -0,0 +1,4 @@ + + + + diff --git a/test/validator/samples/a11y-media-has-caption/warnings.json b/test/validator/samples/a11y-media-has-caption/warnings.json new file mode 100644 index 0000000000..a8c894b1d4 --- /dev/null +++ b/test/validator/samples/a11y-media-has-caption/warnings.json @@ -0,0 +1,32 @@ +[ + { + "code": "a11y-media-has-caption", + "end": { + "character": 55, + "column": 15, + "line": 2 + }, + "message": "A11y: Media elements must have a ", + "pos": 40, + "start": { + "character": 40, + "column": 0, + "line": 2 + } + }, + { + "code": "a11y-media-has-caption", + "end": { + "character": 80, + "column": 24, + "line": 3 + }, + "message": "A11y: Media elements must have a ", + "pos": 56, + "start": { + "character": 56, + "column": 0, + "line": 3 + } + } +] From 0f3bbb441e1a6895f0e236edc83147672c8014e2 Mon Sep 17 00:00:00 2001 From: Conduitry Date: Wed, 5 Aug 2020 12:22:22 -0400 Subject: [PATCH 26/32] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac39b41ee3..d788205b0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ * Fix unneeded invalidation of `$$props` and `$$restProps` ([#4993](https://github.com/sveltejs/svelte/issues/4993), [#5118](https://github.com/sveltejs/svelte/issues/5118)) * Provide better compiler error message when mismatched tags are due to autoclosing of tags ([#5049](https://github.com/sveltejs/svelte/issues/5049)) * Add `a11y-label-has-associated-control` warning ([#5074](https://github.com/sveltejs/svelte/pull/5074)) +* Add `a11y-media-has-caption` warning ([#5075](https://github.com/sveltejs/svelte/pull/5075)) * Fix `bind:group` when using contextual reference ([#5174](https://github.com/sveltejs/svelte/issues/5174)) ## 3.24.0 From a62d7362150bacc6c84fe8c813ba9b8849216763 Mon Sep 17 00:00:00 2001 From: Conduitry Date: Wed, 5 Aug 2020 12:25:52 -0400 Subject: [PATCH 27/32] -> v3.24.1 --- CHANGELOG.md | 2 +- package-lock.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d788205b0a..2863bf73eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Svelte changelog -## Unreleased +## 3.24.1 * 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)) diff --git a/package-lock.json b/package-lock.json index 82ad8fb6f6..0110595c76 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "svelte", - "version": "3.24.0", + "version": "3.24.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 6927dc3d0d..e0de8670ef 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "svelte", - "version": "3.24.0", + "version": "3.24.1", "description": "Cybernetically enhanced web apps", "module": "index.mjs", "main": "index", From cf57050f4919bb3ae5cb3b5801a5919f1672b2ab Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Fri, 7 Aug 2020 04:16:10 -0700 Subject: [PATCH 28/32] Mention "import type" in TypeScript FAQ (#5243) * Mention "import type" in TypeScript FAQ * Update site/content/faq/500-what-about-typescript-support.md Co-authored-by: Christian Kaisermann --- site/content/faq/500-what-about-typescript-support.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/site/content/faq/500-what-about-typescript-support.md b/site/content/faq/500-what-about-typescript-support.md index adfd63764e..98838bab3d 100644 --- a/site/content/faq/500-what-about-typescript-support.md +++ b/site/content/faq/500-what-about-typescript-support.md @@ -10,3 +10,11 @@ To declare the type of a reactive variable in a Svelte template, you should use let x: number; $: x = count + 1; ``` + +To import a type or interface make sure to use [TypeScript's `type` modifier](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export): + +``` +import type { SomeInterface } from './SomeFile'; +``` + +You must use the `type` modifier because `svelte-preprocess` doesn't know whether an import is a type or a value — it only transpiles one file at a time without knowledge of the other files and therefore can't safely erase imports which only contain types without this modifier present. From 1398affa53050a4685bdf00b373197e7ba0d0965 Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Fri, 7 Aug 2020 15:01:58 -0700 Subject: [PATCH 29/32] Update TypeScript blog post with info about Sapper (#5249) --- site/content/blog/2020-07-17-svelte-and-typescript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/content/blog/2020-07-17-svelte-and-typescript.md b/site/content/blog/2020-07-17-svelte-and-typescript.md index c3afb95c73..9c228a17da 100644 --- a/site/content/blog/2020-07-17-svelte-and-typescript.md +++ b/site/content/blog/2020-07-17-svelte-and-typescript.md @@ -134,7 +134,7 @@ error Command failed with exit code 1. ## What about TypeScript in Sapper projects? -Watch this space! +TypeScript support was added to Sapper in 0.28, so if you're using an older version be sure to [upgrade](https://sapper.svelte.dev/migrating#0_27_to_0_28). ## How can I contribute? From 4c449a741f9941d785c2ccb7cd79ebf12e7c68df Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 10 Aug 2020 22:53:06 -0400 Subject: [PATCH 30/32] bump site-kit version --- site/package-lock.json | 6 +++--- site/package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/site/package-lock.json b/site/package-lock.json index bde0e87f82..66d9be0d00 100644 --- a/site/package-lock.json +++ b/site/package-lock.json @@ -1281,9 +1281,9 @@ } }, "@sveltejs/site-kit": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@sveltejs/site-kit/-/site-kit-1.2.1.tgz", - "integrity": "sha512-5AhOCBcproHF5UbmuOIB9CiyAmG6BXOr2G4EjeeDz/tyo9myfnRKIgJSy26q8Zlw6TOlwxhzcAgvL5sgZF+IsA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@sveltejs/site-kit/-/site-kit-1.2.3.tgz", + "integrity": "sha512-2IwPD1soaUczsXHi6aXZ6EO0R0K/C4PDAPrZ//CX9gKGNmkAky4xmsqsrT/R1gPPPWbGeELkaU2NXDSt8DYXlQ==", "dev": true, "requires": { "@sindresorhus/slugify": "^0.9.1", diff --git a/site/package.json b/site/package.json index 2564fce2c6..e8ff39bd06 100644 --- a/site/package.json +++ b/site/package.json @@ -36,7 +36,7 @@ "@babel/preset-env": "^7.6.0", "@babel/runtime": "^7.6.0", "@sindresorhus/slugify": "^0.9.1", - "@sveltejs/site-kit": "^1.2.1", + "@sveltejs/site-kit": "^1.2.3", "@sveltejs/svelte-repl": "^0.2.0", "degit": "^2.1.4", "dotenv": "^8.1.0", From a1cb70dde41d0e22eff916bbf03f981dce9f4dcb Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 10 Aug 2020 23:15:12 -0400 Subject: [PATCH 31/32] bump site-kit version --- site/package-lock.json | 6 +++--- site/package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/site/package-lock.json b/site/package-lock.json index 66d9be0d00..caeb17a9bc 100644 --- a/site/package-lock.json +++ b/site/package-lock.json @@ -1281,9 +1281,9 @@ } }, "@sveltejs/site-kit": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@sveltejs/site-kit/-/site-kit-1.2.3.tgz", - "integrity": "sha512-2IwPD1soaUczsXHi6aXZ6EO0R0K/C4PDAPrZ//CX9gKGNmkAky4xmsqsrT/R1gPPPWbGeELkaU2NXDSt8DYXlQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@sveltejs/site-kit/-/site-kit-1.2.4.tgz", + "integrity": "sha512-W+/PthWX4R8UvKr+IyWIITGoY3cl/54ePZr3dU9ZlyP9r/weEvvKDBvjmW8tAKQFRfbxyySmXUxEGBoPhF8XAA==", "dev": true, "requires": { "@sindresorhus/slugify": "^0.9.1", diff --git a/site/package.json b/site/package.json index e8ff39bd06..fd5be85976 100644 --- a/site/package.json +++ b/site/package.json @@ -36,7 +36,7 @@ "@babel/preset-env": "^7.6.0", "@babel/runtime": "^7.6.0", "@sindresorhus/slugify": "^0.9.1", - "@sveltejs/site-kit": "^1.2.3", + "@sveltejs/site-kit": "^1.2.4", "@sveltejs/svelte-repl": "^0.2.0", "degit": "^2.1.4", "dotenv": "^8.1.0", From 5194f596f775965d6538470574296d8fd6da43ba Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Thu, 13 Aug 2020 02:53:18 +0800 Subject: [PATCH 32/32] do not declare variable for member assignment in reactive declaration in SSR (#5251) --- CHANGELOG.md | 4 ++ src/compiler/compile/render_ssr/index.ts | 39 ++++++------------- .../reactive-value-assign-property/_config.js | 5 +++ .../main.svelte | 6 +++ 4 files changed, 26 insertions(+), 28 deletions(-) create mode 100644 test/runtime/samples/reactive-value-assign-property/_config.js create mode 100644 test/runtime/samples/reactive-value-assign-property/main.svelte diff --git a/CHANGELOG.md b/CHANGELOG.md index 2863bf73eb..fd590c71aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Svelte changelog +## Unreleased + +* In SSR mode, do not automatically declare variables for reactive assignments to member expressions ([#5247](https://github.com/sveltejs/svelte/issues/5247)) + ## 3.24.1 * 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)) diff --git a/src/compiler/compile/render_ssr/index.ts b/src/compiler/compile/render_ssr/index.ts index c87fe3bdd9..a72b8b35ae 100644 --- a/src/compiler/compile/render_ssr/index.ts +++ b/src/compiler/compile/render_ssr/index.ts @@ -5,8 +5,7 @@ import { string_literal } from '../utils/stringify'; import Renderer from './Renderer'; import { INode as TemplateNode } from '../nodes/interfaces'; // TODO import Text from '../nodes/Text'; -import { extract_names } from '../utils/scope'; -import { LabeledStatement, Statement, ExpressionStatement, AssignmentExpression, Node } from 'estree'; +import { LabeledStatement, Statement, Node } from 'estree'; export default function ssr( component: Component, @@ -72,37 +71,17 @@ export default function ssr( }) : []; + const injected = Array.from(component.injected_reactive_declaration_vars).filter(name => { + const variable = component.var_lookup.get(name); + return variable.injected; + }); + const reactive_declarations = component.reactive_declarations.map(d => { const body: Statement = (d.node as LabeledStatement).body; let statement = b`${body}`; - if (d.declaration) { - const declared = extract_names(d.declaration); - const injected = declared.filter(name => { - return name[0] !== '$' && component.var_lookup.get(name).injected; - }); - - const self_dependencies = injected.filter(name => d.dependencies.has(name)); - - if (injected.length) { - // in some cases we need to do `let foo; [expression]`, in - // others we can do `let [expression]` - const separate = ( - self_dependencies.length > 0 || - declared.length > injected.length - ); - - const { left, right } = (body as ExpressionStatement).expression as AssignmentExpression; - - statement = separate - ? b` - ${injected.map(name => b`let ${name};`)} - ${statement}` - : b` - let ${left} = ${right}`; - } - } else { // TODO do not add label if it's not referenced + if (!d.declaration) { // TODO do not add label if it's not referenced statement = b`$: { ${statement} }`; } @@ -119,6 +98,8 @@ export default function ssr( ${reactive_store_values} + ${injected.map(name => b`let ${name};`)} + ${reactive_declarations} $$rendered = ${literal}; @@ -129,6 +110,8 @@ export default function ssr( : b` ${reactive_store_values} + ${injected.map(name => b`let ${name};`)} + ${reactive_declarations} return ${literal};`; diff --git a/test/runtime/samples/reactive-value-assign-property/_config.js b/test/runtime/samples/reactive-value-assign-property/_config.js new file mode 100644 index 0000000000..7b6c1d2965 --- /dev/null +++ b/test/runtime/samples/reactive-value-assign-property/_config.js @@ -0,0 +1,5 @@ +export default { + html: ` +

Hello world!

+ `, +}; diff --git a/test/runtime/samples/reactive-value-assign-property/main.svelte b/test/runtime/samples/reactive-value-assign-property/main.svelte new file mode 100644 index 0000000000..58e0fdb03c --- /dev/null +++ b/test/runtime/samples/reactive-value-assign-property/main.svelte @@ -0,0 +1,6 @@ + + +

Hello {user.name}!

\ No newline at end of file