---
# System prepended metadata

title: 'Rush: Svelte'
tags: [RushNote]

---

# Rush: Svelte

:::info
🔗**References**:
- https://svelte.dev/
:::

:::success
:::spoiler **Table of content**
[ToC]
:::

<hr>

## 1. # Rush: Svelte

:::info
🔗**References**:
- https://svelte.dev/
:::

:::success
:::spoiler **Table of content**
[ToC]
:::

<hr>

## 1. Fundamentals

### Svelte Component

```xml
<script>
    (1) <-- Business Logic
</script>

    (2) <-- Markups

<style>
    (3) <-- Styling
</style>
```

Every component needs to be putted into a `.svelte` file

#### `<script>` block

- `export` keyword mark a variable declaration as a **prop** (*component consumer is able to use it*).
    - export `const`, `class`, `function`: will be **read-only**
    - use cannot `export default` any props.
- Assignments are **reactive**: re-render component when a value changed
    - Assignments are the trigger for re-render, using array-methods (like `.push()`, `.splice()`) do not trigger it.
- `$` marks a statement reactive:
    - **Eg**: if `title` changed, `document.title` would change respectively  
    ```jsx
        <script>
            $: document.title = title
        </script>
    ```
- `$storeValue`: access the store in ***store contract***.
    - A stored value must be declared at **outmost scope**.
    - To assign new value: use `storeValue.set(newValue)`

- `<script context="module">`:
    - make the content ***run once when the module firstly evaluted*** rather than each components.
    
#### `<style>` block

To store CSS :v obviously

- `:global(X)`: to apply CSS for X component for all, not just inside this component

### Basic component

#### Import & use a component

```jsx
<script>
import Widget from './Widget.svelte'
</script>

<div>
    <Widget /> /* <-- this is a component */
</div>
```

#### Attributes

Work as same as HTML counterpart. However, there are some empowered syntatic sugars:
- Embedding attribute / content value:
    ```jsx
    <a href="/account/{ id }"> { id } </a>
    ```
- Appearance of boolean attributes based on boolean (truth / falsy) value:
    ```jsx
    <a href="/account/{ id }" disabled={ isBanned }> { id } </a>
    ```
    (*As you can see, when `isBanned` is falsy, the attribute `disabled` will not be included*)  
- Respectively, an attribute may not be included when passed a nullish value (`null`, `undefined`)
    ```jsx
    <a href="/account/{ id }" id={ null }> { id } </a>
    ```
- Shorthand syntax for the attributes which has the same name with passed values:
    ```jsx
    <a href="/account/{ id }" { id } { disabled } > { id } </a>
    ```

#### Props

As same as attributes, we pass them into a component like this:
```jsx
<Component value={31} { flag } otherValue="testValue" />
```

Or can be written using ***Spread attributes***
```jsx
<Component {...args} />
```

It's replacable with `$$props` - a reference to all props which are passed into the component.
```jsx
<Component {...$$props} />
```
- **`$$restProps`**: refers to passed props without `export` declaration.

#### Branching statement

```jsx
{#if expression}
    ...
{:else if expression} 
    ...
{:else} 
    ...
{/if}
```

#### For-each loop

```jsx
{#each expression as name}
    ...
{:else}
    ...
{/each}
```
The way we write the `each` open-statement can be differential:
```jsx
{#each expression as name, index}
{#each expression as name (key)}
{#each expression as name, index (key)}
```
We can also use **destructuring & rest patterns**:
```jsx
{#each objects as { id, ...rest }}
  <li><span>{id}</span><MyComponent {...rest} /></li>
{/each}
```

```jsx
{#each items as [id, ...rest]}
  <li><span>{id}</span><MyComponent values={rest} /></li>
{/each}
```

#### Asynchronous with Promise 

```jsx
{#await expression}...{:then name}...{:catch name}...{/await}
```

We can rewrite the `await` clause like this:
```jsx
{#await expression then name}...{/await}
{#await expression catch name}...{/await}
```

#### Recreation

Key blocks destroy and recreate their contents when the value of an expression changes.

```hbs
{#key expression}
    ...
{/key}
```

### Special tags

