diff --git a/apps/svelte.dev/content/docs/svelte/01-introduction/01-overview.md b/apps/svelte.dev/content/docs/svelte/01-introduction/01-overview.md index b1218232db..5acbe4897b 100644 --- a/apps/svelte.dev/content/docs/svelte/01-introduction/01-overview.md +++ b/apps/svelte.dev/content/docs/svelte/01-introduction/01-overview.md @@ -2,29 +2,29 @@ title: Overview --- -- Short intro to what Svelte is and why it's the best ever -- A few code examples to have a very rough understanding of how Svelte code looks like -- Jump off points to tutorial, SvelteKit etc - -Svelte is a web UI framework that uses a compiler to turn declarative component code like this... +Svelte is a framework for building user interfaces on the web. It uses a compiler to turn declarative components written in HTML, CSS and JavaScript... ```svelte - - + + + ``` -...into tightly optimized JavaScript that updates the document when state like count changes. Because the compiler can 'see' where count is referenced, the generated code is highly efficient, and because we're hijacking syntax like `$state(...)` and `=` instead of using cumbersome APIs, you can write less code. +...into lean, tightly optimized JavaScript. + +You can use it to build anything on the web, from standalone components to ambitious full stack apps (using Svelte's companion application framework, [SvelteKit](../kit)) and everything in between. -Besides being fun to work with, Svelte offers a lot of features built-in, such as animations and transitions. Once you've written your first components you can reach for our batteries included metaframework [SvelteKit](../kit) which provides you with an opinionated router, data loading and more. +These pages serve as reference documentation. If you're new to Svelte, we recommend starting with the [interactive tutorial](/tutorial) and coming back here when you have questions. -If you're new to Svelte, visit the [interactive tutorial](/tutorial) before consulting this documentation. You can try Svelte online using the [REPL](/repl). Alternatively, if you'd like a more fully-featured environment, you can try Svelte on [StackBlitz](https://sveltekit.new). +You can also try Svelte online in the [playground](/playground) or, if you need a more fully-featured environment, on [StackBlitz](https://sveltekit.new). diff --git a/apps/svelte.dev/content/docs/svelte/01-introduction/02-getting-started.md b/apps/svelte.dev/content/docs/svelte/01-introduction/02-getting-started.md index 62026018e1..940c38afe7 100644 --- a/apps/svelte.dev/content/docs/svelte/01-introduction/02-getting-started.md +++ b/apps/svelte.dev/content/docs/svelte/01-introduction/02-getting-started.md @@ -2,37 +2,27 @@ title: Getting started --- -- `npm create svelte@latest`, describe that it scaffolds SvelteKit project -- `npm create vite@latest`, describe that it scaffolds Svelte SPA powered by Vite -- mention `svelte-add` -- Jump off points to tutorial, SvelteKit etc - -## Start a new project - -We recommend using [SvelteKit](https://kit.svelte.dev/), the official application framework from the Svelte team: +We recommend using [SvelteKit](https://kit.svelte.dev/), the official application framework from the Svelte team powered by [Vite](https://vite.dev/): ``` -npm create svelte@latest myapp +npx sv create myapp cd myapp -npm install npm run dev ``` -SvelteKit will handle calling [the Svelte compiler](https://www.npmjs.com/package/svelte) to convert your `.svelte` files into `.js` files that create the DOM and `.css` files that style it. It also provides all the other pieces you need to build a web application such as a development server, routing, deployment, and SSR support. [SvelteKit](https://kit.svelte.dev/) uses [Vite](https://vitejs.dev/) to build your code. - Don't worry if you don't know Svelte yet! You can ignore all the nice features SvelteKit brings on top for now and dive into it later. ### Alternatives to SvelteKit -If you don't want to use SvelteKit for some reason, you can also use Svelte with Vite (but without SvelteKit) by running `npm create vite@latest` and selecting the `svelte` option. With this, `npm run build` will generate HTML, JS and CSS files inside the `dist` directory thanks using [vite-plugin-svelte](https://github.com/sveltejs/vite-plugin-svelte). In most cases, you will probably need to [choose a routing library](faq#Is-there-a-router) as well. +You can also use Svelte directly with Vite by running `npm create vite@latest` and selecting the `svelte` option. With this, `npm run build` will generate HTML, JS and CSS files inside the `dist` directory using [vite-plugin-svelte](https://github.com/sveltejs/vite-plugin-svelte). In most cases, you will probably need to [choose a routing library](faq#Is-there-a-router) as well. -Alternatively, there are plugins for [Rollup](https://github.com/sveltejs/rollup-plugin-svelte), [Webpack](https://github.com/sveltejs/svelte-loader) [and a few others](https://sveltesociety.dev/packages?category=build-plugins) to handle Svelte compilation — which will output `.js` and `.css` that you can insert into your HTML — but setting up SSR with them requires more manual work. +There are also plugins for [Rollup](https://github.com/sveltejs/rollup-plugin-svelte), [Webpack](https://github.com/sveltejs/svelte-loader) [and a few others](https://sveltesociety.dev/packages?category=build-plugins), but we recommend Vite. ## Editor tooling The Svelte team maintains a [VS Code extension](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode) and there are integrations with various other [editors](https://sveltesociety.dev/resources#editor-support) and tools as well. -You can also check your code from the command line using [svelte-check](https://www.npmjs.com/package/svelte-check) (using the Svelte or Vite CLI setup will install this for you). +You can also check your code from the command line using [sv check](https://github.com/sveltejs/cli). ## Getting help diff --git a/apps/svelte.dev/content/docs/svelte/01-introduction/03-svelte-files.md b/apps/svelte.dev/content/docs/svelte/01-introduction/03-svelte-files.md new file mode 100644 index 0000000000..d68bb89126 --- /dev/null +++ b/apps/svelte.dev/content/docs/svelte/01-introduction/03-svelte-files.md @@ -0,0 +1,66 @@ +--- +title: .svelte files +--- + +Components are the building blocks of Svelte applications. They are written into `.svelte` files, using a superset of HTML. + +All three sections — script, styles and markup — are optional. + + +```svelte +/// file: MyComponent.svelte + + + + + + + +``` + +## ` + + +``` + +## ` +``` + +For more information regarding styling, read the documentation around [styles and classes](styles-and-classes). diff --git a/apps/svelte.dev/content/docs/svelte/01-introduction/04-svelte-js-files.md b/apps/svelte.dev/content/docs/svelte/01-introduction/04-svelte-js-files.md new file mode 100644 index 0000000000..d0dde34111 --- /dev/null +++ b/apps/svelte.dev/content/docs/svelte/01-introduction/04-svelte-js-files.md @@ -0,0 +1,7 @@ +--- +title: .svelte.js and .svelte.ts files +--- + +Besides `.svelte` files, Svelte also operates on `.svelte.js` and `.svelte.ts` files. + +These behave like any other `.js` or `.ts` module, except that you can use runes. This is useful for creating reusable reactive logic, or sharing reactive state across your app. diff --git a/apps/svelte.dev/content/docs/svelte/02-template-syntax/01-component-fundamentals.md b/apps/svelte.dev/content/docs/svelte/01-introduction/xx-props.md similarity index 63% rename from apps/svelte.dev/content/docs/svelte/02-template-syntax/01-component-fundamentals.md rename to apps/svelte.dev/content/docs/svelte/01-introduction/xx-props.md index 0e5597c020..cad854d878 100644 --- a/apps/svelte.dev/content/docs/svelte/02-template-syntax/01-component-fundamentals.md +++ b/apps/svelte.dev/content/docs/svelte/01-introduction/xx-props.md @@ -1,30 +1,7 @@ --- -title: Component fundamentals +title: Public API of a component --- -- script (module) / template / style (rough overview) -- `$props` / `$state` (in the context of components) - -Components are the building blocks of Svelte applications. They are written into `.svelte` files, using a superset of HTML. - -All three sections — script, styles and markup — are optional. - -```svelte - - - - - -``` - -## ` - - -``` - -## ` -``` - -For more information regarding styling, read the documentation around [styles and classes](styles-and-classes). diff --git a/apps/svelte.dev/content/docs/svelte/01-introduction/03-reactivity-fundamentals.md b/apps/svelte.dev/content/docs/svelte/01-introduction/xx-reactivity-fundamentals.md similarity index 100% rename from apps/svelte.dev/content/docs/svelte/01-introduction/03-reactivity-fundamentals.md rename to apps/svelte.dev/content/docs/svelte/01-introduction/xx-reactivity-fundamentals.md diff --git a/apps/svelte.dev/content/docs/svelte/02-runes/01-what-are-runes.md b/apps/svelte.dev/content/docs/svelte/02-runes/01-what-are-runes.md new file mode 100644 index 0000000000..26c1e22472 --- /dev/null +++ b/apps/svelte.dev/content/docs/svelte/02-runes/01-what-are-runes.md @@ -0,0 +1,21 @@ +--- +title: What are runes? +--- + +> [!NOTE] **rune** /ro͞on/ _noun_ +> +> A letter or mark used as a mystical or magic symbol. + +Runes are symbols that you use in `.svelte` and `.svelte.js`/`.svelte.ts` files to control the Svelte compiler. If you think of Svelte as a language, runes are part of the syntax — they are _keywords_. + +Runes have a `$` prefix and look like functions: + +```js +let message = $state('hello'); +``` + +They differ from normal JavaScript functions in important ways, however: + +- You don't need to import them — they are part of the language +- They're not values — you can't assign them to a variable or pass them as arguments to a function +- Just like JavaScript keywords, they are only valid in certain positions (the compiler will help you if you put them in the wrong place) diff --git a/apps/svelte.dev/content/docs/svelte/02-runes/02-$state.md b/apps/svelte.dev/content/docs/svelte/02-runes/02-$state.md new file mode 100644 index 0000000000..7653e3e87a --- /dev/null +++ b/apps/svelte.dev/content/docs/svelte/02-runes/02-$state.md @@ -0,0 +1,127 @@ +--- +title: $state +--- + +The `$state` rune allows you to create _reactive state_, which means that your UI _reacts_ when it changes. + +```svelte + + + +``` + +Unlike other frameworks you may have encountered, there is no API for interacting with state — `count` is just a number, rather than an object or a function, and you can update it like you would update any other variable. + +### Deep state + +If `$state` is used with an array or a simple object, the result is a deeply reactive _state proxy_. [Proxies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) allow Svelte to run code when you read or write properties, including via methods like `array.push(...)`, triggering granular updates. + +State is proxified recursively until Svelte finds something other than an array or simple object. In a case like this... + +```js +let todos = $state([ + { + done: false, + text: 'add more todos' + } +]); +``` + +...modifying an individual todo's property will trigger updates to anything in your UI that depends on that specific property: + +```js +// @filename: ambient.d.ts +declare global { + const todos: Array<{ done: boolean, text: string }> +} + +// @filename: index.js +// ---cut--- +todos[0].done = !todos[0].done; +``` + +If you push a new object to the array, it will also be proxified: + +```js +// @filename: ambient.d.ts +declare global { + const todos: Array<{ done: boolean, text: string }> +} + +// @filename: index.js +// ---cut--- +todos.push({ + done: false, + text: 'eat lunch' +}); +``` + +> [!NOTE] When you update properties of proxies, the original object is _not_ mutated. + +### Classes + +You can also use `$state` in class fields (whether public or private): + +```js +// @errors: 7006 2554 +class Todo { + done = $state(false); + text = $state(); + + constructor(text) { + this.text = text; + } + + reset() { + this.text = ''; + this.done = false; + } +} +``` + +> [!NOTE] The compiler transforms `done` and `text` into `get`/`set` methods on the class prototype referencing private fields. + +## `$state.raw` + +In cases where you don't want objects and arrays to be deeply reactive you can use `$state.raw`. + +State declared with `$state.raw` cannot be mutated; it can only be _reassigned_. In other words, rather than assigning to a property of an object, or using an array method like `push`, replace the object or array altogether if you'd like to update it: + +```js +let person = $state.raw({ + name: 'Heraclitus', + age: 49 +}); + +// this will have no effect (and will throw an error in dev) +person.age += 1; + +// this will work, because we're creating a new person +person = { + name: 'Heraclitus', + age: 50 +}; +``` + +This can improve performance with large arrays and objects that you weren't planning to mutate anyway, since it avoids the cost of making them reactive. Note that raw state can _contain_ reactive state (for example, a raw array of reactive objects). + +## `$state.snapshot` + +To take a static snapshot of a deeply reactive `$state` proxy, use `$state.snapshot`: + +```svelte + +``` + +This is handy when you want to pass some state to an external library or API that doesn't expect a proxy, such as `structuredClone`. diff --git a/apps/svelte.dev/content/docs/svelte/02-runes/03-$derived.md b/apps/svelte.dev/content/docs/svelte/02-runes/03-$derived.md new file mode 100644 index 0000000000..4f0d70dcc8 --- /dev/null +++ b/apps/svelte.dev/content/docs/svelte/02-runes/03-$derived.md @@ -0,0 +1,45 @@ +--- +title: $derived +--- + +Derived state is declared with the `$derived` rune: + +```svelte + + + + +

{count} doubled is {doubled}

+``` + +The expression inside `$derived(...)` should be free of side-effects. Svelte will disallow state changes (e.g. `count++`) inside derived expressions. + +As with `$state`, you can mark class fields as `$derived`. + +## `$derived.by` + +Sometimes you need to create complex derivations that don't fit inside a short expression. In these cases, you can use `$derived.by` which accepts a function as its argument. + +```svelte + + + +``` + +In essence, `$derived(expression)` is equivalent to `$derived.by(() => expression)`. diff --git a/apps/svelte.dev/content/docs/svelte/03-runes/02-side-effects.md b/apps/svelte.dev/content/docs/svelte/02-runes/04-$effect.md similarity index 76% rename from apps/svelte.dev/content/docs/svelte/03-runes/02-side-effects.md rename to apps/svelte.dev/content/docs/svelte/02-runes/04-$effect.md index c9bda9a1e6..c81dcbc570 100644 --- a/apps/svelte.dev/content/docs/svelte/03-runes/02-side-effects.md +++ b/apps/svelte.dev/content/docs/svelte/02-runes/04-$effect.md @@ -1,15 +1,16 @@ --- -title: Side effects +title: $effect --- -- `$effect` (.pre) -- when not to use it, better patterns for what to do instead +Effects are what make your application _do things_. When Svelte runs an effect function, it tracks which pieces of state (and derived state) are accessed, and re-runs the function when that state later changes. -Side effects play a crucial role in applications. They are triggered by state changes and can then interact with external systems, like logging something, setting up a server connection or synchronize with a third-party library that has no knowledge of Svelte's reactivity model. +Most of the effects in a Svelte app are created by Svelte itself — they're the bits that update the text in `

hello {name}!

` when `name` changes. -## `$effect` fundamentals +But you can also create your own effects with the `$effect` rune, which is useful when you need to synchronize an external system (whether that's a library, or a `` element, or something across a network) with state inside your Svelte app. -To run _side-effects_ when the component is mounted to the DOM, and when values change, we can use the `$effect` rune ([demo](/#H4sIAAAAAAAAE31T24rbMBD9lUG7kAQ2sbdlX7xOYNk_aB_rQhRpbAsU2UiTW0P-vbrYubSlYGzmzMzROTPymdVKo2PFjzMzfIusYB99z14YnfoQuD1qQh-7bmdFQEonrOppVZmKNBI49QthCc-OOOH0LZ-9jxnR6c7eUpOnuv6KeT5JFdcqbvbcBcgDz1jXKGg6ncFyBedYR6IzLrAZwiN5vtSxaJA-EzadfJEjKw11C6GR22-BLH8B_wxdByWpvUYtqqal2XB6RVkG1CoHB6U1WJzbnYFDiwb3aGEdDa3Bm1oH12sQLTcNPp7r56m_00mHocSG97_zd7ICUXonA5fwKbPbkE2ZtMJGGVkEdctzQi4QzSwr9prnFYNk5hpmqVuqPQjNnfOJoMF22lUsrq_UfIN6lfSVyvQ7grB3X2mjMZYO3XO9w-U5iLx42qg29md3BP_ni5P4gy9ikTBlHxjLzAtPDlyYZmRdjAbGq7HprEQ7p64v4LU_guu0kvAkhBim3nMplWl8FreQD-CW20aZR0wq12t-KqDWeBywhvexKC3memmDwlHAv9q4Vo2ZK8KtK0CgX7u9J8wXbzdKv-nRnfF_2baTqlYoWUF2h5efl9-n0O6koAMAAA==)): +> [!NOTE] Avoid overusing effects! When you do too much work in them, code often becomes difficult to understand and maintain. See [when not to use effects](#When-not-to-use-effects) to learn about alternative approaches. + +Your effects run after the component has been mounted to the DOM, and in a [microtask](https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide) after state changes ([demo](/playground/untitled#H4sIAAAAAAAAE31S246bMBD9lZF3pSRSAqTVvrCAVPUP2sdSKY4ZwJJjkD0hSVH-vbINuWxXfQH5zMyZc2ZmZLVUaFn6a2R06ZGlHmBrpvnBvb71fWQHVOSwPbf4GS46TajJspRlVhjZU1HqkhQSWPkHIYdXS5xw-Zas3ueI6FRn7qHFS11_xSRZhIxbFtcDtw7SJb1iXaOg5XIFeQGjzyPRaevYNOGZIJ8qogbpe8CWiy_VzEpTXiQUcvPDkSVrSNZz1UlW1N5eLcqmpdXUvaQ4BmqlhZNUCgxuzFHDqUWNAxrYeUM76AzsnOsdiJbrBp_71lKpn3RRbii-4P3f-IMsRxS-wcDV_bL4PmSdBa2wl7pKnbp8DMgVvJm8ZNskKRkEM_OzyOKQFkgqOYBQ3Nq89Ns0nbIl81vMFN-jKoLMTOr-SOBOJS-Z8f5Y6D1wdcR8dFqvEBdetK-PHwj-z-cH8oHPY54wRJ8Ys7iSQ3Bg3VA9azQbmC9k35kKzYa6PoVtfwbbKVnBixBiGn7Pq0rqJoUtHiCZwAM3jdTPWCVtr_glhVrhecIa3vuksJ_b7TqFs4DPyriSjd5IwoNNQaAmNI-ESfR2p8zimzvN1swdCkvJHPH6-_oX8o1SgcIDAAA=)): ```svelte -``` - -...do this: - -```svelte - -``` - -> [!NOTE] For things that are more complicated than a simple expression like `count * 2`, you can also use `$derived.by`. - -You might be tempted to do something convoluted with effects to link one value to another. The following example shows two inputs for "money spent" and "money left" that are connected to each other. If you update one, the other should update accordingly. Don't use effects for this ([demo](/#H4sIAAAAAAAACpVRy2rDMBD8lWXJwYE0dg-9KFYg31H3oNirIJBlYa1DjPG_F8l1XEop9LgzOzP7mFAbSwHF-4ROtYQCL97jAXn0sQh3skx4wNANfR2RMtS98XyuXMWWGLhjZUHCa1GcVix4cgwSdoEVU1bsn4wl_Y1I2kS6inekNdWcZXuQZ5giFDWpfwl5WYyT2fynbB1g1UWbTVbm2w6utOpKNq1TGucHhri6rLBX7kYVwtW4RtyVHUhOyXeGVj3klLxnyJP0i8lXNJUx6en-v6A48K85kTimpi0sYj-yAo-Wlh9FcL1LY4K3ahSgLT1OC3ZTXkBxfKN2uVC6T5LjAduuMdpQg4L7geaP-RNHPuClMQIAAA==)): - -```svelte - - - - - -``` - -Instead, use callbacks where possible ([demo](/#H4sIAAAAAAAACo2SP2-DMBDFv8rp1CFR84cOXQhU6p6tY-ngwoEsGWPhI0pk8d0rG5yglqGj37v7veMJh7VUZDH9dKhFS5jiuzG4Q74Z_7AXUky4Q9sNfemVzJa9NPxW6IIVMXDHQkEOL0lyipo1pBlyeLIsmDbJ9u4oqhdG2A2mLrgedMmy0zCYSjB9eMaGtuC8WXBkPtOBRd8QHy5CDXSa3Jk7HbOfDgjWuAo_U71kz9vr6Bgc2X44orPjow2dKfFNKhSTSW0GBl9iXmAvdEMFQqDmLgBH6HQYyt3ie0doxTV3IWqEY2DN88eohqePvsf9O9mf_if4HMSVXD89NfEI99qvbMs3RdPv4MXYaSWtUeKWQq3oOlfZCJNCcnildlFgWMcdtl0la0kVptwPNH6NP_uzV0acAgAA)): - -```svelte - - - - - -``` - -If you need to use bindings, for whatever reason (for example when you want some kind of "writable `$derived`"), consider using getters and setters to synchronise state ([demo](/#H4sIAAAAAAAACo2SQW-DMAyF_4pl7dBqXcsOu1CYtHtvO44dsmKqSCFExFRFiP8-xRCGth52tJ_9PecpA1bakMf0Y0CrasIU35zDHXLvQuGvZJhwh77p2nPoZP7casevhS3YEAM3rAzk8Jwkx9jzjixDDg-eFdMm2S6KoWolyK6ItuCqs2fWjYXOlYrpPTA2tIUhiAVH5iPtWbUX4v1VmY6Okzpzp2OepgNEGu_CT1St2fP2fXQ0juwwHNHZ4ScNmxn1RUaCybR1HUMIMS-wVfZCBYJQ80GAIzRWhvJh9d4RanXLB7Ea4SCsef4Qu1IG68Xu387h9D_GJ2ne8ZXpxTZUv1w994amjxCaMc1Se2dUn0Jl6DaHeFEuhWT_QvUqOlnHHdZNqStNJabcdjR-jt8IbC-7lgIAAA==)): - -```svelte - - - - - -``` - -If you absolutely have to update `$state` within an effect and run into an infinite loop because you read and write to the same `$state`, use [untrack](svelte#untrack). - ## `$effect.pre` In rare cases, you may need to run code _before_ the DOM updates. For this we can use the `$effect.pre` rune: @@ -375,3 +261,118 @@ nested effects that you want to manually control. This rune also allows for crea }); ``` + +## When not to use effects + +In general, `$effect` is best considered something of an escape hatch — useful for things like analytics and direct DOM manipulation — rather than a tool you should use frequently. In particular, avoid using it to synchronise state. Instead of this... + +```svelte + +``` + +...do this: + +```svelte + +``` + +> [!NOTE] For things that are more complicated than a simple expression like `count * 2`, you can also use `$derived.by`. + +You might be tempted to do something convoluted with effects to link one value to another. The following example shows two inputs for "money spent" and "money left" that are connected to each other. If you update one, the other should update accordingly. Don't use effects for this ([demo](/#H4sIAAAAAAAACpVRy2rDMBD8lWXJwYE0dg-9KFYg31H3oNirIJBlYa1DjPG_F8l1XEop9LgzOzP7mFAbSwHF-4ROtYQCL97jAXn0sQh3skx4wNANfR2RMtS98XyuXMWWGLhjZUHCa1GcVix4cgwSdoEVU1bsn4wl_Y1I2kS6inekNdWcZXuQZ5giFDWpfwl5WYyT2fynbB1g1UWbTVbm2w6utOpKNq1TGucHhri6rLBX7kYVwtW4RtyVHUhOyXeGVj3klLxnyJP0i8lXNJUx6en-v6A48K85kTimpi0sYj-yAo-Wlh9FcL1LY4K3ahSgLT1OC3ZTXkBxfKN2uVC6T5LjAduuMdpQg4L7geaP-RNHPuClMQIAAA==)): + +```svelte + + + + + +``` + +Instead, use callbacks where possible ([demo](/#H4sIAAAAAAAACo2SP2-DMBDFv8rp1CFR84cOXQhU6p6tY-ngwoEsGWPhI0pk8d0rG5yglqGj37v7veMJh7VUZDH9dKhFS5jiuzG4Q74Z_7AXUky4Q9sNfemVzJa9NPxW6IIVMXDHQkEOL0lyipo1pBlyeLIsmDbJ9u4oqhdG2A2mLrgedMmy0zCYSjB9eMaGtuC8WXBkPtOBRd8QHy5CDXSa3Jk7HbOfDgjWuAo_U71kz9vr6Bgc2X44orPjow2dKfFNKhSTSW0GBl9iXmAvdEMFQqDmLgBH6HQYyt3ie0doxTV3IWqEY2DN88eohqePvsf9O9mf_if4HMSVXD89NfEI99qvbMs3RdPv4MXYaSWtUeKWQq3oOlfZCJNCcnildlFgWMcdtl0la0kVptwPNH6NP_uzV0acAgAA)): + +```svelte + + + + + +``` + +If you need to use bindings, for whatever reason (for example when you want some kind of "writable `$derived`"), consider using getters and setters to synchronise state ([demo](/#H4sIAAAAAAAACo2SQW-DMAyF_4pl7dBqXcsOu1CYtHtvO44dsmKqSCFExFRFiP8-xRCGth52tJ_9PecpA1bakMf0Y0CrasIU35zDHXLvQuGvZJhwh77p2nPoZP7casevhS3YEAM3rAzk8Jwkx9jzjixDDg-eFdMm2S6KoWolyK6ItuCqs2fWjYXOlYrpPTA2tIUhiAVH5iPtWbUX4v1VmY6Okzpzp2OepgNEGu_CT1St2fP2fXQ0juwwHNHZ4ScNmxn1RUaCybR1HUMIMS-wVfZCBYJQ80GAIzRWhvJh9d4RanXLB7Ea4SCsef4Qu1IG68Xu387h9D_GJ2ne8ZXpxTZUv1w994amjxCaMc1Se2dUn0Jl6DaHeFEuhWT_QvUqOlnHHdZNqStNJabcdjR-jt8IbC-7lgIAAA==)): + +```svelte + + + + + +``` + +If you absolutely have to update `$state` within an effect and run into an infinite loop because you read and write to the same `$state`, use [untrack](svelte#untrack). diff --git a/apps/svelte.dev/content/docs/svelte/02-runes/05-$props.md b/apps/svelte.dev/content/docs/svelte/02-runes/05-$props.md new file mode 100644 index 0000000000..1ac90662c7 --- /dev/null +++ b/apps/svelte.dev/content/docs/svelte/02-runes/05-$props.md @@ -0,0 +1,5 @@ +--- +title: $props +--- + +Coming soon! diff --git a/apps/svelte.dev/content/docs/svelte/02-runes/06-$bindable.md b/apps/svelte.dev/content/docs/svelte/02-runes/06-$bindable.md new file mode 100644 index 0000000000..b2b5661eb4 --- /dev/null +++ b/apps/svelte.dev/content/docs/svelte/02-runes/06-$bindable.md @@ -0,0 +1,5 @@ +--- +title: $bindable +--- + +Coming soon! diff --git a/apps/svelte.dev/content/docs/svelte/02-runes/07-$inspect.md b/apps/svelte.dev/content/docs/svelte/02-runes/07-$inspect.md new file mode 100644 index 0000000000..8bfb708bce --- /dev/null +++ b/apps/svelte.dev/content/docs/svelte/02-runes/07-$inspect.md @@ -0,0 +1,5 @@ +--- +title: $inspect +--- + +Coming soon! diff --git a/apps/svelte.dev/content/docs/svelte/02-runes/08-$host.md b/apps/svelte.dev/content/docs/svelte/02-runes/08-$host.md new file mode 100644 index 0000000000..dee06943b5 --- /dev/null +++ b/apps/svelte.dev/content/docs/svelte/02-runes/08-$host.md @@ -0,0 +1,5 @@ +--- +title: $host +--- + +Coming soon! diff --git a/apps/svelte.dev/content/docs/svelte/03-runes/index.md b/apps/svelte.dev/content/docs/svelte/02-runes/index.md similarity index 100% rename from apps/svelte.dev/content/docs/svelte/03-runes/index.md rename to apps/svelte.dev/content/docs/svelte/02-runes/index.md diff --git a/apps/svelte.dev/content/docs/svelte/03-runes/01-state.md b/apps/svelte.dev/content/docs/svelte/03-runes/01-state.md deleted file mode 100644 index 1ab89fa239..0000000000 --- a/apps/svelte.dev/content/docs/svelte/03-runes/01-state.md +++ /dev/null @@ -1,201 +0,0 @@ ---- -title: State ---- - -Svelte 5 uses _runes_, a powerful set of primitives for controlling reactivity inside your Svelte components and inside `.svelte.js` and `.svelte.ts` modules. - -Runes are function-like symbols that provide instructions to the Svelte compiler. You don't need to import them from anywhere — when you use Svelte, they're part of the language. This page describes the runes that are concerned with managing state in your application. - -## `$state` - -The `$state` rune is the at the heart of the runes API. It is used to declare reactive state: - -```svelte - - - -``` - -Variables declared with `$state` are the variable _itself_, in other words there's no wrapper around the value that it contains. This is possible thanks to the compiler-nature of Svelte. As such, updating state is done through simple reassignment. - -You can also use `$state` in class fields (whether public or private): - -```js -// @errors: 7006 2554 -class Todo { - done = $state(false); - text = $state(); - - constructor(text) { - this.text = text; - } - - reset() { - this.text = ''; - this.done = false; - } -} -``` - -> [!NOTE] In this example, the compiler transforms `done` and `text` into `get`/`set` methods on the class prototype referencing private fields - -Objects and arrays are made deeply reactive by wrapping them with [`Proxies`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy). What that means is that in the following example, we can mutate the `entries` object and the UI will still update - but only the list item that is actually changed will rerender: - -```svelte - - -{#each entries as entry (entry.id)} - {entry.text} -{/each} - - -``` - -> [!NOTE] Only POJOs (plain old JavaScript objects) are made deeply reactive. Reactivity will stop at class boundaries and leave those alone - -## `$state.raw` - -State declared with `$state.raw` cannot be mutated; it can only be _reassigned_. In other words, rather than assigning to a property of an object, or using an array method like `push`, replace the object or array altogether if you'd like to update it: - -```js -let person = $state.raw({ - name: 'Heraclitus', - age: 49 -}); - -// this will have no effect (and will throw an error in dev) -person.age += 1; - -// this will work, because we're creating a new person -person = { - name: 'Heraclitus', - age: 50 -}; -``` - -This can improve performance with large arrays and objects that you weren't planning to mutate anyway, since it avoids the cost of making them reactive. Note that raw state can _contain_ reactive state (for example, a raw array of reactive objects). - -## `$state.snapshot` - -To take a static snapshot of a deeply reactive `$state` proxy, use `$state.snapshot`: - -```svelte - -``` - -This is handy when you want to pass some state to an external library or API that doesn't expect a proxy, such as `structuredClone`. - -## `$derived` - -Derived state is declared with the `$derived` rune: - -```svelte - - - - -

{count} doubled is {doubled}

-``` - -The expression inside `$derived(...)` should be free of side-effects. Svelte will disallow state changes (e.g. `count++`) inside derived expressions. - -As with `$state`, you can mark class fields as `$derived`. - -## `$derived.by` - -Sometimes you need to create complex derivations that don't fit inside a short expression. In these cases, you can use `$derived.by` which accepts a function as its argument. - -```svelte - - - -``` - -In essence, `$derived(expression)` is equivalent to `$derived.by(() => expression)`. - -## Universal reactivity - -In the examples above, `$state` and `$derived` only appear at the top level of components. You can also use them within functions or even outside Svelte components inside `.svelte.js` or `.svelte.ts` modules. - -```ts -/// file: counter.svelte.ts -export function createCounter(initial: number) { - let count = $state(initial); - let double = $derived(count * 2); - return { - get count() { - return count; - }, - get double() { - return double; - }, - increment: () => count++ - }; -} -``` - -```svelte - - - - -``` - -There are a few things to note in the above example: - -- We're using getters to transport reactivity across the function boundary. This way we keep reactivity "alive". If we were to return the value itself, it would be fixed to the value at that point in time. This is no different to how regular JavaScript variables behave. -- We're not destructuring the counter at the usage site. Because we're using getters, destructuring would fix `count` and `double` to the value at that point in time. To keep the getters "alive", we're not using destructuring. Again, this is how regular JavaScript works. - -If you have shared state you want to manipulate from various places, you don't need to resort to getters. Instead, you can take advantage of `$state` being deeply reactive and only update its properties, not the value itself: - -```ts -/// file: app-state.svelte.ts -export const appState = $state({ - loggedIn: true -}); -``` - -```svelte - - - - -``` diff --git a/apps/svelte.dev/content/docs/svelte/02-template-syntax/02-basic-markup.md b/apps/svelte.dev/content/docs/svelte/03-template-syntax/01-basic-markup.md similarity index 82% rename from apps/svelte.dev/content/docs/svelte/02-template-syntax/02-basic-markup.md rename to apps/svelte.dev/content/docs/svelte/03-template-syntax/01-basic-markup.md index e40c78a7cb..07b093df87 100644 --- a/apps/svelte.dev/content/docs/svelte/02-template-syntax/02-basic-markup.md +++ b/apps/svelte.dev/content/docs/svelte/03-template-syntax/01-basic-markup.md @@ -2,11 +2,11 @@ title: Basic markup --- -- [basically what we have in the Svelte docs today](https://svelte.dev/docs/basic-markup) +Markup inside a Svelte component can be thought of as HTML++. ## Tags -A lowercase tag, like `
`, denotes a regular HTML element. A capitalised tag, such as `` or ``, indicates a _component_. +A lowercase tag, like `
`, denotes a regular HTML element. A capitalised tag or a tag that uses dot notation, such as `` or ``, indicates a _component_. ```svelte