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/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).) 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 ``` 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} 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. 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