- **`{@html validHtmlExpression}`**: render escaped HTML expression
- **`{@debug val}`**: equivalents with `console.log(X)`


## SvelteKit

A **framework** for Svelte (*as same as NextJS for React*)

To create a new project, run: `npm create svelte@latest <APP_NAME>`

### Project structure

- `src/lib`: library code (ultilities & components), which can be imported by using **`$lib`**
- `src/param`: param matchers
- `src/routes`: routing (*optional*)

### Core concepts: Routing

**Filesystem-based routing approach.** Each route dir contains 1/n **route files** (with `+` prefix).

:::warning
Note that SvelteKit uses `<a>` elements to navigate between routes, rather than a framework-specific `<Link>` component.
:::

- `src/routes/`: root route.
- `src/routes/+page.svelte`: component defines a page for the app
- `src/routes/+page.js`: contains **exported `load()` function**, use for pre-rendering logics (*such as loading data*)
- `src/routes/+page.server.js`: to identify that the `load()` function is server-only runnable
- `src/routes/+error.svelte`: default error page when `load()` has failed.
- `src/routes/+error.server.js`: respectively
- `src/routes/about`: create an `/about` route
- `src/routes/products/[product-name]`: create a `/products` route with path param `[product-name]`.

<br>

- `src/routes/+layout.svelte`: create a layout that applies to every page. Used with `<slot>` tag.
- `src/routes/+layout.js`: as same as other `.js` files


1. You define your `+page.js` file to load some data:

```typescript
/** @type {import('./$types').PageLoad} */
export function load({ params }) {
    return {
        post: {
            title: `Title for ${params.slug} goes here`,
            content: `Content for ${params.slug} goes here`
        }
    };
}
```

2. You consume the data and render it in `+page.svelte`:

```jsx
<script>
	/** @type {import('./$types').PageData} */
	export let data;
</script>

<h1>{data.post.title}</h1>
<div>{@html data.post.content}</div>
```

#### Get the data of parent `load()`

- `src/routes/+layout.js`
```typescript
/** @type {import('./$types').LayoutLoad} */
export function load() {
	return { a: 1 };
}
```
- `src/routes/abc/+layout.js`
```typescript
/** @type {import('./$types').LayoutLoad} */
export async function load({ parent }) {
	const { a } = await parent();
	return { b: a + 1 };
}
```

### Core concepts: Form actions

```jsx
<form
	method="POST"
	use:enhance={({ formElement, formData, action, cancel, submitter }) => {
		// `formElement` is this `<form>` element
		// `formData` is its `FormData` object that's about to be submitted
		// `action` is the URL to which the form is posted
		// calling `cancel()` will prevent the submission
		// `submitter` is the `HTMLElement` that caused the form to be submitted

		return async ({ result, update }) => {
			// `result` is an `ActionResult` object
			// `update` is a function which triggers the default logic that would be triggered if this callback wasn't set
		};
	}}
>
```
- **`formElement`**: refers to `<form>` element
- **`formData`**: is its `FormData` object that's about to be submitted
- **`action`**: is the URL to which the form is posted
- calling `cancel()` will prevent the submission
- **`submitter`**: is the `HTMLElement` that caused the form to be submitted


### Core concept: State management

There are some rules:
1. Browser are ***stateful*** while server is ***stateless***
2. No side-effects in `load()`

**NEVER DO THIS:**

```typescript
import { user } from '$lib/user';


/** @type {import('./$types').PageLoad} */
export async function load({ fetch }) {
	const response = await fetch('/api/user');


	// NEVER DO THIS!
	user.set(await response.json());
}
```

Use **CONTEXT API** instead.

- `src/routes/+layout.svelte`
```typescript
<script>
	import { setContext } from 'svelte';
	import { writable } from 'svelte/store';

	/** @type {import('./$types').LayoutData} */
	export let data;

	// Create a store and update it when necessary...
	const user = writable();
	$: user.set(data.user);

	// ...and add it to the context for child components to access
	setContext('user', user);
</script>
```
- `src/routes/+page.svelte`
```jsx
<script>
	import { getContext } from 'svelte';

	// Retrieve user store from context
	const user = getContext('user');
</script>

<p>Welcome {$user.name}</p>
```

