Svelte — Framework Compile-Time Cho Web App
Svelte là framework compile-time — biến component thành JavaScript thuần ở build step. Không virtual DOM, bundle siêu nhỏ, reactive declarative.
Svelte là framework UI khác biệt: nó compile component thành JavaScript thuần ở build time, không gửi runtime framework cho browser.
React: Component → JSX → React runtime → Virtual DOM → Real DOM
Svelte: Component → Compiler → Vanilla JS → Real DOM (trực tiếp)plaintextKết quả: bundle nhỏ hơn, nhanh hơn, không cần virtual DOM.
Tại Sao Svelte?#
Bundle Size#
# React + ReactDOM: ~40KB min+gzip
# Svelte: 0KB runtime (chỉ code bạn viết)bashApp càng nhỏ, Svelte càng lợi thế. Một “Hello World” Svelte: ~2KB. React: ~40KB.
Performance#
Không virtual DOM = không diff, không reconciliation. Svelte biết chính xác DOM nào cần update khi state thay đổi — vì compiler tính trước.
React: state change → diff VDOM → patch DOM
Svelte: state change → direct DOM update (compiler biết trước)plaintextComponent#
<!-- App.svelte -->
<script>
let name = 'world'
let count = 0
function increment() {
count += 1
}
</script>
<h1>Hello {name}!</h1>
<p>Count: {count}</p>
<button on:click={increment}>+1</button>
<style>
h1 { color: purple; }
</style>svelteHTML, script, style trong một file. Scoped CSS mặc định.
Reactivity#
<script>
let count = 0
// Reactive statement — chạy lại khi dependency thay đổi
$: doubled = count * 2
$: console.log(`Count is ${count}`)
// Reactive block
$: if (count > 10) {
console.log('Over 10!')
}
function increment() {
count += 1 // Tự động reactive
}
</script>
<p>{count} × 2 = {doubled}</p>
<button on:click={increment}>+</button>svelteKhông useState, không useEffect, không dependency array. Gán biến = tự động reactive.
Props & Events#
<!-- Child.svelte -->
<script>
// Props — export để parent truyền vào
export let title = 'Default title'
export let items = []
// Dispatch event lên parent
import { createEventDispatcher } from 'svelte'
const dispatch = createEventDispatcher()
function handleClick(item) {
dispatch('select', { item })
}
</script>
<h2>{title}</h2>
<ul>
{#each items as item (item.id)}
<li on:click={() => handleClick(item)}>{item.name}</li>
{/each}
</ul>svelte<!-- Parent.svelte -->
<script>
import Child from './Child.svelte'
const items = [
{ id: 1, name: 'Svelte' },
{ id: 2, name: 'SvelteKit' },
]
function onSelect(event) {
console.log('Selected:', event.detail.item)
}
</script>
<Child title="Frameworks" {items} on:select={onSelect} />svelteLogic Blocks#
{#if user.loggedIn}
<p>Welcome, {user.name}!</p>
<button on:click={logout}>Logout</button>
{:else}
<button on:click={login}>Login</button>
{/if}
{#each posts as post, i}
<article>
<h3>{i + 1}. {post.title}</h3>
<p>{post.excerpt}</p>
</article>
{/each}
{#each items as item (item.id)}
<!-- Keyed each — giống React key -->
<div>{item.name}</div>
{/each}
{#await promise}
<p>Loading...</p>
{:then data}
<p>Data: {data}</p>
{:catch error}
<p>Error: {error.message}</p>
{/await}svelteStores (State Management)#
// store.ts — Svelte store là observable
import { writable, derived } from 'svelte/store'
export const count = writable(0)
export const doubled = derived(count, ($count) => $count * 2)
// Methods
export function increment() {
count.update(n => n + 1)
}
export function reset() {
count.set(0)
}svelte<script>
import { count, doubled, increment } from './store'
// Auto-subscribe — reactive
// $ prefix = tự động subscribe/unsubscribe
</script>
<p>Count: {$count}</p>
<p>Doubled: {$doubled}</p>
<button on:click={increment}>+</button>svelteTransitions & Animations#
<script>
import { fade, slide, fly, scale } from 'svelte/transition'
import { flip } from 'svelte/animate'
let visible = false
let items = ['a', 'b', 'c']
</script>
<button on:click={() => visible = !visible}>
Toggle
</button>
{#if visible}
<div transition:fade={{ duration: 300 }}>
Fade in/out
</div>
<div transition:slide>
Slide in/out
</div>
<div transition:fly={{ x: 200, duration: 500 }}>
Fly from right
</div>
{/if}
<!-- Flip animation cho list -->
{#each items as item (item)}
<div animate:flip>{item}</div>
{/each}svelteCSS transitions native — không cần thư viện animation.
SvelteKit (App Framework)#
SvelteKit là Next.js của Svelte — fullstack framework:
npm create svelte@latest my-app
cd my-app
npm install
npm run devbashRouting#
<!-- src/routes/+page.svelte — trang chủ -->
<h1>Home</h1>
<!-- src/routes/blog/[slug]/+page.svelte — dynamic route -->
<script>
import { page } from '$app/stores'
export let data // Từ load function
</script>
<h1>{data.post.title}</h1>
<article>{@html data.post.content}</article>svelteLoad Data#
// src/routes/blog/[slug]/+page.ts
export async function load({ params, fetch }) {
const res = await fetch(`/api/posts/${params.slug}`)
const post = await res.json()
return { post }
}typescriptForm Actions#
// src/routes/login/+page.server.ts
export const actions = {
default: async ({ request }) => {
const data = await request.formData()
const email = data.get('email')
const password = data.get('password')
// Validate
if (!email) return { error: 'Email required' }
// Login logic
const user = await login(email, password)
return { success: true }
}
}typescript<script>
import { enhance } from '$app/forms'
export let form // Server trả về
</script>
<form method="POST" use:enhance>
<input name="email" type="email">
<input name="password" type="password">
<button type="submit">Login</button>
</form>
{#if form?.error}
<p class="error">{form.error}</p>
{/if}svelteSvelte vs React#
| React | Svelte | |
|---|---|---|
| Runtime | ~40KB | 0KB (compiled) |
| Virtual DOM | ✅ | ❌ (direct DOM) |
| State | useState, useReducer | let, $:, stores |
| Effect | useEffect + deps | $: reactive statements |
| Props | props object | export let |
| Events | Callback props | createEventDispatcher |
| CSS | CSS-in-JS, modules | Scoped mặc định |
| Transition | React Transition Group, Framer | Built-in (fade, slide, fly) |
| Learning curve | Cao (JSX, hooks, deps) | Thấp (HTML + JS) |
| Bundle | App + React runtime | Chỉ code của bạn |
Khi nào dùng Svelte?#
✅ Nên dùng:
- Web app nhỏ-gọn — bundle size quan trọng
- Interactive UI — animation, transition nhiều
- Team mới học — Svelte dễ hơn React
- Embedded UI — bundle nhỏ = load nhanh
❌ Không nên:
- Ecosystem dependency — React ecosystem lớn hơn
- Team React chuyên — không cần đổi
- Job market — React jobs nhiều hơn
Tổng Kết#
Svelte đơn giản hóa web development bằng cách compile đi complexity.
<!-- Svelte: code = HTML + JS, framework xử lý phần còn lại -->
<script>
let count = 0
</script>
<button on:click={() => count++}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
<style>
button { background: purple; color: white; }
</style>svelte| Tính năng | Svelte | React |
|---|---|---|
| Bundle | ~2KB (Hello World) | ~40KB |
| Boilerplate | 0 (gán biến = state) | useState, useEffect |
| Scoped CSS | Mặc định | CSS-in-JS |
| Animation | Built-in | Thư viện |
| Compile time | ✅ | ❌ |
| Runtime | 0KB | ~40KB |
Svelte không phải “React killer” — nó là alternative cho những ai muốn ít abstraction hơn, bundle nhỏ hơn, và code gần với HTML thuần hơn.