Astro กับ Svelte: ใช้ Svelte Components ใน Astro
Astro กับ Svelte: ใช้ Svelte Components ใน Astro
Astro เป็น framework ที่ออกแบบมาให้ทำงานร่วมกับ UI framework อื่นได้อย่างยืดหยุ่น หนึ่งในตัวเลือกที่น่าสนใจคือ Svelte ซึ่งเป็น framework ที่มีขนาดเล็ก ทำงานเร็ว และมี syntax ที่เรียบง่าย บทความนี้จะพาคุณเรียนรู้วิธีการใช้ Svelte Components ภายใน Astro Project
ทำไมต้องใช้ Svelte กับ Astro?
Svelte มีจุดเด่นหลายอย่างที่ทำให้มันเข้ากันได้ดีกับ Astro:
- Compiled Output: Svelte compile component เป็น vanilla JavaScript ทำให้ bundle size เล็กมาก
- No Virtual DOM: Svelte ไม่ใช้ Virtual DOM ทำให้ performance ดีกว่า React หรือ Vue ในหลายกรณี
- Reactive Declarations: การจัดการ state ใน Svelte เรียบง่ายและอ่านง่ายมาก
- Built-in Animations: Svelte มี transition และ animation API ในตัว
การติดตั้ง Svelte Integration
เริ่มต้นด้วยการติดตั้ง Svelte integration สำหรับ Astro:
npx astro add svelte
คำสั่งนี้จะติดตั้ง @astrojs/svelte และ svelte package พร้อมกับอัปเดต astro.config.mjs ให้อัตโนมัติ
หรือจะติดตั้งเองแบบ manual:
npm install @astrojs/svelte svelte
จากนั้นแก้ไข astro.config.mjs:
import { defineConfig } from 'astro/config';
import svelte from '@astrojs/svelte';
export default defineConfig({
integrations: [svelte()],
});
สร้าง Svelte Component แรก
สร้างไฟล์ src/components/Counter.svelte:
<script lang="ts">
let count: number = 0;
function increment() {
count += 1;
}
function decrement() {
count -= 1;
}
function reset() {
count = 0;
}
</script>
<div class="counter">
<h2>Counter: {count}</h2>
<div class="buttons">
<button on:click={decrement}>-</button>
<button on:click={reset}>Reset</button>
<button on:click={increment}>+</button>
</div>
</div>
<style>
.counter {
display: flex;
flex-direction: column;
align-items: center;
gap: 1rem;
padding: 2rem;
border: 1px solid #ccc;
border-radius: 8px;
}
.buttons {
display: flex;
gap: 0.5rem;
}
button {
padding: 0.5rem 1rem;
font-size: 1rem;
cursor: pointer;
border-radius: 4px;
border: 1px solid #333;
background: #f0f0f0;
}
button:hover {
background: #e0e0e0;
}
</style>
ใช้ Svelte Component ใน Astro Page
ใน Astro page ให้ import และใช้ Svelte component:
---
import Counter from '../components/Counter.svelte';
---
<html lang="th">
<head>
<title>Astro + Svelte Demo</title>
</head>
<body>
<h1>ทดสอบ Svelte Component</h1>
<!-- Static render (no interactivity) -->
<Counter />
<!-- Client-side hydration -->
<Counter client:load />
<!-- Hydrate when visible -->
<Counter client:visible />
</body>
</html>
Client Directives ที่ควรรู้
Astro มี client directives หลายแบบสำหรับควบคุมการ hydrate:
| Directive | คำอธิบาย |
|---|---|
client:load |
Hydrate ทันทีที่ page โหลด |
client:idle |
Hydrate เมื่อ browser ว่าง |
client:visible |
Hydrate เมื่อ component เข้ามาใน viewport |
client:media |
Hydrate เมื่อ media query match |
client:only |
Render บน client เท่านั้น |
การส่ง Props ไปยัง Svelte Component
สร้าง component ที่รับ props:
<script lang="ts">
export let name: string;
export let initialCount: number = 0;
let count = initialCount;
</script>
<div>
<p>สวัสดี, {name}!</p>
<p>Count: {count}</p>
<button on:click={() => count++}>เพิ่ม</button>
</div>
ใช้งานใน Astro:
---
import Greeting from '../components/Greeting.svelte';
---
<Greeting name="นักพัฒนา" initialCount={5} client:load />
Svelte Stores กับ Astro
สำหรับ shared state ระหว่าง components ใช้ Svelte stores:
// src/stores/cartStore.ts
import { writable, derived } from 'svelte/store';
interface CartItem {
id: string;
name: string;
price: number;
quantity: number;
}
export const cartItems = writable<CartItem[]>([]);
export const cartTotal = derived(cartItems, ($items) =>
$items.reduce((total, item) => total + item.price * item.quantity, 0)
);
export function addToCart(item: CartItem) {
cartItems.update((items) => {
const existing = items.find((i) => i.id === item.id);
if (existing) {
return items.map((i) =>
i.id === item.id ? { ...i, quantity: i.quantity + 1 } : i
);
}
return [...items, item];
});
}
ใช้ store ใน Svelte component:
<script lang="ts">
import { cartItems, cartTotal, addToCart } from '../stores/cartStore';
</script>
<div>
<p>จำนวนสินค้า: {$cartItems.length}</p>
<p>ราคารวม: {$cartTotal} บาท</p>
</div>
Svelte Transitions ใน Astro
หนึ่งในจุดเด่นของ Svelte คือ built-in transitions:
<script lang="ts">
import { fade, fly, slide } from 'svelte/transition';
let visible = false;
</script>
<button on:click={() => visible = !visible}>
Toggle
</button>
{#if visible}
<div transition:fade={{ duration: 300 }}>
<p>Fade in/out</p>
</div>
<div in:fly={{ y: 50, duration: 400 }} out:slide>
<p>Fly in, Slide out</p>
</div>
{/if}
สรุป
การใช้ Svelte กับ Astro เป็นการผสมผสานที่ลงตัวมาก Astro จัดการ static content และ routing ในขณะที่ Svelte ดูแล interactive components ด้วย bundle size ที่เล็กและ performance ที่ดีเยี่ยม คู่นี้เหมาะสำหรับการสร้าง website ที่ต้องการทั้งความเร็วและ interactivity