### Hooks

Hooks are **app-wide functions** which will be called in response to specific events. You can declare within 2 files:
- `src/hooks.servers.js`
- `src/hooks.client.js`



### Svelte Component

```xml
<script>
    (1) <-- Business Logic
</script>

    (2) <-- Markups

<style>
    (3) <-- Styling
</style>
```

Every component needs to be putted into a `.svelte` file

#### `<script>` block

- `export` keyword mark a variable declaration as a **prop** (*component consumer is able to use it*).
    - export `const`, `class`, `function`: will be **read-only**
    - use cannot `export default` any props.
- Assignments are **reactive**: re-render component when a value changed
    - Assignments are the trigger for re-render, using array-methods (like `.push()`, `.splice()`) do not trigger it.
- `$` marks a statement reactive:
    - **Eg**: if `title` changed, `document.title` would change respectively  
    ```jsx
        <script>
            $: document.title = title
        </script>
    ```
- `$storeValue`: access the store in ***store contract***.
    - A stored value must be declared at **outmost scope**.
    - To assign new value: use `storeValue.set(newValue)`

- `<script context="module">`:
    - make the content ***run once when the module firstly evaluted*** rather than each components.
    
#### `<style>` block

To store CSS :v obviously

- `:global(X)`: to apply CSS for X component for all, not just inside this component

### Basic component

#### Import & use a component

```jsx
<script>
import Widget from './Widget.svelte'
</script>

<div>
    <Widget /> /* <-- this is a component */
</div>
```

#### Attributes

Work as same as HTML counterpart. However, there are some empowered syntatic sugars:
- Embedding attribute / content value:
    ```jsx
    <a href="/account/{ id }"> { id } </a>
    ```
- Appearance of boolean attributes based on boolean (truth / falsy) value:
    ```jsx
    <a href="/account/{ id }" disabled={ isBanned }> { id } </a>
    ```
    (*As you can see, when `isBanned` is falsy, the attribute `disabled` will not be included*)  
- Respectively, an attribute may not be included when passed a nullish value (`null`, `undefined`)
    ```jsx
    <a href="/account/{ id }" id={ null }> { id } </a>
    ```
- Shorthand syntax for the attributes which has the same name with passed values:
    ```jsx
    <a href="/account/{ id }" { id } { disabled } > { id } </a>
    ```

#### Props

As same as attributes, we pass them into a component like this:
```jsx
<Component value={31} { flag } otherValue="testValue" />
```

Or can be written using ***Spread attributes***
```jsx
<Component {...args} />
```

It's replacable with `$$props` - a reference to all props which are passed into the component.
```jsx
<Component {...$$props} />
```
- **`$$restProps`**: refers to passed props without `export` declaration.

#### Branching statement

```jsx
{#if expression}
    ...
{:else if expression} 
    ...
{:else} 
    ...
{/if}
```

#### For-each loop

```jsx
{#each expression as name}
    ...
{:else}
    ...
{/each}
```
The way we write the `each` open-statement can be differential:
```jsx
{#each expression as name, index}
{#each expression as name (key)}
{#each expression as name, index (key)}
```
We can also use **destructuring & rest patterns**:
```jsx
{#each objects as { id, ...rest }}
  <li><span>{id}</span><MyComponent {...rest} /></li>
{/each}
```

```jsx
{#each items as [id, ...rest]}
  <li><span>{id}</span><MyComponent values={rest} /></li>
{/each}
```

#### Asynchronous with Promise 

```jsx
{#await expression}...{:then name}...{:catch name}...{/await}
```

We can rewrite the `await` clause like this:
```jsx
{#await expression then name}...{/await}
{#await expression catch name}...{/await}
```

#### Recreation

Key blocks destroy and recreate their contents when the value of an expression changes.

```hbs
{#key expression}
    ...
{/key}
```

### Special tags

- **`{@html validHtmlExpression}`**: render escaped HTML expression
- **`{@debug val}`**: equivalents with `console.log(X)`


## SvelteKit

A **framework** for Svelte (*as same as NextJS for React*)

