Svelte и SvelteKit: компилятор вместо runtime

Реактивность без Virtual DOM, меньше кода, лучше производительность

Svelte переосмысливает frontend фреймворки. Компилятор вместо runtime, реактивность на уровне языка, минимальный boilerplate. SvelteKit — full-stack framework как Next.js. Разберем почему Svelte набирает популярность. Svelte vs React React: Runtime library (~45KB) Virtual DOM useState, useEffect hooks JSX syntax Svelte: Compiler (0KB runtime overhead) No Virtual DOM Reactive declarations HTML-first syntax Component Basics import { useState } from 'react'; function Counter() { const [count, setCount] = useState(0); return ( Count: {count} setCount(count + 1)}> Increment ); } let count = 0; Count: {count} count += 1}> Increment Реактивность const [count, setCount] = useState(0); const doubled = count * 2; // Не реактивно! // Нужен useMemo const doubled = useMemo(() => count * 2, [count]); let count = 0; $: doubled = count * 2; // Автоматически реактивно! Reactive Statements: let count = 0; // Reactive declaration $: doubled = count * 2; // Reactive statement $: { console.log(`Count is ${count}`); if (count > 10) { alert('Too high!'); } } // Reactive function call $: updateTitle(count); function updateTitle(value) { document.title = `Count: ${value}`; } Props import Child from './Child.svelte'; export let name; export let age = 25; // Default value {name} is {age} years old Events import { createEventDispatcher } from 'svelte'; const dispatch = createEventDispatcher(); function handleClick() { dispatch('message', { text: 'Hello from child!' }); } Send Message function handleMessage(event) { console.log(event.detail.text); } Binding let name = ''; Hello {name}! let agreed = false; I agree let selected = 'option1'; Option 1 Option 2 Lifecycle import { onMount, onDestroy, beforeUpdate, afterUpdate } from 'svelte'; onMount(() => { console.log('Component mounted'); // Cleanup return () => { console.log('Cleanup'); }; }); onDestroy(() => { console.log('Component destroyed'); }); beforeUpdate(() => { console.log('Before update'); }); afterUpdate(() => { console.log('After update'); }); Stores (state management) Writable Store: // store.js import { writable } from 'svelte/store'; export const count = writable(0); // Component.svelte import { count } from './store.js'; function increment() { count.update(n => n + 1); } function reset() { count.set(0); } Count: {$count} + Reset Readable Store: // store.js import { readable } from 'svelte/store'; export const time = readable(new Date(), (set) => { const interval = setInterval(() => { set(new Date()); }, 1000); return () => clearInterval(interval); }); Derived Store: import { derived } from 'svelte/store'; import { count } from './store.js'; export const doubled = derived(count, $count => $count * 2); Custom Store: // store.js import { writable } from 'svelte/store'; function createCounter() { const { subscribe, set, update } = writable(0); return { subscribe, increment: () => update(n => n + 1), decrement: () => update(n => n - 1), reset: () => set(0) }; } export const count = createCounter(); Transitions & Animations import { fade, fly, slide } from 'svelte/transition'; import { flip } from 'svelte/animate'; let visible = false; visible = !visible}>Toggle {#if visible} Fades in and out {/if} {#if visible} Different in/out transitions {/if} {#each items as item (item.id)} {item.name} {/each} Conditional Rendering & Lists let user = { loggedIn: true, name: 'John' }; let todos = [ { id: 1, text: 'Task 1', done: false }, { id: 2, text: 'Task 2', done: true } ]; {#if user.loggedIn} Welcome, {user.name}! {:else} Please log in {/if} {#each todos as todo (todo.id)} {todo.text} {:else} No todos {/each} .done { text-decoration: line-through; } Await Blocks async function fetchUser(id) { const res = await fetch(`/api/users/${id}`); return res.json(); } let promise = fetchUser(123); {#await promise} Loading... {:then user} Welcome {user.name}! {:catch error} Error: {error.message} {/await} SvelteKit Project Structure: my-app/ ├── src/ │ ├── routes/ │ │ ├── +page.svelte │ │ ├── +page.js │ │ ├── about/ │ │ │ └── +page.svelte │ │ └── blog/ │ │ ├── +page.svelte │ │ └── [slug]/ │ │ └── +page.svelte │ ├── lib/ │ └── app.html ├── static/ └── svelte.config.js File-based Routing: Home About export let data; {data.post.title} {@html data.post.content} Loading Data: // src/routes/blog/[slug]/+page.js export async function load({ params, fetch }) { const res = await fetch(`/api/posts/${params.slug}`); const post = await res.json(); return { post }; } Server-side Code: // src/routes/api/posts/+server.js import { json } from '@sveltejs/kit'; import { db } from '$lib/db'; export async function GET() { const posts = await db.posts.findAll(); return json(posts); } export async function POST({ request }) { const data = await request.json(); const post = await db.posts.create(data); return json(post, { status: 201 }); } Form Actions: Create Post export const actions = { create: async ({ request }) => { const data = await request.formData(); const title = data.get('title'); const content = data.get('content'); await db.posts.create({ title, content }); return { success: true }; } }; Layouts: Home About Blog © 2024 SEO & Meta Tags My Page Title Content Performance Bundle size — меньше чем React на 40-50% Runtime performance — нет Virtual DOM overhead Compile time — оптимизации на этапе компиляции Code splitting — автоматический в SvelteKit Заключение: Svelte — свежий подход к frontend. Меньше кода, лучше производительность. Реактивность без hooks. SvelteKit — полноценный full-stack framework. Начните с tutorial на svelte.dev. Попробуйте SvelteKit для нового проекта. Svelte растет — следите за развитием.