diff --git a/apps/svelte.dev/content/tutorial/01-svelte/01-introduction/01-welcome-to-svelte/index.md b/apps/svelte.dev/content/tutorial/01-svelte/01-introduction/01-welcome-to-svelte/index.md index 0701a69017..fcf895270a 100644 --- a/apps/svelte.dev/content/tutorial/01-svelte/01-introduction/01-welcome-to-svelte/index.md +++ b/apps/svelte.dev/content/tutorial/01-svelte/01-introduction/01-welcome-to-svelte/index.md @@ -18,12 +18,13 @@ You can build your entire app with Svelte (for example, using an application fra > You'll need to have basic familiarity with HTML, CSS and JavaScript to understand Svelte. -This tutorial is split into four main parts: +This tutorial is split into five main parts: - [Basic Svelte](/tutorial/welcome-to-svelte) (you are here) - [Advanced Svelte](/tutorial/tweens) - [Basic SvelteKit](/tutorial/introducing-sveltekit) - [Advanced SvelteKit](/tutorial/optional-params) +- [Migrating from Svelte 4 to 5](/tutorial/migration-overview) Each section will present an exercise designed to illustrate a feature. Later exercises build on the knowledge gained in earlier ones, so it's recommended that you go from start to finish. If necessary, you can navigate via the menu above. diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/+assets/src/routes/+error.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/+assets/src/routes/+error.svelte new file mode 100644 index 0000000000..7e25aa26ec --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/+assets/src/routes/+error.svelte @@ -0,0 +1,26 @@ + + +{#if $page.status === 404} +

Not found

+

Go to /

+{:else} +

+ Server-side rendering failed with HTTP status + code + {$page.status} +

+{/if} + + diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/+assets/src/routes/+layout.js b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/+assets/src/routes/+layout.js new file mode 100644 index 0000000000..a3d15781a7 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/+assets/src/routes/+layout.js @@ -0,0 +1 @@ +export const ssr = false; diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/+assets/src/routes/+page.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/+assets/src/routes/+page.svelte new file mode 100644 index 0000000000..04da569127 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/+assets/src/routes/+page.svelte @@ -0,0 +1,5 @@ + + + diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/01-migration-overview/+assets/app-a/src/lib/App.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/01-migration-overview/+assets/app-a/src/lib/App.svelte new file mode 100644 index 0000000000..18d9be1d1e --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/01-migration-overview/+assets/app-a/src/lib/App.svelte @@ -0,0 +1,7 @@ + + +

Welcome to Svelte {version}!

+ + diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/01-migration-overview/index.md b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/01-migration-overview/index.md new file mode 100644 index 0000000000..1399836956 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/01-migration-overview/index.md @@ -0,0 +1,9 @@ +--- +title: Migration overview +--- + +Svelte 5 is the next incarnation of Svelte. It's the culmination of our learnings over the course of five years. + +On first look a lot of things have changed between version 3/4 and 5. But on a closer look you will find a lot of similarities, many unchanged parts of the syntax, and hopefully the same familiar feeling that got you into Svelte. + +This tutorial is meant for people who already know Svelte and are upgrading to Svelte 5. It will go through each of the syntax changes along with explanations of why we did it. For a complete list of all changes (however tiny they are) head over to _TODO LINK TO LIST OF BREAKING CHANGES_. diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/02-state-migration/+assets/app-a/src/lib/App.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/02-state-migration/+assets/app-a/src/lib/App.svelte new file mode 100644 index 0000000000..26b386e223 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/02-state-migration/+assets/app-a/src/lib/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/02-state-migration/+assets/app-b/src/lib/App.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/02-state-migration/+assets/app-b/src/lib/App.svelte new file mode 100644 index 0000000000..63225a3fdd --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/02-state-migration/+assets/app-b/src/lib/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/02-state-migration/index.md b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/02-state-migration/index.md new file mode 100644 index 0000000000..626cdefbac --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/02-state-migration/index.md @@ -0,0 +1,19 @@ +--- +title: State +--- + +At the heart of Svelte 5 is the new runes API. Runes are basically compiler instructions that inform Svelte about reactivity. Syntactically, runes are functions starting with a dollar-sign. + +In Svelte 4, a `let` declaration at the top level of a component was implicitly reactive. In Svelte 5, things are more explicit: a variable is reactive when created using the `$state` rune. Let's migrate the counter to runes mode by wrapping the counter in `$state`: + +```svelte + +``` + +Nothing else changes. `count` is still the number itself, and you read and write directly to it, without a wrapper like `.value` or `getCount()`. + +## Why we did this + +`let` being implicitly reactive at the top level worked great, but it meant that reactivity was constrained - a `let` declaration anywhere else was not reactive. This forced you to resort to using stores when refactoring code out of the top level of components for reuse. This meant you had to learn an entirely separate reactivity model, and the result often wasn't as nice to work with. Because reactivity is more explicit in Svelte 5, you can keep using the same API in an outside the top level of components. Head to TODO LINK TO TUTORIAL to learn more. diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/03-derived-migration/+assets/app-a/src/lib/App.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/03-derived-migration/+assets/app-a/src/lib/App.svelte new file mode 100644 index 0000000000..b6241a4bcd --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/03-derived-migration/+assets/app-a/src/lib/App.svelte @@ -0,0 +1,6 @@ + + + diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/03-derived-migration/+assets/app-b/src/lib/App.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/03-derived-migration/+assets/app-b/src/lib/App.svelte new file mode 100644 index 0000000000..86a30a9c54 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/03-derived-migration/+assets/app-b/src/lib/App.svelte @@ -0,0 +1,6 @@ + + + diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/03-derived-migration/index.md b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/03-derived-migration/index.md new file mode 100644 index 0000000000..32de6a8742 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/03-derived-migration/index.md @@ -0,0 +1,35 @@ +--- +title: Derivations +--- + +In Svelte 4, a `$:` statement at the top level of a component could be used to declare a derivation, i.e. state that is entirely defined through a computation of other state. In Svelte 5, this is achieved using the `$derived` rune: + +```svelte + +``` + +As with `$state`, nothing else changes. `double` is still the number itself, and you read it directly, without a wrapper like `.value` or `getCount()`. + +## Why we did this + +`$:` was a great shorthand and intuitive to get started with: you could slap a `$:` in front of most code and it would somehow work. This intuitiveness was also its drawback the more complicated your code became, because it wasn't as easy to reason about. Was the intent of the code to create a derivation, or a side effect? + +There were also gotchas that were hard to spot: + +- `$:` only updated directly before rendering, which meant you could read stale values in-between rerenders +- `$:` only ran once per tick, which meant that statements may run less often than you think +- `$:` dependencies were determined through static analysis of the dependencies. This worked in most cases, but could break in subtle ways during a refactoring where dependencies would be for example moved into a function and no longer be visible as a result +- `$:` statements were also ordered by using static analysis of the dependencies. In some cases there could be ties and the ordering would be wrong as a result, needing manual interventions. Ordering could also break while refactoring code and some dependencies no longer being visible as a result. + +Lastly, it wasn't TypeScript-friendly (our editor tooling had to jump through some hoops to make it valid for TypeScript), which was a blocker for making Svelte's reactivity model truly universal. + +`$derived` fixes all of these by + +- always returning the latest value +- running as often as needed to be stable +- determining the dependencies at runtime, and therefore being immune to refactorings +- executing dependencies as need and therefore being immune to ordering problems +- being TypeScript-friendly diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/04-effect-migration/+assets/app-a/src/lib/App.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/04-effect-migration/+assets/app-a/src/lib/App.svelte new file mode 100644 index 0000000000..f8da626d53 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/04-effect-migration/+assets/app-a/src/lib/App.svelte @@ -0,0 +1,10 @@ + + + diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/04-effect-migration/+assets/app-b/src/lib/App.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/04-effect-migration/+assets/app-b/src/lib/App.svelte new file mode 100644 index 0000000000..f1c94d9221 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/04-effect-migration/+assets/app-b/src/lib/App.svelte @@ -0,0 +1,10 @@ + + + diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/04-effect-migration/index.md b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/04-effect-migration/index.md new file mode 100644 index 0000000000..a6ce6e6d1d --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/04-effect-migration/index.md @@ -0,0 +1,22 @@ +--- +title: Side effects +--- + +In Svelte 4, a `$:` statement at the top level of a component could also be used to create side effects. In Svelte 5, this is achieved using the `$effect` rune: + +```svelte + +``` + +As with `$state`, nothing else changes. `double` is still the number itself, and you read it directly, without a wrapper like `.value` or `getCount()`. + +## Why we did this + +Most of the rationale is explained in the previous section already. Additionally, `$:` could be used for all kinds of things: Derivations, side effects, mix the two - you could even create state with it instead of using `let`. This meant that while it was easy to write code, it became harder to read the code and reason about it. With `$derived` and `$effect`, you have a bit more up-front decision making to do (spoiler alert: 90% of the time you want `$derived`), but future-you and other developers on your team will have an easier time. diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/05-props-migration-1/+assets/app-a/src/lib/App.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/05-props-migration-1/+assets/app-a/src/lib/App.svelte new file mode 100644 index 0000000000..6529413003 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/05-props-migration-1/+assets/app-a/src/lib/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/05-props-migration-1/+assets/app-a/src/lib/Nested.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/05-props-migration-1/+assets/app-a/src/lib/Nested.svelte new file mode 100644 index 0000000000..b5ba51435e --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/05-props-migration-1/+assets/app-a/src/lib/Nested.svelte @@ -0,0 +1,7 @@ + + +

Optional: {optional}

+

Required: {required}

diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/05-props-migration-1/+assets/app-b/src/lib/Nested.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/05-props-migration-1/+assets/app-b/src/lib/Nested.svelte new file mode 100644 index 0000000000..0cdf32599d --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/05-props-migration-1/+assets/app-b/src/lib/Nested.svelte @@ -0,0 +1,6 @@ + + +

Optional: {optional}

+

Required: {required}

diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/05-props-migration-1/index.md b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/05-props-migration-1/index.md new file mode 100644 index 0000000000..0bade91fd8 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/05-props-migration-1/index.md @@ -0,0 +1,19 @@ +--- +title: Component props +--- + +In Svelte 4, properties of a component were declared using `export let`. Each property was one declaration. In Svelte 5, all properties are declared through the `$props` rune, through destructuring: + +```svelte + +``` + +## Why we did this + +`export let` was one of the more controversial API decisions, and there was a lot of debate about whether you should think about a property being `export`ed or `import`ed. `$props` doesn't have this trait. It's also in line with the other runes, and the general thinking reduces to "everything special to reactivity in Svelte is a rune". + +There were also a lot of limitations around `export let`, which required additional API. These are discussed in the next section. diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/06-props-migration-2/+assets/app-a/src/lib/App.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/06-props-migration-2/+assets/app-a/src/lib/App.svelte new file mode 100644 index 0000000000..77270433f1 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/06-props-migration-2/+assets/app-a/src/lib/App.svelte @@ -0,0 +1,5 @@ + + +

{string}

diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/06-props-migration-2/+assets/app-b/src/lib/App.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/06-props-migration-2/+assets/app-b/src/lib/App.svelte new file mode 100644 index 0000000000..463eb8250e --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/06-props-migration-2/+assets/app-b/src/lib/App.svelte @@ -0,0 +1,5 @@ + + +

{@html string}

diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/06-props-migration-2/index.md b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/06-props-migration-2/index.md new file mode 100644 index 0000000000..6b0a5c3622 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/06-props-migration-2/index.md @@ -0,0 +1,37 @@ +--- +title: Component props (advanced) +--- + +There are multiple cases where declaring properties becomes less straightforward than having a few `export let` declarations: + +- you want to rename the property, for example because the name is a reserved identifier (e.g. `class`) +- you don't know which other properties to expect in advance +- you want to forward every property to another component + +All these cases need special syntax in Svelte 4: + +- renaming: `export { klass as class}` +- other properties: `$$restProps` +- all properties `$$props` + +In Svelte 5, the `$props` rune makes this straightforward without any additional Svelte-specific syntax: + +- renaming: use property renaming `let { class: klass } = $props();` +- other properties: use spreading `let { foo, bar, ...rest } = $props();` +- all properties: don't destructure `let props = $props();` + +Let's transform our component to using the new syntax. + +```svelte + + + +``` + +## Why we did this + +It should become clear by now that `export let` had a lot of limitations beyond simple cases, which meant we had to add more APIs. With `$props` we can remove a lot of that stuff in favor of a simpler, more robust model. diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/index.md b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/index.md new file mode 100644 index 0000000000..aab57b5330 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/01-runes/index.md @@ -0,0 +1,5 @@ +--- +title: $/let/... -> runes +scope: { 'prefix': '/src/lib/', 'name': 'src' } +focus: /src/lib/App.svelte +--- diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-event-attributes/01-dom-event-migration/+assets/app-a/src/lib/App.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-event-attributes/01-dom-event-migration/+assets/app-a/src/lib/App.svelte new file mode 100644 index 0000000000..18d9be1d1e --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-event-attributes/01-dom-event-migration/+assets/app-a/src/lib/App.svelte @@ -0,0 +1,7 @@ + + +

Welcome to Svelte {version}!

+ + diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-event-attributes/01-dom-event-migration/index.md b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-event-attributes/01-dom-event-migration/index.md new file mode 100644 index 0000000000..fabcbaa203 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-event-attributes/01-dom-event-migration/index.md @@ -0,0 +1,11 @@ +--- +title: Dom events +--- + +Svelte 5 changes the way we do event handling. + +TODO on:click -> onclick + +## Why we did this + +The change in itself doesn't seem all that relevant or even unnecessary, but it unlocks crucial capabilities like using callback props for consistency, spreading events, and more. See the next sections for more details. diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-event-attributes/02-component-events-migration/+assets/app-a/src/lib/App.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-event-attributes/02-component-events-migration/+assets/app-a/src/lib/App.svelte new file mode 100644 index 0000000000..26b386e223 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-event-attributes/02-component-events-migration/+assets/app-a/src/lib/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-event-attributes/02-component-events-migration/+assets/app-b/src/lib/App.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-event-attributes/02-component-events-migration/+assets/app-b/src/lib/App.svelte new file mode 100644 index 0000000000..63225a3fdd --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-event-attributes/02-component-events-migration/+assets/app-b/src/lib/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-event-attributes/02-component-events-migration/index.md b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-event-attributes/02-component-events-migration/index.md new file mode 100644 index 0000000000..255551cfb1 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-event-attributes/02-component-events-migration/index.md @@ -0,0 +1,18 @@ +--- +title: Component events +--- + +TODO some createEventDispatcher stuff migrated to props + +## Why we did this + +`createEventDispatcher` was always a bit boilerplate-y: + +- import the function +- call the function to get a dispatch function +- call said dispatch function with a string and possibly a payload +- retrieve said payload on the other end through a `.details` property, because the event itself was always a `CustomEvent` + +It was always possible to use component callback props, but because you had to listen to dom events using `on:`, it made sense to use `createEventDispatcher` for component events due to syntactical consiscency. Now that we have event attributes (`onclick`), it's the other way around: Callback props are now the more sensible thing to do. + +They also unlock event spreading, which we discuss in the next section. diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-event-attributes/02-event-forwarding-migration/+assets/app-a/src/lib/App.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-event-attributes/02-event-forwarding-migration/+assets/app-a/src/lib/App.svelte new file mode 100644 index 0000000000..26b386e223 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-event-attributes/02-event-forwarding-migration/+assets/app-a/src/lib/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-event-attributes/02-event-forwarding-migration/+assets/app-b/src/lib/App.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-event-attributes/02-event-forwarding-migration/+assets/app-b/src/lib/App.svelte new file mode 100644 index 0000000000..63225a3fdd --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-event-attributes/02-event-forwarding-migration/+assets/app-b/src/lib/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-event-attributes/02-event-forwarding-migration/index.md b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-event-attributes/02-event-forwarding-migration/index.md new file mode 100644 index 0000000000..18298d17c0 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-event-attributes/02-event-forwarding-migration/index.md @@ -0,0 +1,9 @@ +--- +title: Event forwarding +--- + +TODO event forwarding + +## Why we did this + +This is a huge improvement over the old syntax: We had to manually forward each event separately, not know which of the events the consumer is actually interested in. With event spreading, we turn it around - the consumer is now in charge, and the component can spread events like props onto other components or the Dom. diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-event-attributes/index.md b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-event-attributes/index.md new file mode 100644 index 0000000000..908c2b5041 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-event-attributes/index.md @@ -0,0 +1,5 @@ +--- +title: Event directives -> event attributes +scope: { 'prefix': '/src/lib/', 'name': 'src' } +focus: /src/lib/App.svelte +--- diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/01-slots-migration/+assets/app-a/src/lib/App.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/01-slots-migration/+assets/app-a/src/lib/App.svelte new file mode 100644 index 0000000000..6ddf52dcca --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/01-slots-migration/+assets/app-a/src/lib/App.svelte @@ -0,0 +1,34 @@ + + +
+ + Patrick BATEMAN + Vice President + + 212 555 6342 + + + Pierce & Pierce + Mergers and Aquisitions + + + 358 Exchange Place, New York, N.Y. 10099 fax 212 555 6390 telex 10 4534 + +
+ + \ No newline at end of file diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/01-slots-migration/+assets/app-a/src/lib/Card.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/01-slots-migration/+assets/app-a/src/lib/Card.svelte new file mode 100644 index 0000000000..7395157ba0 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/01-slots-migration/+assets/app-a/src/lib/Card.svelte @@ -0,0 +1,50 @@ +
+
+ + +
+ + + +
+ +
+
+ + diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/01-slots-migration/+assets/app-a/src/lib/paper.svg b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/01-slots-migration/+assets/app-a/src/lib/paper.svg new file mode 100644 index 0000000000..5dba50c15f --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/01-slots-migration/+assets/app-a/src/lib/paper.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/01-slots-migration/+assets/app-a/src/lib/wood.svg b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/01-slots-migration/+assets/app-a/src/lib/wood.svg new file mode 100644 index 0000000000..5157ea83b5 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/01-slots-migration/+assets/app-a/src/lib/wood.svg @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/01-slots-migration/+assets/app-b/src/lib/App.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/01-slots-migration/+assets/app-b/src/lib/App.svelte new file mode 100644 index 0000000000..2e95cc11ac --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/01-slots-migration/+assets/app-b/src/lib/App.svelte @@ -0,0 +1,37 @@ + + +
+ + Patrick BATEMAN + Vice President + + {#snippet telephone()}212 555 6342{/snippet} + + {#snippet company()} + Pierce & Pierce + Mergers and Aquisitions + {/snippet} + + {#snippet address()} + 358 Exchange Place, New York, N.Y. 10099 + fax 212 555 6390 telex 10 4534 + {/snippet} + +
+ + \ No newline at end of file diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/01-slots-migration/+assets/app-b/src/lib/Card.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/01-slots-migration/+assets/app-b/src/lib/Card.svelte new file mode 100644 index 0000000000..fdad3df09f --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/01-slots-migration/+assets/app-b/src/lib/Card.svelte @@ -0,0 +1,54 @@ + + +
+
+ {@render telephone()} + {@render company()} +
+ + {@render children()} + +
+ {@render address()} +
+
+ + diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/01-slots-migration/index.md b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/01-slots-migration/index.md new file mode 100644 index 0000000000..c86703ecf1 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/01-slots-migration/index.md @@ -0,0 +1,9 @@ +--- +title: Slotted content +--- + +TODO `` -> `{@render ...}` + +## Why we did this + +... diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/02-slot-props-migration/+assets/app-a/src/lib/App.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/02-slot-props-migration/+assets/app-a/src/lib/App.svelte new file mode 100644 index 0000000000..26b386e223 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/02-slot-props-migration/+assets/app-a/src/lib/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/02-slot-props-migration/+assets/app-b/src/lib/App.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/02-slot-props-migration/+assets/app-b/src/lib/App.svelte new file mode 100644 index 0000000000..63225a3fdd --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/02-slot-props-migration/+assets/app-b/src/lib/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/02-slot-props-migration/index.md b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/02-slot-props-migration/index.md new file mode 100644 index 0000000000..5ce8d754e9 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/02-slot-props-migration/index.md @@ -0,0 +1,9 @@ +--- +title: Slot properties +--- + +TODO let:x -> {#snippet ...} + +## Why we did this + +... diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/03-optional-slots-migration/+assets/app-a/src/lib/App.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/03-optional-slots-migration/+assets/app-a/src/lib/App.svelte new file mode 100644 index 0000000000..26b386e223 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/03-optional-slots-migration/+assets/app-a/src/lib/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/03-optional-slots-migration/+assets/app-b/src/lib/App.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/03-optional-slots-migration/+assets/app-b/src/lib/App.svelte new file mode 100644 index 0000000000..63225a3fdd --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/03-optional-slots-migration/+assets/app-b/src/lib/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/03-optional-slots-migration/index.md b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/03-optional-slots-migration/index.md new file mode 100644 index 0000000000..53e7f5e9be --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/03-optional-slots-migration/index.md @@ -0,0 +1,9 @@ +--- +title: Optional content +--- + +TODO $$slots + +## Why we did this + +... diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/index.md b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/index.md new file mode 100644 index 0000000000..1c2a543b65 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/02-snippets/index.md @@ -0,0 +1,5 @@ +--- +title: Slots -> snippets +scope: { 'prefix': '/src/lib/', 'name': 'src' } +focus: /src/lib/App.svelte +--- diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/03-migration-script/01-migration-script-overview/+assets/app-a/src/lib/App.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/03-migration-script/01-migration-script-overview/+assets/app-a/src/lib/App.svelte new file mode 100644 index 0000000000..30404ce4c5 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/03-migration-script/01-migration-script-overview/+assets/app-a/src/lib/App.svelte @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/03-migration-script/01-migration-script-overview/index.md b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/03-migration-script/01-migration-script-overview/index.md new file mode 100644 index 0000000000..a857ad15a6 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/03-migration-script/01-migration-script-overview/index.md @@ -0,0 +1,18 @@ +--- +title: Migration script overview +--- + +By now you should have a pretty good understanding of the before->after and how the old syntax related to the new syntax. It probably also become clear that a lot of these migrations are rather technical and repetitive - something you don't want to do by hand. + +We thought the same, which is why we provide a migration script to do most of the migration automatically. You can upgrade your project by using `npx svelte-migrate svelte-5`. This will do the following things: + +- bump core dependencies in your `package.json` +- migrate to runes (`let` -> `$state` etc) +- migrate to event attributes for Dom elements (`on:click` -> `onclick`) +- migrate slot creations to render tags (`` -> `{@render children()}`) +- migrate slot usages to snippets (`
...
` -> `{#snippet x()}
...
{/snippet}`) +- migrate obvious component creations (`new Component(...)` -> `mount(Component, ...)`) + +You can also migrate a single component in VS Code through the `Migrate to Svelte 5 syntax` command, or in our Playground through the `Migrate` button. For this tutorial, press the "solve" buttons to see what the migration script can do automatically. + +As you can see, it got most of the work done. It uses some methods from `svelte/legacy` though. Let's look at these more closely in the following sections. diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/03-migration-script/02-migration-script-effects/+assets/app-a/src/lib/App.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/03-migration-script/02-migration-script-effects/+assets/app-a/src/lib/App.svelte new file mode 100644 index 0000000000..30404ce4c5 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/03-migration-script/02-migration-script-effects/+assets/app-a/src/lib/App.svelte @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/03-migration-script/02-migration-script-effects/index.md b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/03-migration-script/02-migration-script-effects/index.md new file mode 100644 index 0000000000..6309c25180 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/03-migration-script/02-migration-script-effects/index.md @@ -0,0 +1,7 @@ +--- +title: Migrating run +--- + +First look `run` from `svelte/legacy`: `$:` statements ran on the server and the client. `$effect` only runs on the client. When the migration detects that it cannot express a certain reactive statement as a `$derived`, it therefore uses `run` instead, which behaves like "run once on the server, run like `$effect` on the client". The task is to either migrate it towards a `$derived` (prefered, if possible), or towards `$effect` if you determine that it's ok (or actually desireable) that the given code does not run on the server + +TODO diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/03-migration-script/03-migration-script-events/+assets/app-a/src/lib/App.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/03-migration-script/03-migration-script-events/+assets/app-a/src/lib/App.svelte new file mode 100644 index 0000000000..30404ce4c5 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/03-migration-script/03-migration-script-events/+assets/app-a/src/lib/App.svelte @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/03-migration-script/03-migration-script-events/index.md b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/03-migration-script/03-migration-script-events/index.md new file mode 100644 index 0000000000..ed66924edc --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/03-migration-script/03-migration-script-events/index.md @@ -0,0 +1,7 @@ +--- +title: Migrating event modifiers +--- + +- various event modifiers from `svelte/legacy`: Event modifiers cannot be used with event attributes, as such they are deprecated. If applicable migrate away from using the higher order functions towards simple calls on the event object (for example `onclick={preventDefault(() => ...)}` -> `onclick={e => { e.preventDefault(); ... }}`) + +TODO diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/03-migration-script/03-migration-script-limitations/+assets/app-a/src/lib/App.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/03-migration-script/03-migration-script-limitations/+assets/app-a/src/lib/App.svelte new file mode 100644 index 0000000000..30404ce4c5 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/03-migration-script/03-migration-script-limitations/+assets/app-a/src/lib/App.svelte @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/03-migration-script/03-migration-script-limitations/index.md b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/03-migration-script/03-migration-script-limitations/index.md new file mode 100644 index 0000000000..559720d9f9 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/03-migration-script/03-migration-script-limitations/index.md @@ -0,0 +1,11 @@ +--- +title: Migration script limitations +--- + +There are also a few things that the migration script cannot migrate automatically: + +- `beforeUpdate`/`afterUpdate`: These are deprecated and no longer work in runes mode. Since the migration script cannot infer the intent of why you use `beforeUpdate/afterUpdate`, it will not migrate them. In general, you will want to migrate `beforeUpdate` to `$effect.pre` and `afterUpdate` to `$effect`. When migrating, make sure the right dependencies are read within the effects so that the rerun at the appropriate times +- `createEventDispatcher` and component events: The migration runs file by file, and it's not clear whether or not a given component is from your own project, or coming from a third party library. Therefore both event dispatcher and event listeners are left as is. +- complex edge cases: Certain combinations of old syntax features are too involved to migrate automatically + +TODO how to tutorialize? diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/03-migration-script/index.md b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/03-migration-script/index.md new file mode 100644 index 0000000000..10396a91c5 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/03-migration-script/index.md @@ -0,0 +1,3 @@ +--- +title: Conclusion +--- diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/04-conclusion/01-next-steps-svelte-5/+assets/app-a/src/lib/App.svelte b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/04-conclusion/01-next-steps-svelte-5/+assets/app-a/src/lib/App.svelte new file mode 100644 index 0000000000..50c307bc43 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/04-conclusion/01-next-steps-svelte-5/+assets/app-a/src/lib/App.svelte @@ -0,0 +1,57 @@ + + +{#each confetti as c} + {c.character} +{/each} + + diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/04-conclusion/01-next-steps-svelte-5/index.md b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/04-conclusion/01-next-steps-svelte-5/index.md new file mode 100644 index 0000000000..4ba78368c1 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/04-conclusion/01-next-steps-svelte-5/index.md @@ -0,0 +1,7 @@ +--- +title: Next steps +--- + +Congratulations! If you've made it the entire way through the migration tutorial, you can now consider yourself a Svelte 5 expert. + +TODO some parting words to our good friend Svelte 4 diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/04-conclusion/index.md b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/04-conclusion/index.md new file mode 100644 index 0000000000..10396a91c5 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/04-conclusion/index.md @@ -0,0 +1,3 @@ +--- +title: Conclusion +--- diff --git a/apps/svelte.dev/content/tutorial/05-svelte-5-migration/index.md b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/index.md new file mode 100644 index 0000000000..1533d66f07 --- /dev/null +++ b/apps/svelte.dev/content/tutorial/05-svelte-5-migration/index.md @@ -0,0 +1,5 @@ +--- +title: Migrating from Svelte 4 to 5 +scope: { 'prefix': '/src/lib/', 'name': 'src' } +focus: /src/lib/App.svelte +--- diff --git a/apps/svelte.dev/src/routes/docs/+page.svelte b/apps/svelte.dev/src/routes/docs/+page.svelte index ebead4145f..9c0bf8d746 100644 --- a/apps/svelte.dev/src/routes/docs/+page.svelte +++ b/apps/svelte.dev/src/routes/docs/+page.svelte @@ -72,10 +72,10 @@

- +

I’m migrating an app from Svelte 4

- If you’re already experienced with an older version of Svelte, the migration guide + If you’re already experienced with an older version of Svelte, the migration tutorial will bring you up to speed on the changes in Svelte 5.

diff --git a/apps/svelte.dev/src/routes/tutorial/[slug]/+page.svelte b/apps/svelte.dev/src/routes/tutorial/[slug]/+page.svelte index 680e62ae73..63ba8ed9bf 100644 --- a/apps/svelte.dev/src/routes/tutorial/[slug]/+page.svelte +++ b/apps/svelte.dev/src/routes/tutorial/[slug]/+page.svelte @@ -2,7 +2,7 @@ import { afterNavigate, beforeNavigate } from '$app/navigation'; import { SplitPane } from '@rich_harris/svelte-split-pane'; import { Icon } from '@sveltejs/site-kit/components'; - import { reset } from './adapter.svelte'; + import { needs_rollup, reset } from './adapter.svelte'; import Editor from './Editor.svelte'; import ContextMenu from './filetree/ContextMenu.svelte'; import Filetree from './filetree/Filetree.svelte'; @@ -317,7 +317,7 @@
- {#if /svelte$/.test($page.data.exercise.part.slug)} + {#if needs_rollup($page.data.exercise.part.slug)} {:else} diff --git a/apps/svelte.dev/src/routes/tutorial/[slug]/adapter.svelte.ts b/apps/svelte.dev/src/routes/tutorial/[slug]/adapter.svelte.ts index 0a86794fb4..7c4066982b 100644 --- a/apps/svelte.dev/src/routes/tutorial/[slug]/adapter.svelte.ts +++ b/apps/svelte.dev/src/routes/tutorial/[slug]/adapter.svelte.ts @@ -33,11 +33,15 @@ export const adapter_state = new (class { warnings = $derived((use_rollup ? rollup_state.warnings : wc_state.warnings) || {}); })(); +export function needs_rollup(slug: string) { + return /svelte|to 5$/.test(slug); +} + if (browser) { page.subscribe(($page) => { const slug = $page.data?.exercise?.part?.slug; if (slug) { - use_rollup = /svelte$/.test(slug); + use_rollup = needs_rollup(slug); if (use_rollup) { load_rollup();