มารู้จัก Svelte และ SvelteKit กัน
/ 9 min read
สามารถดู video ของหัวข้อนี้ก่อนได้ ดู video
(บทความนี้เป็นบทความประกอบการอธิบายกับ Video นะครับ)
รู้จัก Svelte / Svelte Kit
Ref: https://svelte.dev/
Svelte คือ open-source Frontend component framework ที่ถูกสร้างโดย Rich Harris และ maintain โดย Svelte core team ที่มีจุดประสงค์ในการทำ UI Component ของ Web เพื่ออำนวยความสะดวกในการ reuse component ทั้งส่วน UI / Styling และ Logic ใน Component ได้ โดยจุดเด่นหลักๆของ Svelte คือ
- Component-based = เหมือนๆกับ Web framework ชื่อดังเจ้าอื่นๆ อย่าง React, Vue, Angular สามารถทำ UI Component ที่รวม Style / Logic ไว้ได้
- Reactive = มีความสามารถในการ update UI แบบอัตโนมัติเมื่อ data change (คล้ายๆ Vue)
- Compiler-based = จุดแข็งสำคัญของ Svelte สำหรับการ build project
Svelte จะใช้ compiler (จังหวะที่มีการ build code เพื่อ production ใช้งาน) ทำการ convert เป็น optimized JavaScript ที่สามารถจัดการ DOM โดยตรงได้เลย
จากแต่เดิมที่บาง Framework ต้องอาศัย Virtual DOM ในการช่วย Optimize การ manipulates ของ Javascript (โดยการ pack javascript ส่วนนี้เข้าไป) ที่ถึงแม้ว่าจะเร็วกว่าการจัดการ DOM โดยตรง แต่การใช้ Virtual DOM ก็เพิ่มกระบวนการประมวลผลและใช้หน่วยความจำมากขึ้น
ฝั่ง Svelte จะทำ step นี้ตั้งแต่ compiler เลย ระบบ compile ของ Svelte จะวิเคราะห์ code แบบคงที่ระหว่างการสร้าง โดยจะส่งผลทำให้ bundle sizes มีขนาดเล็กลง และ Javascript สามารถจัดการได้ไวขึ้น
รวมถึงเทคนิคอย่าง Reactive = Svelte ใช้เทคนิคใหม่ stores
เพื่อจัดการกับความ responsive แทน virtual DOM diffing stores
จะเชื่อมต่อกับองค์ประกอบ DOM โดยตรง อัปเดตเฉพาะองค์ประกอบที่ได้รับผลจากการเปลี่ยนแปลงสถานะ ลดการทำงานของ DOM และการใช้หน่วยความจำ (ระบบ reactive นี้มีประสิทธิภาพมากกว่า virtual DOM เพราะจะอัปเดตเฉพาะสิ่งที่ต้องการเท่านั้น) เทียบได้กับการที่ code สามารถตัด runtime ออกได้ แล้วเหลือเพียง javascript ไป run ตรงๆได้
-
Small bulider-size = จากคุณสมบัติเรื่อง compiler ส่งผลทำให้ขนาดของ build file svelte มีขนาดเล็กมาก (ราวๆ 2kb) เมื่อเทียบกับเจ้าอื่นๆ
-
Easy to learn = มีเว็บ tutorial ให้เรียนรู้ได้เลย และ code ส่วนใหญ่ (จากเท่าที่ลองมา) code สั้นกว่า framework หลายๆเจ้า เมื่อใช้ไอเดียเดียวกัน
นี่คือ 1 ใน framework ที่ Release ช่วงปี 2016 เทียบกับ React (2013), Angular (2010), Vue (2014) ก็ถือว่าเป็น Framework ที่เกิดขึ้นในยุคหลังๆก็ว่าได้ = ดังนั้น เป็น 1 ใน framework ที่มี lesson learn มาแล้วจาก 3 Framework ชื่อดังก่อนหน้านี้มา
นี่คือเว็บ tutorial ของ svelte https://learn.svelte.dev/tutorial/updating-arrays-and-objects
เพิ่มเติมตัวของ SvelteKit
จุดแข็งอีกอย่างของ Svelte ที่นอกเหนือจากการที่เป็น UI Framework แล้ว ยังมี library ที่ใช้งานคู่กันอย่าง SvelteKit ที่ช่วยอำนวยความสะดวกในการทำ web application ด้วย โดย SvelteKit นั้นวางตัวเองเป็น
SvelteKit เป็น Framework ที่สร้างขึ้นบน Svelte ช่วยให้นักพัฒนาสามารถสร้าง web app เว็บแบบเต็มรูปแบบได้อย่างง่ายดาย
library ของ SvelteKit ครอบคลุมถึง
-
Svelte: คอมไพเลอร์ Svelte ที่แปลงโค้ด Svelte เป็น JavaScript ธรรมดา
-
Vite: เครื่องมือรันไทม์ที่โหลดแอปพลิเคชัน SvelteKit อย่างรวดเร็ว
-
Router: ไลบรารีการจัดการเส้นทางที่ช่วยให้นักพัฒนาสร้างแอปพลิเคชันแบบหลายหน้า
-
Store: ไลบรารีการจัดการสถานะแบบ reactive
-
Form: ไลบรารีการจัดการแบบฟอร์มที่ช่วยให้นักพัฒนาสร้างแบบฟอร์มที่ใช้งานได้ง่าย
-
library ที่ทำการรวม feature พื้นฐานของ Web framework โดย design ให้ใช้ร่วมกับ Svelte Component ได้
-
ถ้าเทียบกับฝั่ง React หรือ Vue
- Svelte = React, Vue
- SvelteKit = Next, Nuxt
Feature มีตั้งแต่
- Routing
- Server-side rendering
- Data fetching
- Service workers
- TypeScript integration
- Prerendering
- Single-page apps
- Library packaging
- Optimised production builds
- Deploying to different hosting providers
Feature support ก็คล้ายๆกับฝั่ง Next, Nuxt เลย แต่ก็จะมีของที่คล้ายๆกันกับของบางอย่างที่ง่ายกว่า (มาดูผ่านตัวอย่างไปพร้อมๆกันได้)
เราจะคุยอะไรกันใน Session นี้บ้าง
ในหัวข้อนี้เราจะพูด 2 Part แยกออกจากกันคือ
- มารู้จักกับ Svelte Component พื้นฐานของตัว Svelte ก่อน (ผ่าน tutorial ของ Svelte) โดยเราจะหยิบเอาตัวที่เรารู้สึกว่า “ต้องรู้” ของ Svelte มาก่อน
- มาลองทำ project Easy Blog กัน ผ่าน SvelteKit
ก่อนเราจะมาทำ project จริงกัน เราจะพาทัวร์ feature ของ Component ของ Svelte เพื่อให้เห็นภาพรวมของ Feature ของ component ใน Svelte ก่อน
Part 1 - Svelte
Ref: https://learn.svelte.dev/tutorial/welcome-to-svelte
เนื่องจาก Part 1 เราจะยังไม่ใช้ SvelteKit ดังนั้น เราจะขอลงจาก Vite มาก่อนแทน
โดยเราจะดำเนินการตามหัวข้อของ Tutorial ใน Svelte (ตาม link ที่ Reference นี้)
Component
ใน Svelte web app จะประกอบด้วยองค์ประกอบตั้งแต่ 1 component ขึ้นไป โดย component คือ block of code ที่นำมาใช้ซ้ำได้ ซึ่งห่อหุ้ม HTML, CSS และ JavaScript ไว้ด้วยกัน โดยเขียนเป็นไฟล์ .svelte
ไว้
ตัวอย่าง App.svelte
โดยสามารถส่งตัวแปรเข้า attribute ของ html จาก javascript ได้ภายใน component
Reactivity
การผูกตัวแปรแบบ reactive โดยสามารถเปลี่ยนแปลงและแสดงผลบน UI ออกมาเมื่อ data เกิดการ change ได้
Props
Component สามารถรับค่าผ่าน Properties และส่งค่าผ่าน Props ได้
เช่นที่ App.svelte
โดยที่ Hello.svelte
ทำการ import properties ผ่าน export let <ชื่อตัวแปร>
เช่น เคสนี้ทำการสร้าง properties answer ที่เป็นตัวรับออกมา จึงสามารถรับค่า answer
ออกมาได้
Logic blocks
Component ของ Svelte อนุญาตให้สามารถเพิ่ม dynamic behavior หรือ control flow ของ web app ได้ โดย Logic blocks เหล่านี้ใช้เพื่อจัดการกับเงื่อนไข, ทำซ้ำ (loop), และคำสั่ง reactive statement ซึ่งเป็นส่วนหนึ่งของ template ใน Svelte ที่ได้เตรียมรูปแบบการจัดการเอาไว้
ตัวอย่าง code ของการใช้ if blocks ของ control flow สำหรับการควบคุมการแสดงผลเมื่อ count > 10 ให้แสดงข้อความออกมา
ซึ่งนอกเหนือจาก if blocks ยังมี else, else-if, each รวมถึง await block ที่ใช้สำหรับดึง API ได้หน้าตาประมาณนี้
อ่านได้จากหัวข้อ https://learn.svelte.dev/tutorial/if-blocks หรือ document หลัก https://svelte.dev/docs/logic-blocks
Event
ใช้คำสั่ง on:
เพื่อ listener event ของ DOM ได้ เช่น
on:click
เพื่อทำการดักตามการ click ของปุ่ม ตามเคสใน code ด้านล่างนี้
อ่านได้จากหัวข้อ https://learn.svelte.dev/tutorial/dom-events
Binding
ผูก Data เข้ากับ form โดยใช้คำสั่ง bind:value
โดยทำการใส่คู่กับ bind เข้ากับ input DOM ที่ต้องการทำการ binding ไว้
ตัวอย่างของการผูก name เข้ากับ input form
อ่านได้จากหัวข้อ https://learn.svelte.dev/tutorial/text-inputs
Lifecycle
Cycle ของ Component ใน state onMount, beforeUpdate, afterUpdate
อ่านได้จากหัวข้อ https://learn.svelte.dev/tutorial/onmount
Stores
จัดการ state ตรงกลาง
อ่านได้จากหัวข้อ https://learn.svelte.dev/tutorial/writable-stores
โจทย์ของเรา
เราจะมาใช้ Svelte ทำ Project ที่มี feature ดังนี้
- ทำ Blog แสดงข้อมูลออกมาทั้งหมด ผ่าน API ของ mockapi
- ดู detail blog แต่ละหน้าได้ ผ่าน parameter
- ทำหน้า เพิ่ม Blog โดยมี input สำหรับใส่ชื่อ blog
- เพิ่มหน้า login เพื่อกั้นสิทธิ์ให้เฉพาะคนที่ login แล้วเท่านั้นที่แก้ blog ได้ (ใช้ server action เข้าไป)
- เพิ่ม jwt token cookie (เพิ่ม hook สำหรับเช็ค cookie ก่อนที่จะเปิดหน้าแก้ไข)
** tutorial ฉบับเต็มสามารถดูได้ผ่าน video ในส่วน source code สามารถดูผ่าน github นี้ได้เลย https://github.com/mikelopster/svelte-basic
Part 2 - SvelteKit
Ref: https://learn.svelte.dev/tutorial/introducing-sveltekit
Follow ตามหัวข้อของ Tutorial SvelteKit
Routing
Ref: https://kit.svelte.dev/docs/routing
การแยกระหว่าง Component โหลดจาก server, Component โหลดจาก Client โดยหลักการ SvelteKit คือ Router ที่ใช้ระบบชื่อไฟล์เป็นการกำนนด path ที่ user สามารถ access ได้ โดยจะกำหนดจาก directory ของ codebase เป็นหลัก:
src/routes
คือ root routesrc/routes/about
สร้าง/about
routesrc/routes/blog/[slug]
สร้าง/blog
route ที่สามารถรับ parameter, slug ที่ใช้สำหรับการโหลด data แบบ dynamic ออกมาได้เมื่อ user มีการเปิด page เช่น/blog/hello-world
ออกมา
โดยนอกจาก path แล้วจะมีชื่อ file ที่เป็นตัวกำหนดคุณสมบัติของ page นั้นออกมาได้ โดยจะมี 3 ประเภทใหญ่ๆที่จะมีโอกาสได้ใช้บ่อยๆ (ทุกประเภทสามารถดูผ่าน document ต้นฉบับได้)
+page.svelte
เป็นการกำหนด page component ของ web app = เทียบได้กับเป็น default ของ component ที่ใช้แสดงผลในแต่ละหน้า และ ทุก page นั้นโดย default จะ render ได้ทั้งบน Server (SSR) สำหรับการเรียก request รอบแรก และ บน Browser (CSR) สำหรับการเปิดไปในแต่ละหน้า
โดยสามารถเขียน code แบบ svelte component ได้เลย เช่นแบบนี้ ลองวางไว้ที่ src/routes/blog/+page.svelte
เมื่อเปิด web ผ่าน localhost:5173/blog
ก็จะสามารถเปิดหน้านั้นแสดงผลออกมาได้
+page.server.js
หากเราต้องการ load ข้อมูลก่อนที่ component นั้นจะแสดงผลออกมา = เราต้องการ run load function จากบน server ออกมาก่อน
- ถ้าเราต้องการดึงข้อมูล data ไม่ว่าจะเป็นจาก database หรือ private environment variable ที่มี API key
- เราสามารถใช้
+page.server.js
เพื่อเป็นการกำหนดว่าเราจะโหลดข้อมูลออกจาก server มาก่อนได้
เช่น เคสนี้ หากเราต้องการดึงข้อมูลจาก Mock API ออกมาก่อน ใน folder เดียวกันเราจึงมี 2 files คือ +page.server.js
และ +page.svelte
โดย
+page.server.js
จะทำการดึงข้อมูลออกมาก่อนด้วย load function และส่งข้อมูลออกไปผ่าน propsdata
- ที่ page component
+page.svelte
จะนำข้อมูลจาก server component มาใช้ต่อและแสดงผลออกมาได้
code ก็จะมีหน้าตาประมาณนี้
ก็จะสามารถใช้งานข้อมูลจาก server ได้
+page.js
ในกรณีที่เราต้องการ load ข้อมูลมา แต่เราอยากให้การ load นี้เกิดขึ้นได้ทั้งจากฝั่งของ Server (ตอนเปิดหน้าเว็บขึ้นมาใหม่ - SSR) และ จากฝั่งของ Client (จากการเปลี่ยนหน้ามา และโหลดข้อมูลใหม่ - CSR) จะสามารถใช้ +page.js
ในการดึงข้อมูลออกมาได้ โดยสามารถ export data ออกได้จาก load function (แบบเดียวกันกับ server component)
้เช่น code ลักษณะนี้
สังเกตว่า code จะเหมือนๆกันกับฝั่ง Server เลยแต่ขอให้เข้าใจไว้้ว่า
+page.server.js
จะ run แค่บนฝั่ง Server เท่านั้น = เหมือนเรากำลังทำทุกอย่างบน Server+page.js
จะ run ทั้งฝั่ง Client (Browser) และ Server = แม้จะดึงข้อมูลเหมือนกัน แต่เมื่อมีการเปิดผ่าน navigation ออกมา จะเป็นการทำงานฝั่ง Client แทน ดังนั้น ต้องไม่ใส่หรือวางข้อมูลอะไรก็ตามที่มีลักษณะ private ไว้ที่ page.js เด็ดขาด
รวมถึงสามารถใช้งานร่วมกับ feature page option โดยสามารถกำหนดได้ว่า
export const prerender = true or false or 'auto'
= prelender ออกมาก่อนหรือไม่export const ssr = true or false
= เปิด ssr หรือไม่ ? (default: เปิด)export const csr = true or false
= เปิด csr หรือไม่ ?
เป็นต้น สามารถอ่านเพิ่มเติมได้จากหัวข้อ Page option ตาม url นี้ https://kit.svelte.dev/docs/page-options
API routes
นอกเหนือจากทำ page component ได้แล้ว คล้ายๆกับ Framework ตัวอื่นๆอย่าง Nuxt.js
หรือ Next.js
สามารถที่จะทำ api route ออกมาได้เช่นเดียวกัน โดยมีเบื้องหลังการทำงานเป็น node.js
ทำให้เราสามารถสร้าง custom api บน SvelteKit ออกมาได้ โดยสามารถทำได้ผ่านชื่อไฟล์ +server.js
ตัวอย่างเคสนี้ หากเราต้องการสร้าง API GET /api/blog
ออกมา เราต้องสร้างไฟล์ server.js
ใน src/routes/api/blog/server.js
(กฎการตั้ง path ยังเหมือนกับ Route แบบ page component) และสามารถวาง server code ที่ server.js
ได้เลย
อย่างเคสนี้เราสร้าง proxy API ขึ้นมาสำหรับการดึงข้อมูลจาก mock api โดยดึงผ่าน GET /api/blog
ออกมาแทน
- ชื่อ function
GET
คือ method ที่ใช้สำหรับการ call API ที่สร้างขึ้นมาสามารถเป็นGET
,POST
,PATCH
,PUT
,DELETE
,OPTIONS
ได้ตาม method ที่เรากำหนด
และเมื่อเราลอง call API ดูก็จะสามารถยิง API ได้เหมือนกับเวลาเราทำด้วย node.js ออกมาได้เลย
ENV
Ref:
- https://kit.svelte.dev/docs/adapter-node#environment-variables
- https://kit.svelte.dev/docs/modules#$env-static-private
env
คือการตั้งค่า environment หรือตัวแปร ที่ใช้ขณะ development หรือ build process ของ Svelte โดย ตัวแปร environment เหล่านี้จะถูกใช้สำหรับการเก็บค่า configuration ของระบบเพื่อไม่ให้เป็นการ hard-code โดยตรงเข้าไป (ทำให้สามารถปรับได้เมื่อมีการเปลี่ยนค่าโดยไม่ต้องทำการ update code ชุดใหม่) ซึ่งปกติจะใช้กับค่าอย่าง API Keys, URLs หรือการเปิด / ปิด feature เป็นต้น
โดยวิธีการประกาศ ตัวแปร env
นั้นสามารถสร้างไฟล์ .env
จาก root directory ของ project ได้เลย (อยู่ระดับเดียวกับ src
) โดยวิธีการประกาศเป็นดังนี้
- ตัวแปรทั่วไปเมื่อมีการใส่ไว้ใน
.env
= จะถือว่าเป็น Private env โดย default (จะไม่สามารถ access เข้ามาจาก Client ได้) - เมื่อไหร่ก็ตามที่มีการใส่
PUBLIC_
นำหน้าตัวแปร.env
= เป็นการเปิดเผยไปยังฝั่ง Client ทำให้ Client สามารถเรียกใช้งานได้เช่นกัน
เช่นแบบนี้
โดยเคสนี้
JWT_SECRET_KEY
= เป็น private env ที่เรียกได้จากฝั่ง server เท่านั้นPUBLIC_BASE_API_URL
= เป็น public env ที่สามารถเรียกใช้ได้จากฝั่งของ client ด้วย
วิธีการเรียกใช้ตัวแปร env
จาก SvelteKit สามารถทำได้จากการ import เข้ามาโดยตรงได้เลย
- สำหรับ private env จะ import ผ่าน
$env/static/private
เช่น
- สำหรับ public env จะ import ผ่าน
$env/static/public
เช่น
ก็จะสามารถเรียกใช้ตัวแปร ENV ออกมาได้
Hook
Ref: https://kit.svelte.dev/docs/hooks
Hook คือ function ที่อนุญาตให้เราคั่นกลาง (intercept) ระหว่าง request และ response ของ application โดย feature นี้ทำให้สามารถแทรก logic หรือ function ระหว่างกลางของ page และ endpoint ที่มีการเปิดขึ้นมาได้
โดยใน SvelteKit นั้นจะมี hook ทั้ง 2 ประเภทคือ
src/hooks.server.js
— Server hooks สำหรับการคั่นกลางระหว่าง Serversrc/hooks.client.js
— Client hooks สำหรับการคั่นกลางระหว่าง Client
โดย code เหล่านี้จะ run เมื่อ web app เริ่มต้นขึ้นมาซึ่งสามารถใช้ได้กับเคสที่ต้องมีการเริ่มต้นเช่น initial database
ตัวอย่างการใช้ hook หนึ่งเคส (ที่ workshop ในบทความนี้ทำ)
- สร้างไฟล์
hooks.server.js
สำหรับการเพิ่ม hook ฝั่ง server ขึ้นมา - โดย hook จะทำการแกะ jwt token (ที่แนบผ่าน cookie ใน request) มาเพื่อเป็นการยืนยันตัวตนว่า login มาแล้วหรือไม่ ?
- ซึ่งถ้าแกะ cookie สำเร็จ = สามารถไปต่อได้ และส่งข้อมูล user ผ่าน
event.locals.user
ไปได้ - หากแกะไม่สำเร็จ = ให้พากลับไปยังหน้าแรกผ่านคำสั่ง
redirect('/')
เพื่อเป็นการบังคับให้ user ต้อง login
Production ready ?
Svelte พร้อมสำหรับงานจริงแล้ว เนื่องจาก Svelte 3 เป็น version ที่มีความเสถียรและใช้งานจริงมาหลายปีแล้ว รวมถึง บริษัทใหญ่หลายแห่งไว้วางใจภาษา แถมยังเรียนรู้ได้ง่ายด้วย (แถมมาพร้อมกับ web ที่เป็น tutorial อีกต่างหาก)
อย่างไรก็ตาม Svelte ยังเป็น Web framework ที่อายุน้อยกว่า React, Vue และ Angular โดย
- Community อาจจะยังไม่ใหญ่เท่า 3 เจ้านี้
- แต่ความเห็นส่วนตัวของผม Svelte ครอบคลุมทุก case จำเป็นอยู่แล้ว ดังนั้นถ้าพัฒนา web app พื้นฐาน มี feature ที่จำเป็นพร้อมอยู่แล้ว
- มาเรียนรู้พื้นฐาน Functional Programming กันมี Video
มาเรียนรู้พื้นฐาน Functional Programming กันว่ามันคืออะไร
-
- NestJS และ Mongoมี Video
เรียนรู้การผสานพลังระหว่าง NestJS framework ยอดนิยมฝั่ง Node.js กับ MongoDB ฐานข้อมูล NoSQL สุดทรงพลังกัน
- ทำเว็บ Blog ด้วย Next.js และ Strapiมี Video
ภาคต่อจาก Next.js เราจะลองนำ Next.js มาสร้างเว็บ Content จริงๆกันผ่าน Strapi