From fd78385447b07c307dccb076cb27b542ad32f321 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 21 Oct 2024 11:57:07 -0400 Subject: [PATCH] chore: restructure docs for new site (#13699) --- .prettierignore | 4 +- .../blog/2020-07-17-svelte-and-typescript.md | 2 +- .../2022-12-14-announcing-sveltekit-1.0.md | 2 +- documentation/blog/2023-06-22-svelte-4.md | 4 +- .../blog/2023-08-31-view-transitions.md | 2 +- .../docs/01-introduction/01-overview.md | 32 +- .../01-introduction/02-getting-started.md | 20 +- .../docs/01-introduction/03-svelte-files.md | 66 ++ .../01-introduction/04-svelte-js-files.md | 7 + .../xx-props.md} | 65 +- ...ntals.md => xx-reactivity-fundamentals.md} | 0 .../docs/02-runes/01-what-are-runes.md | 21 + documentation/docs/02-runes/02-$state.md | 127 +++ documentation/docs/02-runes/03-$derived.md | 45 + .../04-$effect.md} | 255 ++--- documentation/docs/02-runes/05-$props.md | 128 +++ documentation/docs/02-runes/06-$bindable.md | 54 + documentation/docs/02-runes/07-$inspect.md | 44 + documentation/docs/02-runes/08-$host.md | 37 + .../docs/{03-runes => 02-runes}/index.md | 0 documentation/docs/03-runes/01-state.md | 201 ---- .../01-basic-markup.md} | 23 +- .../docs/03-template-syntax/02-if.md | 40 + .../docs/03-template-syntax/03-each.md | 92 ++ .../docs/03-template-syntax/04-key.md | 24 + .../05-await.md} | 27 +- .../06-snippet.md} | 28 +- .../docs/03-template-syntax/07-@render.md | 39 + .../docs/03-template-syntax/08-@html.md | 51 + .../docs/03-template-syntax/09-@const.md | 14 + .../10-bind.md} | 260 +++-- .../11-use.md} | 2 +- .../12-transition.md} | 29 +- .../docs/03-template-syntax/13-in-and-out.md | 5 + .../docs/03-template-syntax/14-animate.md | 5 + .../03-template-syntax/15-class-and-style.md | 5 + .../index.md | 0 .../xx-control-flow.md} | 37 - .../03-template-syntax/xx-data-fetching.md | 20 + .../01-styles-and-classes.md} | 0 documentation/docs/04-styling/index.md | 3 + documentation/docs/05-misc/01-debugging.md | 94 -- .../docs/05-misc/07-v5-migration-guide.md | 5 - .../09-special-elements.md | 4 +- .../docs/05-special-elements/index.md | 3 + .../{04-runtime => 06-runtime}/01-stores.md | 0 .../{04-runtime => 06-runtime}/02-context.md | 0 .../03-lifecycle-hooks.md | 0 .../04-imperative-component-api.md | 0 .../docs/{04-runtime => 06-runtime}/index.md | 0 documentation/docs/07-misc/01-debugging.md | 55 ++ .../docs/{05-misc => 07-misc}/02-testing.md | 2 +- .../{05-misc => 07-misc}/03-typescript.md | 6 +- .../04-custom-elements.md | 0 .../05-reactivity-indepth.md | 0 .../06-v4-migration-guide.md | 0 .../docs/07-misc/07-v5-migration-guide.md | 920 ++++++++++++++++++ .../docs/{05-misc => 07-misc}/99-faq.md | 0 .../docs/{05-misc => 07-misc}/index.md | 0 documentation/docs/98-reference/01-$state.md | 9 - .../01-introduction/06-making-an-app/text.md | 2 +- packages/svelte/README.md | 2 +- .../routes/docs/content/03-appendix/01-faq.md | 2 +- 63 files changed, 2125 insertions(+), 799 deletions(-) create mode 100644 documentation/docs/01-introduction/03-svelte-files.md create mode 100644 documentation/docs/01-introduction/04-svelte-js-files.md rename documentation/docs/{02-template-syntax/01-component-fundamentals.md => 01-introduction/xx-props.md} (63%) rename documentation/docs/01-introduction/{03-reactivity-fundamentals.md => xx-reactivity-fundamentals.md} (100%) create mode 100644 documentation/docs/02-runes/01-what-are-runes.md create mode 100644 documentation/docs/02-runes/02-$state.md create mode 100644 documentation/docs/02-runes/03-$derived.md rename documentation/docs/{03-runes/02-side-effects.md => 02-runes/04-$effect.md} (75%) create mode 100644 documentation/docs/02-runes/05-$props.md create mode 100644 documentation/docs/02-runes/06-$bindable.md create mode 100644 documentation/docs/02-runes/07-$inspect.md create mode 100644 documentation/docs/02-runes/08-$host.md rename documentation/docs/{03-runes => 02-runes}/index.md (100%) delete mode 100644 documentation/docs/03-runes/01-state.md rename documentation/docs/{02-template-syntax/02-basic-markup.md => 03-template-syntax/01-basic-markup.md} (82%) create mode 100644 documentation/docs/03-template-syntax/02-if.md create mode 100644 documentation/docs/03-template-syntax/03-each.md create mode 100644 documentation/docs/03-template-syntax/04-key.md rename documentation/docs/{02-template-syntax/10-data-fetching.md => 03-template-syntax/05-await.md} (56%) rename documentation/docs/{02-template-syntax/04-snippets.md => 03-template-syntax/06-snippet.md} (86%) create mode 100644 documentation/docs/03-template-syntax/07-@render.md create mode 100644 documentation/docs/03-template-syntax/08-@html.md create mode 100644 documentation/docs/03-template-syntax/09-@const.md rename documentation/docs/{02-template-syntax/08-bindings.md => 03-template-syntax/10-bind.md} (53%) rename documentation/docs/{02-template-syntax/07-actions.md => 03-template-syntax/11-use.md} (99%) rename documentation/docs/{02-template-syntax/06-transitions-and-animations.md => 03-template-syntax/12-transition.md} (93%) create mode 100644 documentation/docs/03-template-syntax/13-in-and-out.md create mode 100644 documentation/docs/03-template-syntax/14-animate.md create mode 100644 documentation/docs/03-template-syntax/15-class-and-style.md rename documentation/docs/{02-template-syntax => 03-template-syntax}/index.md (100%) rename documentation/docs/{02-template-syntax/03-control-flow.md => 03-template-syntax/xx-control-flow.md} (81%) create mode 100644 documentation/docs/03-template-syntax/xx-data-fetching.md rename documentation/docs/{02-template-syntax/05-styles-and-classes.md => 04-styling/01-styles-and-classes.md} (100%) create mode 100644 documentation/docs/04-styling/index.md delete mode 100644 documentation/docs/05-misc/01-debugging.md delete mode 100644 documentation/docs/05-misc/07-v5-migration-guide.md rename documentation/docs/{02-template-syntax => 05-special-elements}/09-special-elements.md (98%) create mode 100644 documentation/docs/05-special-elements/index.md rename documentation/docs/{04-runtime => 06-runtime}/01-stores.md (100%) rename documentation/docs/{04-runtime => 06-runtime}/02-context.md (100%) rename documentation/docs/{04-runtime => 06-runtime}/03-lifecycle-hooks.md (100%) rename documentation/docs/{04-runtime => 06-runtime}/04-imperative-component-api.md (100%) rename documentation/docs/{04-runtime => 06-runtime}/index.md (100%) create mode 100644 documentation/docs/07-misc/01-debugging.md rename documentation/docs/{05-misc => 07-misc}/02-testing.md (99%) rename documentation/docs/{05-misc => 07-misc}/03-typescript.md (97%) rename documentation/docs/{05-misc => 07-misc}/04-custom-elements.md (100%) rename documentation/docs/{05-misc => 07-misc}/05-reactivity-indepth.md (100%) rename documentation/docs/{05-misc => 07-misc}/06-v4-migration-guide.md (100%) create mode 100644 documentation/docs/07-misc/07-v5-migration-guide.md rename documentation/docs/{05-misc => 07-misc}/99-faq.md (100%) rename documentation/docs/{05-misc => 07-misc}/index.md (100%) delete mode 100644 documentation/docs/98-reference/01-$state.md diff --git a/.prettierignore b/.prettierignore index 410e22d4ec..d5c124353c 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,6 +1,4 @@ -# Temporarily ignore this file to avoid merge conflicts. -# see: https://github.com/sveltejs/svelte/pull/9609 -documentation/docs/05-misc/03-typescript.md +documentation/docs/ packages/**/dist/*.js packages/**/build/*.js diff --git a/documentation/blog/2020-07-17-svelte-and-typescript.md b/documentation/blog/2020-07-17-svelte-and-typescript.md index a6e07242ec..691ecdafde 100644 --- a/documentation/blog/2020-07-17-svelte-and-typescript.md +++ b/documentation/blog/2020-07-17-svelte-and-typescript.md @@ -16,7 +16,7 @@ We think it'll give you a much nicer development experience — one that also sc ## Try it now -You can start a new Svelte TypeScript project using Svelte's official scaffolding CLI by running `npm create svelte@latest` and following the prompts. This sets up a new SvelteKit project for you. +You can start a new Svelte TypeScript project using Svelte's official scaffolding CLI by running `npx sv create` and following the prompts. This sets up a new SvelteKit project for you. Alternatively you can run `npm create vite@latest myapp -- --template svelte-ts` to scaffold a Vite project using Svelte and TypeScript. diff --git a/documentation/blog/2022-12-14-announcing-sveltekit-1.0.md b/documentation/blog/2022-12-14-announcing-sveltekit-1.0.md index 0b8f081ef7..a2c569d016 100644 --- a/documentation/blog/2022-12-14-announcing-sveltekit-1.0.md +++ b/documentation/blog/2022-12-14-announcing-sveltekit-1.0.md @@ -9,7 +9,7 @@ After two years in development, [SvelteKit](https://kit.svelte.dev) has finally We’re so excited to share this release with you. It’s the culmination of thousands of hours of work, both from the Svelte core team and the wider community, and we think it’s the most enjoyable way to build production-grade websites, whether you’re a solo developer working on a small project or part of a large team. -To get started, run `npm create svelte@latest`, and visit the [docs](https://kit.svelte.dev/docs) and (experimental!) [interactive tutorial](https://learn.svelte.dev). +To get started, run `npm sv create`, and visit the [docs](https://kit.svelte.dev/docs) and (experimental!) [interactive tutorial](https://learn.svelte.dev).
diff --git a/documentation/blog/2023-06-22-svelte-4.md b/documentation/blog/2023-06-22-svelte-4.md index 7eb2bd8342..89b1e76510 100644 --- a/documentation/blog/2023-06-22-svelte-4.md +++ b/documentation/blog/2023-06-22-svelte-4.md @@ -9,7 +9,7 @@ After months in the making, we're excited to announce the stable release of Svel Time flies - Svelte 3 was released more than four years ago! In JavaScript-framework-time, that's eons. Svelte’s freshness has persisted throughout, but Node.js and browser APIs have evolved during that time and today we’re updating Svelte to take advantage of some of these improvements. Svelte 4 is mainly a maintenance release, bumping minimum version requirements and tightening up the design in specific areas. It sets the stage for the next generation of Svelte to be released as Svelte 5 - we think you’ll love it. -If you haven't tried Svelte yet, take it for a spin in our [interactive tutorial](https://learn.svelte.dev/), on [StackBlitz](https://sveltekit.new/), or locally with `npm create svelte@latest`. Svelte lets you easily put together web UIs leveraging the power of HTML, CSS, JS, and the Svelte compiler. Watch [Svelte Radio Live](https://www.youtube.com/watch?v=72TIVhRtyWE) to learn more about this release. +If you haven't tried Svelte yet, take it for a spin in our [interactive tutorial](https://learn.svelte.dev/), on [StackBlitz](https://sveltekit.new/), or locally with `npx sv create`. Svelte lets you easily put together web UIs leveraging the power of HTML, CSS, JS, and the Svelte compiler. Watch [Svelte Radio Live](https://www.youtube.com/watch?v=72TIVhRtyWE) to learn more about this release. ## What's new @@ -40,7 +40,7 @@ Stay tuned for a more in-depth blog post about all the site changes in the comin ## Migrating -Most apps and libraries that are compatible with Svelte 3 should be compatible with Svelte 4. Library authors will need to update the version range to include Svelte 4 if `svelte` is specified in the `peerDependencies`. For application authors, the most common change required will be updating tooling to meet the new minimum version requirements such as Node.js 16. Many other migration steps can be handled with `npx svelte-migrate@latest svelte-4`. +Most apps and libraries that are compatible with Svelte 3 should be compatible with Svelte 4. Library authors will need to update the version range to include Svelte 4 if `svelte` is specified in the `peerDependencies`. For application authors, the most common change required will be updating tooling to meet the new minimum version requirements such as Node.js 16. Many other migration steps can be handled with `npx sv migrate svelte-4`. Read the [migration guide](/docs/v4-migration-guide) for full details. diff --git a/documentation/blog/2023-08-31-view-transitions.md b/documentation/blog/2023-08-31-view-transitions.md index 3366955ea4..01db9262bf 100644 --- a/documentation/blog/2023-08-31-view-transitions.md +++ b/documentation/blog/2023-08-31-view-transitions.md @@ -54,7 +54,7 @@ With that out of the way, let's see how you can use view transitions in your Sve ## Getting started with view transitions -The best way to see view transitions in action is to try it yourself. You can spin up the SvelteKit demo app by running `npm create svelte@latest` in your local terminal, or in your browser on [StackBlitz](https://sveltekit.new). Make sure to use a browser that supports the view transitions API. Once you have the app running, add the following to the script block in `src/routes/+layout.svelte`. +The best way to see view transitions in action is to try it yourself. You can spin up the SvelteKit demo app by running `npx sv create` in your local terminal, or in your browser on [StackBlitz](https://sveltekit.new). Make sure to use a browser that supports the view transitions API. Once you have the app running, add the following to the script block in `src/routes/+layout.svelte`. ```js // @errors: 2305 7006 2339 2810 diff --git a/documentation/docs/01-introduction/01-overview.md b/documentation/docs/01-introduction/01-overview.md index b1218232db..5acbe4897b 100644 --- a/documentation/docs/01-introduction/01-overview.md +++ b/documentation/docs/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/documentation/docs/01-introduction/02-getting-started.md b/documentation/docs/01-introduction/02-getting-started.md index 62026018e1..940c38afe7 100644 --- a/documentation/docs/01-introduction/02-getting-started.md +++ b/documentation/docs/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/documentation/docs/01-introduction/03-svelte-files.md b/documentation/docs/01-introduction/03-svelte-files.md new file mode 100644 index 0000000000..f534e30fcb --- /dev/null +++ b/documentation/docs/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 + + + + + + + +``` + +## ` + + +``` + +You can `export` bindings from this block, and they will become exports of the compiled module. You cannot `export default`, since the default export is the component itself. + +## ` +``` + +For more information regarding styling, read the documentation around [styles and classes](styles-and-classes). diff --git a/documentation/docs/01-introduction/04-svelte-js-files.md b/documentation/docs/01-introduction/04-svelte-js-files.md new file mode 100644 index 0000000000..d0dde34111 --- /dev/null +++ b/documentation/docs/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/documentation/docs/02-template-syntax/01-component-fundamentals.md b/documentation/docs/01-introduction/xx-props.md similarity index 63% rename from documentation/docs/02-template-syntax/01-component-fundamentals.md rename to documentation/docs/01-introduction/xx-props.md index 0e5597c020..cad854d878 100644 --- a/documentation/docs/02-template-syntax/01-component-fundamentals.md +++ b/documentation/docs/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/documentation/docs/01-introduction/03-reactivity-fundamentals.md b/documentation/docs/01-introduction/xx-reactivity-fundamentals.md similarity index 100% rename from documentation/docs/01-introduction/03-reactivity-fundamentals.md rename to documentation/docs/01-introduction/xx-reactivity-fundamentals.md diff --git a/documentation/docs/02-runes/01-what-are-runes.md b/documentation/docs/02-runes/01-what-are-runes.md new file mode 100644 index 0000000000..26c1e22472 --- /dev/null +++ b/documentation/docs/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/documentation/docs/02-runes/02-$state.md b/documentation/docs/02-runes/02-$state.md new file mode 100644 index 0000000000..5c942c0444 --- /dev/null +++ b/documentation/docs/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 +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/documentation/docs/02-runes/03-$derived.md b/documentation/docs/02-runes/03-$derived.md new file mode 100644 index 0000000000..4f0d70dcc8 --- /dev/null +++ b/documentation/docs/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/documentation/docs/03-runes/02-side-effects.md b/documentation/docs/02-runes/04-$effect.md similarity index 75% rename from documentation/docs/03-runes/02-side-effects.md rename to documentation/docs/02-runes/04-$effect.md index c9bda9a1e6..02f040f931 100644 --- a/documentation/docs/03-runes/02-side-effects.md +++ b/documentation/docs/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, for example. -## `$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: @@ -289,7 +175,7 @@ In rare cases, you may need to run code _before_ the DOM updates. For this we ca
``` -Apart from the timing, `$effect.pre` works exactly like `$effect` — refer to its documentation for more info. +Apart from the timing, `$effect.pre` works exactly like `$effect`. ## `$effect.tracking` @@ -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/documentation/docs/02-runes/05-$props.md b/documentation/docs/02-runes/05-$props.md new file mode 100644 index 0000000000..fdde3a8eef --- /dev/null +++ b/documentation/docs/02-runes/05-$props.md @@ -0,0 +1,128 @@ +--- +title: $props +--- + +The inputs to a component are referred to as _props_, which is short for _properties_. You pass props to components just like you pass attributes to elements: + +```svelte + + +/// file: App.svelte + +``` + +On the other side, inside `MyComponent.svelte`, we can receive props with the `$props` rune... + +```svelte + + +/// file: MyComponent.svelte +

this component is {props.adjective}

+``` + +...though more commonly, you'll [_destructure_](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) your props: + +```svelte +/// file: MyComponent.svelte + + +

this component is {+++adjective+++}

+``` + +## Fallback values + +Destructuring allows us to declare fallback values, which are used if the parent component does not set a given prop: + +```js +/// file: MyComponent.svelte +let { adjective = 'happy' } = $props(); +``` + +> [!NOTE] Fallback values are not turned into reactive state proxies. + +## Renaming props + +We can also use the destructuring assignment to rename props, which is necessary if they're invalid identifiers, or a JavaScript keyword like `super`: + +```js +let { super: trouper = 'lights are gonna find me' } = $props(); +``` + +## Rest props + +Finally, we can use a _rest property_ to get, well, the rest of the props: + +```js +let { a, b, c, ...others } = $props(); +``` + +## Updating props + +References to a prop inside a component update when the prop itself updates — when `count` changes in `App.svelte`, it will also change inside `Child.svelte`. But the child component is able to temporarily override the prop value, which can be useful for unsaved emphemeral state ([demo](/playground/untitled#H4sIAAAAAAAAE6WQ0WrDMAxFf0WIQR0Wmu3VTQJln7HsIfVcZubIxlbGRvC_DzuBraN92qPula50tODZWB1RPi_IX16jLALWSOOUq6P3-_ihLWftNEZ9TVeOWBNHlNhGFYznfqCBzeRdYHh6M_YVzsFNsNs3pdpGd4eBcqPVDMrNxNDBXeSRtXioDgO1zU8ataeZ2RE4Utao924RFXQ9iHXwvoPHKpW1xY4g_Bg0cSVhKS0p560Za95612ZC02ONrD8ZJYdZp_rGQ37ff_mSP86Np2TWZaNNmdcH56P4P67K66_SXoK9pG-5dF5Z9QEAAA==)): + + +```svelte +/// file: App.svelte + + + + + +``` + + +```svelte +/// file: Child.svelte + + + +``` + +## Type safety + +You can add type safety to your components by annotating your props, as you would with any other variable declaration. In TypeScript that might look like this... + +```svelte + +``` + +...while in JSDoc you can do this: + +```svelte + +``` + +You can, of course, separate the type declaration from the annotation: + +```svelte + +``` + +Adding types is recommended, as it ensures that people using your component can easily discover which props they should provide. diff --git a/documentation/docs/02-runes/06-$bindable.md b/documentation/docs/02-runes/06-$bindable.md new file mode 100644 index 0000000000..14bc8ddbec --- /dev/null +++ b/documentation/docs/02-runes/06-$bindable.md @@ -0,0 +1,54 @@ +--- +title: $bindable +--- + +Ordinarily, props go one way, from parent to child. This makes it easy to understand how data flows around your app. + +In Svelte, component props can be _bound_, which means that data can also flow _up_ from child to parent. This isn't something you should do often, but it can simplify your code if used sparingly and carefully. + +It also means that a state proxy can be _mutated_ in the child. + +> [!NOTE] Mutation is also possible with normal props, but is strongly discouraged — Svelte will warn you if it detects that a component is mutating state it does not 'own'. + +To mark a prop as bindable, we use the `$bindable` rune: + + +```svelte +/// file: FancyInput.svelte + + + + + +``` + +Now, a component that uses `` can add the [`bind:`](bind) directive ([demo](/playground/untitled#H4sIAAAAAAAAE3WQwWrDMBBEf2URBSfg2nfFMZRCoYeecqx6UJx1IyqvhLUONcb_XqSkTUOSk1az7DBvJtEai0HI90nw6FHIJIhckO7i78n7IhzQctS2OuAtvXHESByEFFVoeuO5VqTYdN71DC-amvGV_MDQ9q6DrCjP0skkWymKJxYZOgxBfyKs4SGwZlxke7TWZcuVoqo8-1P1z3lraCcP2g64nk4GM5S1osrXf0JV-lrkgvGbheR-wDm_g30V8JL-1vpOCZFogpQsEsWcemtxscyhKArfOx9gjps0Lq4hzRVfemaYfu-PoIqqwKPFY_XpaIqj4tYRP7a6M3aUkD27zjSw0RTgbZN6Z8WNs66XsEP03tBXUueUJFlelvYx_wCuI3leNwIAAA==)): + + +```svelte +/// App.svelte + + + +

{message}

+``` + +The parent component doesn't _have_ to use `bind:` — it can just pass a normal prop. Some parents don't want to listen to what their children have to say. + +In this case, you can specify a fallback value for when no prop is passed at all: + +```js +/// file: FancyInput.svelte +let { value = $bindable('fallback'), ...props } = $props(); +``` diff --git a/documentation/docs/02-runes/07-$inspect.md b/documentation/docs/02-runes/07-$inspect.md new file mode 100644 index 0000000000..ff7fa92c36 --- /dev/null +++ b/documentation/docs/02-runes/07-$inspect.md @@ -0,0 +1,44 @@ +--- +title: $inspect +--- + +The `$inspect` rune is roughly equivalent to `console.log`, with the exception that it will re-run whenever its argument changes. `$inspect` tracks reactive state deeply, meaning that updating something inside an object or array using fine-grained reactivity will cause it to re-fire ([demo](/#H4sIAAAAAAAACkWQ0YqDQAxFfyUMhSotdZ-tCvu431AXtGOqQ2NmmMm0LOK_r7Utfby5JzeXTOpiCIPKT5PidkSVq2_n1F7Jn3uIcEMSXHSw0evHpAjaGydVzbUQCmgbWaCETZBWMPlKj29nxBDaHj_edkAiu12JhdkYDg61JGvE_s2nR8gyuBuiJZuDJTyQ7eE-IEOzog1YD80Lb0APLfdYc5F9qnFxjiKWwbImo6_llKRQVs-2u91c_bD2OCJLkT3JZasw7KLA2XCX31qKWE6vIzNk1fKE0XbmYrBTufiI8-_8D2cUWBA_AQAA)): + +```svelte + + + + +``` + +## $inspect(...).with + +`$inspect` returns a property `with`, which you can invoke with a callback, which will then be invoked instead of `console.log`. The first argument to the callback is either `"init"` or `"update"`; subsequent arguments are the values passed to `$inspect` ([demo](/#H4sIAAAAAAAACkVQ24qDMBD9lSEUqlTqPlsj7ON-w7pQG8c2VCchmVSK-O-bKMs-DefKYRYx6BG9qL4XQd2EohKf1opC8Nsm4F84MkbsTXAqMbVXTltuWmp5RAZlAjFIOHjuGLOP_BKVqB00eYuKs82Qn2fNjyxLtcWeyUE2sCRry3qATQIpJRyD7WPVMf9TW-7xFu53dBcoSzAOrsqQNyOe2XUKr0Xi5kcMvdDB2wSYO-I9vKazplV1-T-d6ltgNgSG1KjVUy7ZtmdbdjqtzRcphxMS1-XubOITJtPrQWMvKnYB15_1F7KKadA_AQAA)): + +```svelte + + + +``` + +A convenient way to find the origin of some change is to pass `console.trace` to `with`: + +```js +// @errors: 2304 +$inspect(stuff).with(console.trace); +``` + +> [!NOTE] `$inspect` only works during development. In a production build it becomes a noop. diff --git a/documentation/docs/02-runes/08-$host.md b/documentation/docs/02-runes/08-$host.md new file mode 100644 index 0000000000..7b5e041e5e --- /dev/null +++ b/documentation/docs/02-runes/08-$host.md @@ -0,0 +1,37 @@ +--- +title: $host +--- + +When compiling a component as a custom element, the `$host` rune provides access to the host element, allowing you to (for example) dispatch custom events ([demo](/playground/untitled#H4sIAAAAAAAAE41Ry2rDMBD8FSECtqkTt1fHFpSSL-ix7sFRNkTEXglrnTYY_3uRlDgxTaEHIfYxs7szA9-rBizPPwZOZwM89wmecqxbF70as7InaMjltrWFR3mpkQDJ8pwXVnbKkKiwItUa3RGLVtk7gTHQXRDR2lXda4CY1D0SK9nCUk0QPyfrCovsRoNFe17aQOAwGncgO2gBqRzihJXiQrEs2csYOhQ-7HgKHaLIbpRhhBG-I2eD_8ciM4KnnOCbeE5dD2P6h0Dz0-Yi_arNhPLJXBtSGi2TvSXdbpqwdsXvjuYsC1veabvvUTog2ylrapKH2G2XsMFLS4uDthQnq2t1cwKkGOGLvYU5PvaQxLsxOkPmsm97Io1Mo2yUPF6VnOZFkw1RMoopKLKAE_9gmGxyDFMwMcwN-Bx_ABXQWmOtAgAA)): + + +```svelte +/// file: Stepper.svelte + + + + + + +``` + + +```svelte +/// file: App.svelte + + + count -= 1} + onincrement={() => count += 1} +> + +

count: {count}

+``` diff --git a/documentation/docs/03-runes/index.md b/documentation/docs/02-runes/index.md similarity index 100% rename from documentation/docs/03-runes/index.md rename to documentation/docs/02-runes/index.md diff --git a/documentation/docs/03-runes/01-state.md b/documentation/docs/03-runes/01-state.md deleted file mode 100644 index 1ab89fa239..0000000000 --- a/documentation/docs/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/documentation/docs/02-template-syntax/02-basic-markup.md b/documentation/docs/03-template-syntax/01-basic-markup.md similarity index 82% rename from documentation/docs/02-template-syntax/02-basic-markup.md rename to documentation/docs/03-template-syntax/01-basic-markup.md index e40c78a7cb..07b093df87 100644 --- a/documentation/docs/02-template-syntax/02-basic-markup.md +++ b/documentation/docs/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 -``` - -While this works, it makes working with promises somewhat unergonomic. Svelte alleviates this problem using the `#await` block. - -## {#await ...} - ```svelte {#await expression}...{:then name}...{:catch name}...{/await} @@ -35,9 +22,7 @@ While this works, it makes working with promises somewhat unergonomic. Svelte al {#await expression catch name}...{/await} ``` -Await blocks allow you to branch on the three possible states of a Promise — pending, fulfilled or rejected. -In SSR mode, only the pending branch will be rendered on the server. -If the provided expression is not a Promise only the fulfilled branch will be rendered, including in SSR mode. +Await blocks allow you to branch on the three possible states of a [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) — pending, fulfilled or rejected. ```svelte {#await promise} @@ -52,6 +37,10 @@ If the provided expression is not a Promise only the fulfilled branch will be re {/await} ``` +> [!NOTE] During server-side rendering, only the pending branch will be rendered. +> +> If the provided expression is not a `Promise` only the `:then` branch will be rendered, including during server-side rendering. + The `catch` block can be omitted if you don't need to render anything when the promise rejects (or no error is possible). ```svelte @@ -79,7 +68,3 @@ Similarly, if you only want to show the error state, you can omit the `then` blo

The error is {error}

{/await} ``` - -## SvelteKit loaders - -Fetching inside your components is great for simple use cases, but it's prone to data loading waterfalls and makes code harder to work with because of the promise handling. SvelteKit solves this problem by providing a opinionated data loading story that is coupled to its router. Learn more about it [in the docs](../kit). diff --git a/documentation/docs/02-template-syntax/04-snippets.md b/documentation/docs/03-template-syntax/06-snippet.md similarity index 86% rename from documentation/docs/02-template-syntax/04-snippets.md rename to documentation/docs/03-template-syntax/06-snippet.md index 1609698e16..70aac3fd2a 100644 --- a/documentation/docs/02-template-syntax/04-snippets.md +++ b/documentation/docs/03-template-syntax/06-snippet.md @@ -1,15 +1,18 @@ --- -title: Snippets +title: {#snippet ...} --- -Better title needed? +```svelte + +{#snippet name()}...{/if} +``` -- `#snippet` -- `@render` -- how they can be used to reuse markup -- how they can be used to pass UI content to components +```svelte + +{#snippet name(param1, param2, paramN)}...{/if} +``` -Snippets, and _render tags_, are a way to create reusable chunks of markup inside your components. Instead of writing duplicative code like [this](/#H4sIAAAAAAAAE5VUYW-kIBD9K8Tmsm2yXXRzvQ-s3eR-R-0HqqOQKhAZb9sz_vdDkV1t000vRmHewMx7w2AflbIGG7GnPlK8gYhFv42JthG-m9Gwf6BGcLbVXZuPSGrzVho8ZirDGpDIhldgySN5GpEMez9kaNuckY1ANJZRamRuu2ZnhEZt6a84pvs43mzD4pMsUDDi8DMkQFYCGdkvsJwblFq5uCik9bmJ4JZwUkv1eoknWigX2eGNN6aGXa6bjV8ybP-X7sM36T58SVcrIIV2xVIaA41xeD5kKqWXuqpUJEefOqVuOkL9DfBchGrzWfu0vb-RpTd3o-zBR045Ga3HfuE5BmJpKauuhbPtENlUF2sqR9jqpsPSxWsMrlngyj3VJiyYjJXb1-lMa7IWC-iSk2M5Zzh-SJjShe-siq5kpZRPs55BbSGU5YPyte4vVV_VfFXxVb10dSLf17pS2lM5HnpPxw4Zpv6x-F57p0jI3OKlVnhv5V9wPQrNYQQ9D_f6aGHlC89fq1Z3qmDkJCTCweOGF4VUFSPJvD_DhreVdA0eu8ehJJ5x91dBaBkpWm3ureCFPt3uzRv56d4kdp-2euG38XZ6dsnd3ZmPG9yRBCrzRUvi-MccOdwz3qE-fOZ7AwAhlrtTUx3c76vRhSwlFBHDtoPhefgHX3dM0PkEAAA=)... +Snippets, and [render tags](@render), are a way to create reusable chunks of markup inside your components. Instead of writing duplicative code like [this](/#H4sIAAAAAAAAE5VUYW-kIBD9K8Tmsm2yXXRzvQ-s3eR-R-0HqqOQKhAZb9sz_vdDkV1t000vRmHewMx7w2AflbIGG7GnPlK8gYhFv42JthG-m9Gwf6BGcLbVXZuPSGrzVho8ZirDGpDIhldgySN5GpEMez9kaNuckY1ANJZRamRuu2ZnhEZt6a84pvs43mzD4pMsUDDi8DMkQFYCGdkvsJwblFq5uCik9bmJ4JZwUkv1eoknWigX2eGNN6aGXa6bjV8ybP-X7sM36T58SVcrIIV2xVIaA41xeD5kKqWXuqpUJEefOqVuOkL9DfBchGrzWfu0vb-RpTd3o-zBR045Ga3HfuE5BmJpKauuhbPtENlUF2sqR9jqpsPSxWsMrlngyj3VJiyYjJXb1-lMa7IWC-iSk2M5Zzh-SJjShe-siq5kpZRPs55BbSGU5YPyte4vVV_VfFXxVb10dSLf17pS2lM5HnpPxw4Zpv6x-F57p0jI3OKlVnhv5V9wPQrNYQQ9D_f6aGHlC89fq1Z3qmDkJCTCweOGF4VUFSPJvD_DhreVdA0eu8ehJJ5x91dBaBkpWm3ureCFPt3uzRv56d4kdp-2euG38XZ6dsnd3ZmPG9yRBCrzRUvi-MccOdwz3qE-fOZ7AwAhlrtTUx3c76vRhSwlFBHDtoPhefgHX3dM0PkEAAA=)... ```svelte {#each images as image} @@ -34,12 +37,7 @@ Snippets, and _render tags_, are a way to create reusable chunks of markup insid ```svelte {#snippet figure(image)}
- {image.caption} + {image.caption}
{image.caption}
{/snippet} @@ -248,6 +246,10 @@ We can tighten things up further by declaring a generic, so that `data` and `row ``` +## Programmatic snippets + +Snippets can be created programmatically with the [`createRawSnippet`](svelte#createRawSnippet) API. This is intended for advanced use cases. + ## Snippets and slots In Svelte 4, content can be passed to components using [slots](https://svelte.dev/docs/special-elements#slot). Snippets are more powerful and flexible, and as such slots are deprecated in Svelte 5. diff --git a/documentation/docs/03-template-syntax/07-@render.md b/documentation/docs/03-template-syntax/07-@render.md new file mode 100644 index 0000000000..b7e41e8337 --- /dev/null +++ b/documentation/docs/03-template-syntax/07-@render.md @@ -0,0 +1,39 @@ +--- +title: {@render ...} +--- + +To render a [snippet](snippet), use a `{@render ...}` tag. + +```svelte +{#snippet sum(a, b)} +

{a} + {b} = {a + b}

+{/snippet} + +{@render sum(1, 2)} +{@render sum(3, 4)} +{@render sum(5, 6)} +``` + +The expression can be an identifer like `sum`, or an arbitrary JavaScript expression: + +```svelte +{@render (cool ? coolSnippet : lameSnippet)()} +``` + +## Optional snippets + +If the snippet is potentially undefined — for example, because it's an incoming prop — then you can use optional chaining to only render it when it _is_ defined: + +```svelte +{@render children?.()} +``` + +Alternatively, use an [`{#if ...}`](if) block with an `:else` clause to render fallback content: + +```svelte +{#if children} + {@render children()} +{:else} +

fallback content

+{/if} +``` diff --git a/documentation/docs/03-template-syntax/08-@html.md b/documentation/docs/03-template-syntax/08-@html.md new file mode 100644 index 0000000000..28a0cdb470 --- /dev/null +++ b/documentation/docs/03-template-syntax/08-@html.md @@ -0,0 +1,51 @@ +--- +title: {@html ...} +--- + +To inject raw HTML into your component, use the `{@html ...}` tag: + +```svelte +
+ {@html content} +
+``` + +> [!NOTE] Make sure that you either escape the passed string or only populate it with values that are under your control in order to prevent [XSS attacks](https://owasp.org/www-community/attacks/xss/). Never render unsanitized content. + +The expression should be valid standalone HTML — this will not work, because `
` is not valid HTML: + +```svelte +{@html '
'}content{@html '
'} +``` + +It also will not compile Svelte code. + +## Styling + +Content rendered this way is 'invisible' to Svelte and as such will not receive [scoped styles](styles-and-classes) — in other words, this will not work, and the `a` and `img` styles will be regarded as unused: + + +```svelte +
+ {@html content} +
+ + +``` + +Instead, use the `:global` modifier to target everything inside the `
`: + + +```svelte + +``` diff --git a/documentation/docs/03-template-syntax/09-@const.md b/documentation/docs/03-template-syntax/09-@const.md new file mode 100644 index 0000000000..f4bde77c23 --- /dev/null +++ b/documentation/docs/03-template-syntax/09-@const.md @@ -0,0 +1,14 @@ +--- +title: {@const ...} +--- + +The `{@const ...}` tag defines a local constant. + +```svelte +{#each boxes as box} + {@const area = box.width * box.height} + {box.width} * {box.height} = {area} +{/each} +``` + +`{@const}` is only allowed as an immediate child of a block — `{#if ...}`, `{#each ...}`, `{#snippet ...}` and so on — or a ``. diff --git a/documentation/docs/02-template-syntax/08-bindings.md b/documentation/docs/03-template-syntax/10-bind.md similarity index 53% rename from documentation/docs/02-template-syntax/08-bindings.md rename to documentation/docs/03-template-syntax/10-bind.md index b1269000fe..70d7d25920 100644 --- a/documentation/docs/02-template-syntax/08-bindings.md +++ b/documentation/docs/03-template-syntax/10-bind.md @@ -1,47 +1,97 @@ --- -title: Bindings +title: bind: --- -- how for dom elements -- list of all bindings -- how for components +Data ordinarily flows down, from parent to child. The `bind:` directive allows data to flow the other way, from child to parent. -Most of the time a clear separation between data flowing down and events going up is worthwhile and results in more robust apps. But in some cases - especially when interacting with form elements - it's more ergonomic to declare a two way binding. Svelte provides many element bindings out of the box, and also allows component bindings. - -## bind:_property_ for elements +The general syntax is `bind:property={expression}`, where `expression` is an _lvalue_ (i.e. a variable or an object property). When the expression is an identifier with the same name as the property, we can omit the expression — in other words these are equivalent: + ```svelte - -bind:property={variable} + + ``` -Data ordinarily flows down, from parent to child. The `bind:` directive allows data to flow the other way, from child to parent. Most bindings are specific to particular elements. +Svelte creates an event listener that updates the bound value. If an element already has a listener for the same event, that listener will be fired before the bound value is updated. + +Most bindings are _two-way_, meaning that changes to the value will affect the element and vice versa. A few bindings are _readonly_, meaning that changing their value will have no effect on the element. -The simplest bindings reflect the value of a property, such as `input.value`. +## `` +A `bind:value` directive on an `` element binds the input's `value` property: + + ```svelte - -