To create a new project, run: `npm create svelte@latest <APP_NAME>`

### Project structure

- `src/lib`: library code (ultilities & components), which can be imported by using **`$lib`**
- `src/param`: param matchers
- `src/routes`: routing (*optional*)

### Core concepts: Routing

**Filesystem-based routing approach.** Each route dir contains 1/n **route files** (with `+` prefix).

:::warning
Note that SvelteKit uses `<a>` elements to navigate between routes, rather than a framework-specific `<Link>` component.
:::

- `src/routes/`: root route.
- `src/routes/+page.svelte`: component defines a page for the app
- `src/routes/+page.js`: contains **exported `load()` function**, use for pre-rendering logics (*such as loading data*)
- `src/routes/+page.server.js`: to identify that the `load()` function is server-only runnable
- `src/routes/+error.svelte`: default error page when `load()` has failed.
- `src/routes/+error.server.js`: respectively
- `src/routes/about`: create an `/about` route
- `src/routes/products/[product-name]`: create a `/products` route with path param `[product-name]`.

<br>

- `src/routes/+layout.svelte`: create a layout that applies to every page. Used with `<slot>` tag.
- `src/routes/+layout.js`: as same as other `.js` files


1. You define your `+page.js` file to load some data:

```typescript
/** @type {import('./$types').PageLoad} */
export function load({ params }) {
    return {
        post: {
            title: `Title for ${params.slug} goes here`,
            content: `Content for ${params.slug} goes here`
        }
    };
}
```

2. You consume the data and render it in `+page.svelte`:

```jsx
<script>
	/** @type {import('./$types').PageData} */
	export let data;
</script>

<h1>{data.post.title}</h1>
<div>{@html data.post.content}</div>
```

#### Get the data of parent `load()`

- `src/routes/+layout.js`
```typescript
/** @type {import('./$types').LayoutLoad} */
export function load() {
	return { a: 1 };
}
```
- `src/routes/abc/+layout.js`
```typescript
/** @type {import('./$types').LayoutLoad} */
export async function load({ parent }) {
	const { a } = await parent();
	return { b: a + 1 };
}
```

### Core concepts: Form actions

```jsx
<form
	method="POST"
	use:enhance={({ formElement, formData, action, cancel, submitter }) => {
		// `formElement` is this `<form>` element
		// `formData` is its `FormData` object that's about to be submitted
		// `action` is the URL to which the form is posted
		// calling `cancel()` will prevent the submission
		// `submitter` is the `HTMLElement` that caused the form to be submitted

		return async ({ result, update }) => {
			// `result` is an `ActionResult` object
			// `update` is a function which triggers the default logic that would be triggered if this callback wasn't set
		};
	}}
>
```
- **`formElement`**: refers to `<form>` element
- **`formData`**: is its `FormData` object that's about to be submitted
- **`action`**: is the URL to which the form is posted
- calling `cancel()` will prevent the submission
- **`submitter`**: is the `HTMLElement` that caused the form to be submitted


### Core concept: State management

There are some rules:
1. Browser are ***stateful*** while server is ***stateless***
2. No side-effects in `load()`

**NEVER DO THIS:**

```typescript
import { user } from '$lib/user';


/** @type {import('./$types').PageLoad} */
export async function load({ fetch }) {
	const response = await fetch('/api/user');


	// NEVER DO THIS!
	user.set(await response.json());
}
```

Use **CONTEXT API** instead.

- `src/routes/+layout.svelte`
```typescript
<script>
	import { setContext } from 'svelte';
	import { writable } from 'svelte/store';

	/** @type {import('./$types').LayoutData} */
	export let data;

	// Create a store and update it when necessary...
	const user = writable();
	$: user.set(data.user);

	// ...and add it to the context for child components to access
	setContext('user', user);
</script>
```
- `src/routes/+page.svelte`
```jsx
<script>
	import { getContext } from 'svelte';

	// Retrieve user store from context
	const user = getContext('user');
</script>

<p>Welcome {$user.name}</p>
```

### Hooks

Hooks are **app-wide functions** which will be called in response to specific events. You can declare within 2 files:
- `src/hooks.servers.js`
- `src/hooks.client.js`

