Skip to content

Commit

Permalink
chore: separate tutorial URLs into svelte and kit (#304)
Browse files Browse the repository at this point in the history
* chore: separate tutorial URLs into svelte and kit

- gives us more leeway with duplicated slugs if needed later on
- makes URL a bit more organized
- will make it easier to set dedicated headers for the SvelteKit tutorial (#301)
- fixes a bug with redirects not being picked up due to prerendering not coming across old slugs

* fix logic

* fix a bunch of links or remove obsolete ones that have no replacement
  • Loading branch information
dummdidumm authored Oct 9, 2024
1 parent 9ee57ca commit 04916af
Show file tree
Hide file tree
Showing 44 changed files with 74 additions and 57 deletions.
2 changes: 1 addition & 1 deletion apps/svelte.dev/content/blog/2019-04-20-write-less-code.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,6 @@ In Vue, meanwhile, we have a default export with a `data` function that returns

## Death to boilerplate

These are just some of the ways that Svelte helps you build user interfaces with a minimum of fuss. There are plenty of others — for example, [reactive declarations](/tutorial/reactive-declarations) essentially do the work of React's `useMemo`, `useCallback` and `useEffect` without the boilerplate (or indeed the garbage collection overhead of creating inline functions and arrays on each state change).
These are just some of the ways that Svelte helps you build user interfaces with a minimum of fuss. There are plenty of others — for example, reactive declarations (`$:` statements) essentially do the work of React's `useMemo`, `useCallback` and `useEffect` without the boilerplate (or indeed the garbage collection overhead of creating inline functions and arrays on each state change).

How? By choosing a different set of constraints. Because [Svelte is a compiler](/blog/frameworks-without-the-framework), we're not bound to the peculiarities of JavaScript: we can _design_ a component authoring experience, rather than having to fit it around the semantics of the language. Paradoxically, this results in _more_ idiomatic code — for example using variables naturally rather than via proxies or hooks — while delivering significantly more performant apps.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Want to learn more about how to get started, what's different compared to Sapper

## New in Svelte & Language Tools

- Slotted components, including `<svelte:fragment slot="...">` lets component consumers target specific slots with rich content (**Svelte 3.35.0, Language Tools [104.5.0](https://github.com/sveltejs/language-tools/releases/tag/extensions-104.5.0)**, check out the [docs](https://svelte.dev/docs#template-syntax-svelte-fragment) and the [tutorial](https://svelte.dev/tutorial/svelte-fragment))
- Slotted components, including `<svelte:fragment slot="...">` lets component consumers target specific slots with rich content (**Svelte 3.35.0, Language Tools [104.5.0](https://github.com/sveltejs/language-tools/releases/tag/extensions-104.5.0)**)
- Linked editing now works for HTML in Svelte files (**Language Tools, [104.6.0](https://github.com/sveltejs/language-tools/releases/tag/extensions-104.6.0)**)
- Type definitions `svelte.d.ts` are now resolved in order, allowing library authors to ship type definitions with their svelte components (**Language Tools, [104.7.0](https://github.com/sveltejs/language-tools/releases/tag/extensions-104.7.0)**)
- [vite-plugin-svelte](https://github.com/sveltejs/vite-plugin-svelte) is available for general use of Svelte in Vite. `npm init @vitejs/app` includes Svelte options using this plugin.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ With yesterday's Svelte Summit behind us, we've got a lot of news to share! Chec

## What's new in Svelte

- The `<svelte:element>` element lets you render an element of a dynamically specified type. This is useful, for example, when rendering rich text content from a CMS. Check out the [docs](https://svelte.dev/docs#template-syntax-svelte-element) or the [tutorial](https://svelte.dev/tutorial/svelte-element) for more info (**3.47.0**)!
- The `<svelte:element>` element lets you render an element of a dynamically specified type. This is useful, for example, when rendering rich text content from a CMS. Check out the [docs](https://svelte.dev/docs#template-syntax-svelte-element) or the [tutorial](/tutorial/svelte/svelte-element) for more info (**3.47.0**)!

## Language Tools updates

Expand Down
2 changes: 1 addition & 1 deletion apps/svelte.dev/content/blog/2023-09-20-runes.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ We don't yet have a release date for Svelte 5. What we're showing you here is a
>
> A letter or mark used as a mystical or magic symbol.
Runes are symbols that influence the Svelte compiler. Whereas Svelte today uses `let`, `=`, the [`export`](https://learn.svelte.dev/tutorial/declaring-props) keyword and the [`$:`](https://learn.svelte.dev/tutorial/reactive-declarations) label to mean specific things, runes use _function syntax_ to achieve the same things and more.
Runes are symbols that influence the Svelte compiler. Whereas Svelte today uses `let`, `=`, the `export` keyword and the `$:` label to mean specific things, runes use _function syntax_ to achieve the same things and more.

For example, to declare a piece of reactive state, we can use the `$state` rune:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ You can build your entire app with Svelte (for example, using an application fra
This tutorial is split into four 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)
- [Basic Svelte](/tutorial/svelte/welcome-to-svelte) (you are here)
- [Advanced Svelte](/tutorial/svelte/tweens)
- [Basic SvelteKit](/tutorial/kit/introducing-sveltekit)
- [Advanced SvelteKit](/tutorial/kit/optional-params)

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.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ The function takes two arguments — the node to which the transition is applied

- `delay` — milliseconds before the transition begins
- `duration` — length of the transition in milliseconds
- `easing` — a `p => t` easing function (see the chapter on [tweening](/tutorial/tweens))
- `easing` — a `p => t` easing function (see the chapter on [tweening](/tutorial/svelte/tweens))
- `css` — a `(t, u) => css` function, where `u === 1 - t`
- `tick` — a `(t, u) => {...}` function that has some effect on the node

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: The animate directive
---

In the [previous chapter](/tutorial/deferred-transitions), we used deferred transitions to create the illusion of motion as elements move from one todo list to the other.
In the [previous chapter](/tutorial/svelte/deferred-transitions), we used deferred transitions to create the illusion of motion as elements move from one todo list to the other.

To complete the illusion, we also need to apply motion to the elements that _aren't_ transitioning. For this, we use the `animate` directive.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,5 @@ We've already got a `handleKeydown` function declared — now all we need to do

```svelte
/// file: App.svelte
<svelte:window +++on:keydown={handleKeydown}+++ />
<svelte:window +++onkeydown={handleKeydown}+++ />
```

> As with DOM elements, you can add [event modifiers](/tutorial/event-modifiers) like `preventDefault`.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ On the right, in the file tree viewer, you'll see a handful of files that Svelte

`vite.config.js` contains the [Vite](https://vitejs.dev/) configuration. Because SvelteKit uses Vite, you can use [Vite features](https://vitejs.dev/guide/features.html) like hot module replacement, TypeScript support, static asset handling and so on.

`src` is where your app's source code goes. `src/app.html` is your page template (SvelteKit replaces the `%sveltekit.head%` and `%sveltekit.body%` as appropriate), and `src/routes` defines the [routes](/tutorial/pages) of your app.
`src` is where your app's source code goes. `src/app.html` is your page template (SvelteKit replaces the `%sveltekit.head%` and `%sveltekit.body%` as appropriate), and `src/routes` defines the [routes](/tutorial/kit/pages) of your app.

Finally, `static` contains any assets (like a `favicon.png` or a `robots.txt`) that should be included when your app is deployed.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Basics
---

In the chapter on [loading data](/tutorial/page-data), we saw how you can export `load` functions from `+page.js`, `+page.server.js`, `+layout.js` and `+layout.server.js` files. We can also export various **page options** from these modules:
In the chapter on [loading data](/tutorial/kit/page-data), we saw how you can export `load` functions from `+page.js`, `+page.server.js`, `+layout.js` and `+layout.server.js` files. We can also export various **page options** from these modules:

- `ssr` — whether or not pages should be server-rendered
- `csr` — whether to load the SvelteKit client
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Optional parameters
---

In the first chapter on [routing](/tutorial/pages), we learned how to create routes with [dynamic parameters](/tutorial/params).
In the first chapter on [routing](/tutorial/kit/pages), we learned how to create routes with [dynamic parameters](/tutorial/kit/params).

Sometimes it's helpful to make a parameter optional. A classic example is when you use the pathname to determine the locale — `/fr/...`, `/de/...` and so on — but you also want to have a default locale.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Route groups
---

As we saw in the [routing introduction](/tutorial/layouts), layouts are a way to share UI and data loading logic between different routes.
As we saw in the [routing introduction](/tutorial/kit/layouts), layouts are a way to share UI and data loading logic between different routes.

Sometimes it's useful to use layouts without affecting the route — for example, you might need your `/app` and `/account` routes to be behind authentication, while your `/about` page is open to the world. We can do this with a _route group_, which is a directory in parentheses.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Using parent data
---

As we saw in the introduction to [layout data](/tutorial/layout-data), `+page.svelte` and `+layout.svelte` components have access to everything returned from their parent `load` functions.
As we saw in the introduction to [layout data](/tutorial/kit/layout-data), `+page.svelte` and `+layout.svelte` components have access to everything returned from their parent `load` functions.

Occasionally it's useful for the `load` functions themselves to access data from their parents. This can be done with `await parent()`.

Expand All @@ -25,7 +25,7 @@ export async function load(+++{ parent }+++) {
}
```

> Notice that a [universal](/tutorial/universal-load-functions) `load` function can get data from a parent _server_ `load` function. The reverse is not true — a server load function can only get parent data from another server load function.
> Notice that a [universal](/tutorial/kit/universal-load-functions) `load` function can get data from a parent _server_ `load` function. The reverse is not true — a server load function can only get parent data from another server load function.
Finally, in `src/routes/sum/+page.js`, get parent data from both `load` functions:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ First, in `.env`, add a new environment variable:
PASSPHRASE=+++"open sesame"+++
```

Open `src/routes/+page.server.js`. Import `PASSPHRASE` from `$env/static/private` and use it inside the [form action](/tutorial/the-form-element):
Open `src/routes/+page.server.js`. Import `PASSPHRASE` from `$env/static/private` and use it inside the [form action](/tutorial/kit/the-form-element):

```js
/// file: src/routes/+page.server.js
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: $env/dynamic/public
---

As with [private environment variables](/tutorial/env-static-private), it's preferable to use static values if possible, but if necessary we can use dynamic values instead:
As with [private environment variables](/tutorial/kit/env-static-private), it's preferable to use static values if possible, but if necessary we can use dynamic values instead:

```svelte
/// file: src/routes/+page.svelte
Expand Down
12 changes: 6 additions & 6 deletions apps/svelte.dev/src/routes/content.json/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { index, docs as _docs, examples } from '$lib/server/content';
import { json } from '@sveltejs/kit';
import { markedTransform, normalizeSlugify, removeMarkdown } from '@sveltejs/site-kit/markdown';
import type { Block } from '@sveltejs/site-kit/search';
import { get_slug } from '../tutorial/[...slug]/content.server';

export const prerender = true;

Expand All @@ -17,13 +18,12 @@ function get_href(parts: string[]) {

async function content() {
const blocks: Block[] = [];
const breadcrumbs: string[] = [];
const docs = Object.values(_docs.pages).concat(
index.tutorial.children.flatMap((topic) =>
topic.children.flatMap((section) =>
section.children.map((entry) => ({
...entry,
slug: `tutorial/${entry.slug.split('/').pop()}`
index.tutorial.children.flatMap((part) =>
part.children.flatMap((chapter) =>
chapter.children.map((exercise) => ({
...exercise,
slug: get_slug(part, exercise)
}))
)
)
Expand Down
7 changes: 0 additions & 7 deletions apps/svelte.dev/src/routes/tutorial/+page.js

This file was deleted.

43 changes: 43 additions & 0 deletions apps/svelte.dev/src/routes/tutorial/[...slug]/+page.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { redirect } from '@sveltejs/kit';
import { load_exercise, parts } from './content.server';

export const prerender = true;

const redirects = new Map([
['reactive-assignments', 'svelte/state'],
['reactive-declarations', 'svelte/derived-state'],
['reactive-statements', 'svelte/effects'],
['updating-arrays-and-objects', 'svelte/deep-state'],
['event-modifiers', 'svelte/capturing'],
['dom-event-forwarding', 'svelte/spreading-events']
]);

export async function load({ params }) {
if (!params.slug || params.slug === 'svelte') redirect(307, '/tutorial/svelte/welcome-to-svelte');
if (params.slug === 'kit') redirect(307, '/tutorial/kit/introducing-sveltekit');

const r = redirects.get(params.slug);
if (r) redirect(307, r);
if (!params.slug.includes('/')) redirect(307, `/tutorial/svelte/${params.slug}`);

return {
exercise: await load_exercise(params.slug)
};
}

export function entries() {
// These are not findable by the router, but we need to know about them for redirects

// So that old tutorial/... routes can redirect to new tutorial/svelte/...
const entries = parts
.filter((part) => !part.slug.includes('sveltekit'))
.flatMap((part) => part.chapters)
.flatMap((chapter) =>
chapter.exercises.map((exercise) => ({ slug: exercise.slug.split('/').pop()! }))
);

// So that redirects from these URLs to /tutorial/<svelte/kit>/... work
entries.push({ slug: 'svelte' }, { slug: 'kit' });

return entries;
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ let prev: null | { slug: string; title: string } = null;

let files: Record<string, string> = {};

export function get_slug(part: Document, exercise: Document) {
const topic = part.slug.split('/').pop()!.includes('sveltekit') ? 'kit' : 'svelte';
return `tutorial/${topic}/${exercise.slug.split('/').pop()}`;
}

export const parts: PartStub[] = index.tutorial.children.map((part) => {
return {
slug: part.slug,
Expand All @@ -42,7 +47,7 @@ export const parts: PartStub[] = index.tutorial.children.map((part) => {
slug: chapter.slug.split('/').pop()!,
title: chapter.metadata.title,
exercises: chapter.children.map((exercise) => {
const slug = exercise.slug.split('/').pop()!;
const slug = get_slug(part, exercise).slice('tutorial/'.length);

const stub: ExerciseStub = {
slug,
Expand Down
22 changes: 0 additions & 22 deletions apps/svelte.dev/src/routes/tutorial/[slug]/+page.server.js

This file was deleted.

0 comments on commit 04916af

Please sign in to comment.