เบากว่าและเร็วกว่า - คู่มือสำหรับ Svelte Framework

เผยแพร่แล้ว: 2022-03-11

เว็บแอปพลิเคชันกำลังเป็นที่นิยมมากขึ้นทุกวัน พวกเขาเป็นโลกที่กำลังเติบโตซึ่งผู้คนเลือกใช้ความเรียบง่าย ความเร็ว และความพร้อมใช้งานข้ามแพลตฟอร์ม แอปพลิเคชันหน้าเดียว (SPA) มีส่วนสำคัญในกระบวนการนี้ กรอบงานเช่น Angular, Vue.js และ React ช่วยให้นักพัฒนาสามารถมอบประสบการณ์ผู้ใช้ที่ดีที่สุดในช่วงเวลาสั้น ๆ โดยปล่อยให้โค้ดรองรับและขยายได้ เครื่องมือเหล่านี้ยังคงได้รับความนิยมสูงสุดในภาคสนามมาอย่างยาวนาน โดยมีข้อได้เปรียบเหนือแพ็คเกจที่สร้างขึ้นใหม่มากมาย รู้สึกเหมือนเป็นผู้ขายน้อยรายในโลกของ SPA อย่างไรก็ตาม กลุ่มนักพัฒนาที่มองการณ์ไกลซึ่งกำหนดเป้าหมายไปที่ตลาดนี้สามารถเข้าร่วมกับคู่แข่งที่จริงจัง นั่นคือ Svelte

Svelte เป็นแนวทางใหม่ในการสร้างส่วนต่อประสานผู้ใช้ มาดำดิ่งลงไปและสำรวจสิ่งที่ทำให้มีความสดใหม่โดยการสร้างแบบฟอร์มการเข้าสู่ระบบทั่วไป

สถาปัตยกรรม

Svelte ได้รับการออกแบบทางสถาปัตยกรรมให้เร็วกว่าห้องสมุดอื่น มันทำได้โดยการเปลี่ยนขั้นตอนการโหลดเฟรมเวิร์กสำหรับการสร้าง DOM เสมือน แทนที่จะใช้เครื่องมือในระหว่างกระบวนการทำงาน มันถูกคอมไพล์เป็น vanilla JS ที่ขั้นตอนการสร้าง ดังนั้นแอปพลิเคชันจึงไม่จำเป็นต้องมีการพึ่งพาเพื่อเริ่มต้น

Svelte ไลบรารี SPA อื่นๆ (React, Vue.js, Angular เป็นต้น)

1. เปิดเว็บไซต์
2. แสดงผลหน้าโดยใช้ JS . บริสุทธิ์

1. เปิดเว็บไซต์
2. รอจนกว่าจะโหลดโค้ดสำหรับสร้าง DOM เสมือน
3. แสดงผลหน้าโดยใช้ไลบรารี

ตารางด้านบนอธิบายว่าทำไม Svelte จึงเป็นผู้ชนะอย่างแท้จริงในประสิทธิภาพการเริ่มต้น ที่ไม่ได้มาจากการเพิ่มประสิทธิภาพใด ๆ แต่โดยการใช้คอมไพเลอร์ JavaScript ของเบราว์เซอร์ที่มีอยู่แทนคอมไพเลอร์ด้านข้าง

การติดตั้ง

การติดตั้ง Svelte ทำได้ง่ายมาก ทำให้การใช้งานเป็นไปอย่างราบรื่น ขั้นตอนแรกคือการดาวน์โหลดเทมเพลตของโครงการ:

 npx degit sveltejs/template svelte-login-form

การทำตามคำสั่งด้านบนให้สมบูรณ์หมายความว่าเรามีเทมเพลตโครงการ Svelte ขณะนี้ว่างเปล่าและยังไม่ได้ติดตั้งแพ็คเกจ NPM ที่จำเป็น มาแก้ไขกันเถอะ

 cd svelte-login-form npm install

ตอนนี้แอปพลิเคชันพร้อมที่จะเริ่มทำงานโดยใช้คำสั่งต่อไปนี้:

 npm run dev

โครงสร้าง

ส่วนประกอบ Svelte ใดๆ อาจประกอบด้วยส่วนต่อไปนี้:

  • สคริปต์
  • สไตล์
  • แม่แบบ

มาดูตัวอย่างในไฟล์ src/App.svelte

 <script> export let name; </script> <style> h1 { color: purple; } </style> <h1>{name}</h1>

รหัสด้านบนประกอบด้วยสามส่วนเท่านั้น:

  1. แท็ก script ซึ่งเป็นบล็อก JavaScript ทางเลือกที่มีการประกาศตัวแปรและฟังก์ชันที่ควรใช้ภายในคอมโพเนนต์

  2. แท็ก style ซึ่งเป็นบล็อกทางเลือกอื่น มันเหมือนกับแท็กสไตล์ HTML ทั่วไป ยกเว้นข้อแตกต่างที่สำคัญอย่างหนึ่ง กฎที่อธิบายไว้ในบล็อกนี้กำหนดขอบเขตไว้เฉพาะส่วนประกอบนี้ การใช้สไตล์กับองค์ประกอบ p จะไม่มีผลกับย่อหน้าทั้งหมดบนหน้า มันวิเศษมากเพราะคุณไม่จำเป็นต้องคิดชื่อคลาส และคุณจะไม่ลบล้างกฎอื่นโดยไม่ได้ตั้งใจ

  3. บล็อกสุดท้ายและบล็อกเดียวที่จำเป็นคือบล็อกเทมเพลต - ในกรณีนี้คือแท็ก h1 เป็นการนำเสนอ/มุมมองขององค์ประกอบของคุณ มีการผูกมัดอย่างแน่นหนากับสไตล์และบล็อกสคริปต์เนื่องจากเป็นตัวกำหนดว่ามุมมองจะถูกจัดรูปแบบอย่างไรและจะทำงานอย่างไร

Svelte เป็นห้องสมุดที่พยายามนำโมดูลาร์มาสู่เกมส่วนหน้า มันทำให้โมดูลาร์นั้นไม่เฉพาะในการแยกส่วนประกอบต่างๆ เท่านั้น แต่ยังรวมถึงการแยกตรรกะ มุมมอง และเทมเพลตด้วย

กลับไปที่แบบฟอร์มการเข้าสู่ระบบที่เรากำลังสร้าง ให้สร้างไฟล์ใหม่ LoginForm.svelte ภายในโฟลเดอร์ src ที่มีเนื้อหาต่อไปนี้:

 <style> form { background: #fff; padding: 50px; width: 250px; height: 400px; display: flex; flex-direction: column; justify-content: center; align-items: center; box-shadow: 0px 20px 14px 8px rgba(0, 0, 0, 0.58); } label { margin: 10px 0; align-self: flex-start; font-weight: 500; } input { border: none; border-bottom: 1px solid #ccc; margin-bottom: 20px; transition: all 300ms ease-in-out; width: 100%; } input:focus { outline: 0; border-bottom: 1px solid #666; } button { margin-top: 20px; background: black; color: white; padding: 10px 0; width: 200px; border-radius: 25px; text-transform: uppercase; font-weight: bold; cursor: pointer; transition: all 300ms ease-in-out; } button:hover { transform: translateY(-2.5px); box-shadow: 0px 1px 10px 0px rgba(0, 0, 0, 0.58); } h1 { margin: 10px 20px 30px 20px; font-size: 40px; } </style> <form> <h1></h1> <label>Email</label> <input name="email" placeholder="[email protected]" /> <label>Password</label> <input name="password" type="password" placeholder="password" /> <button type="submit">Log in </button> </form>

มันเป็นองค์ประกอบที่โง่เขลาที่เราจะทำให้ฉลาดขึ้นในภายหลัง หากต้องการดูองค์ประกอบนี้บนไซต์ของเรา เราควรแสดงผลภายในองค์ประกอบรูท - แอป ไปแก้ไข src/App.svelte กัน จะได้หน้าตาแบบนี้:

 <script> import LoginForm from "./LoginForm.svelte"; </script> <style> section { height: 100vh; width: 100%; display: flex; justify-content: center; align-items: center; background: linear-gradient(to right, #cd76e2, #e358ab); } </style> <section> <LoginForm /> </section>

หากทุกอย่างถูกต้องและแอปพลิเคชันยังทำงานอยู่ แบบฟอร์มของเราจะปรากฏที่ localhost:5000 มาเพิ่มระดับทักษะ Svelte ของเราด้วยการทำให้แบบฟอร์มฉลาดขึ้น

กำลังเก็บสถานะ

องค์ประกอบใดๆ ใน Svelte สามารถมีสถานะได้ สถานะเป็นตัวแปรพิเศษหรือกลุ่มของตัวแปรพิเศษที่สามารถใช้ได้ภายในเทมเพลต ทำไมฉันถึงพูดว่า "พิเศษ"? เมื่อใดก็ตามที่มีการเปลี่ยนแปลงตัวแปรดังกล่าว เทมเพลตจะได้รับการแจ้งเตือนและแสดงเนื้อหาด้วยสถานะใหม่ล่าสุด ซึ่งช่วยให้แอปพลิเคชันตอบสนองต่อการโต้ตอบของผู้ใช้ได้อย่างรวดเร็ว

เราจะประกาศตัวแปรสถานะ email และ password ที่จะจัดเก็บค่าของแบบฟอร์มสำหรับฟิลด์ที่เหมาะสม หมายความว่าตัวแปร email และ password ของเราจะซิงค์กับค่าของแบบฟอร์มเสมอ ดังนั้นเราจะพร้อมส่งค่าเหล่านี้เมื่อใดก็ได้โดยไม่ต้องกลัวว่าจะมีความแตกต่างระหว่างค่าที่ส่งกับค่าจริงในแบบฟอร์ม

 <script> let email = ""; let password = ""; let isLoading = false; const handleSubmit = () => { isLoading = true; // Simulate network request setTimeout(() => { isLoading = false; // Authorize the user }, 1000); }; </script> <style> /* Style is unchanged */ </style> <form on:submit|preventDefault={handleSubmit}> <h1></h1> <label>Email</label> <input name="email" placeholder="[email protected]" bind:value={email} /> <label>Password</label> <input name="password" type="password" bind:value={password} /> {#if isLoading}Logging in...{:else}Log in {/if} </form>

ตัวแปรสถานะดูเหมือนตัวแปร JavaScript ทั่วไป แต่เพื่อให้ซิงโครไนซ์กับค่าของแบบฟอร์ม (เชื่อมโยงกับฟิลด์ของแบบฟอร์ม) จำเป็นต้องใช้คำสั่ง bind:value นอกจากนี้ยังมีบางสิ่งที่ไม่คุ้นเคย:

  • on:submit|preventDefault เป็นชวเลขสำหรับป้องกันพฤติกรรมเริ่มต้นของเหตุการณ์ วิธีนี้สะดวกกว่าการเขียน e.preventDefault() ทุกครั้ง

  • {#if isLoading}Logging in...{:else}Log in {/if} เป็นส่วนประกอบหนึ่งของรูปแบบเทมเพลตของ Svelte เนื่องจากไม่มี JS ในบล็อกเทมเพลต จึงมีไวยากรณ์พิเศษสำหรับการใช้ ifs, loops เป็นต้น

สุดท้าย ลองใช้ตัวเลือกที่มีอยู่โดยใช้สถานะเพื่อเพิ่มการตรวจสอบลงในแบบฟอร์มของเรา สามารถทำได้โดยการสร้าง errors ตัวแปรสถานะอื่น ซึ่งจะเต็มไปด้วยข้อผิดพลาดเมื่อส่งแบบฟอร์มด้วยค่าที่ไม่ถูกต้อง

 <script> let email = ""; let password = ""; let isLoading = false; let errors = {}; const handleSubmit = () => { errors = {}; if (email.length === 0) { errors.email = "Field should not be empty"; } if (password.length === 0) { errors.password = "Field should not be empty"; } if (Object.keys(errors).length === 0) { isLoading = true; // Simulate network request setTimeout(() => { isLoading = false; // Authorize the user }, 1000); } }; </script> <style> // Previous styles unchanged .errors { list-style-type: none; padding: 10px; margin: 0; border: 2px solid #be6283; color: #be6283; background: rgba(190, 98, 131, 0.3); } </style> <form on:submit|preventDefault={handleSubmit}> <h1></h1> <label>Email</label> <input name="email" placeholder="[email protected]" bind:value={email} /> <label>Password</label> <input name="password" type="password" bind:value={password} /> <button type="submit"> {#if isLoading}Logging in...{:else}Log in {/if} </button> {#if Object.keys(errors).length > 0} <ul class="errors"> {#each Object.keys(errors) as field} <li>{field}: {errors[field]}</li> {/each} </ul> {/if} </form> 
แบบฟอร์มเข้าสู่ระบบผิดพลาด

แบบฟอร์มใกล้จะสมบูรณ์แล้ว สิ่งเดียวที่ยังคงอยู่คือข้อความแสดงความสำเร็จเมื่อรับรองความถูกต้องสำเร็จ

มาสร้างตัวแปรสถานะเพื่อติดตามการส่งที่สำเร็จซึ่งเป็น false โดยค่าเริ่มต้น หลังจากส่งแบบฟอร์มสำเร็จแล้ว ค่าของตัวแปรนี้ควรตั้งค่า true

 let isSuccess = false;

ควรเปลี่ยนฟังก์ชันที่จัดการการส่งแบบฟอร์มเพื่อให้เป็นไปตามตรรกะของการสลับ isSuccess หลังจากดำเนินการสำเร็จ

 const handleSubmit = () => { errors = {}; if (email.length === 0) { errors.email = "Field should not be empty"; } if (password.length === 0) { errors.password = "Field should not be empty"; } if (Object.keys(errors).length === 0) { isLoading = true; // Simulate network request setTimeout(() => { isLoading = false; isSuccess = true; // Authorize the user }, 1000); } };

การปรับเปลี่ยนนี้ทำให้แบบฟอร์มเข้าสู่สถานะสำเร็จทันทีที่การส่งเสร็จสมบูรณ์

แต่ถ้าคุณตรวจสอบเซิร์ฟเวอร์การพัฒนา คุณจะไม่พบการเปลี่ยนแปลงใดๆ ในลักษณะการทำงานของแบบฟอร์ม เราเปลี่ยนรหัสแต่ยังไม่ได้แตะแม่แบบ เราจำเป็นต้องเพิ่มคำแนะนำในเทมเพลตเพื่อแสดงข้อความแสดงความสำเร็จเมื่อผู้ใช้ลงชื่อเข้าใช้สำเร็จ ไวยากรณ์เทมเพลตของ Svelte ช่วยให้เรานำไปใช้ได้อย่างง่ายดาย:

 <form on:submit|preventDefault={handleSubmit}> {#if isSuccess} <div class="success"> <br /> You've been successfully logged in. </div> {:else} <h1></h1> <label>Email</label> <input name="email" placeholder="[email protected]" bind:value={email} /> <label>Password</label> <input name="password" type="password" bind:value={password} /> <button type="submit"> {#if isLoading}Logging in...{:else}Log in {/if} </button> {#if Object.keys(errors).length > 0} <ul class="errors"> {#each Object.keys(errors) as field} <li>{field}: {errors[field]}</li> {/each} </ul> {/if} {/if} </form>

บทคัดย่อด้วยคุณสมบัติ

เราได้แยกแยะทุกอย่างเกี่ยวกับสถานะของส่วนประกอบภายในแล้ว ถึงเวลาที่ต้องพิจารณาการพึ่งพาภายนอกที่เรียกว่าคุณสมบัติหรือ "อุปกรณ์ประกอบฉาก" อุปกรณ์ประกอบฉากคืออินพุตหรืออาร์กิวเมนต์ที่ส่งผ่านไปยังส่วนประกอบเพื่ออธิบายสิ่งที่ควรปรากฏหรือองค์ประกอบที่ควรแสดงแก่ส่วนประกอบ

การประกาศคุณสมบัติคล้ายกับสถานะ ยกเว้นสำหรับการ export คำหลัก

 <script> export let answer; </script> <p>The answer is {answer}</p>
 <script> import Nested from './Nested.svelte'; </script> <Nested answer={42}/>

มันคือทั้งหมดที่เกี่ยวกับคุณสมบัติ ประกาศและผ่าน - ทั้งหมดที่คุณต้องรู้เพื่อใช้อุปกรณ์ประกอบฉาก

แต่คุณสมบัติเหล่านี้นำไปใช้กับองค์ประกอบแบบฟอร์มการเข้าสู่ระบบได้อย่างไร อุปกรณ์ประกอบฉากสามารถทำให้แบบฟอร์มการเข้าสู่ระบบของเราเป็นแบบทั่วไปมากขึ้นโดยแยกฟังก์ชันการส่งลงในพร็อพเพอร์ตี้ จะช่วยให้คุณใช้ส่วนประกอบนี้กับการดำเนินการส่งที่คุณต้องการได้ (ขอเซิร์ฟเวอร์ทดสอบ ขอไปยังเซิร์ฟเวอร์จริง ฯลฯ) พร็อพนี้จะถูกเรียกว่า send และจะเป็นฟังก์ชันที่ submit คืนสัญญาที่ได้รับการแก้ไขแล้ว หากการดำเนินการส่งสำเร็จ และสัญญาที่ถูกปฏิเสธหากมีข้อผิดพลาด ขอประกาศพร็อพตามตัวอย่างที่ให้ไว้ข้างต้น:

 export let submit;

ตัวจัดการการส่งภายในแบบฟอร์มการเข้าสู่ระบบควรได้รับการแก้ไขเพื่อใช้คุณสมบัติ submit ใหม่

 const handleSubmit = () => { errors = {}; if (email.length === 0) { errors.email = "Field should not be empty"; } if (password.length === 0) { errors.password = "Field should not be empty"; } if (Object.keys(errors).length === 0) { isLoading = true; submit({ email, password }) .then(() => { isSuccess = true; isLoading = false; }) .catch(err => { errors.server = err; isLoading = false; }); } };

ดูเหมือนว่าองค์ประกอบจะพร้อม อย่างไรก็ตาม หากคุณกลับไปที่แบบฟอร์มและพยายามส่ง คุณจะสังเกตเห็นว่าสถานะของปุ่มไม่ได้เปลี่ยนจากการโหลด นอกจากนี้ยังมีข้อยกเว้นในคอนโซล Uncaught TypeError: submit is not a function แน่นอน เราประกาศพร็อพแล้ว แต่ลืมส่งไป มาประกาศฟังก์ชันในองค์ประกอบของแอปและส่งต่อไปยังแบบฟอร์มการเข้าสู่ระบบ

 const submit = ({ email, password }) => new Promise((resolve, reject) => setTimeout(resolve, 1000));
 <section> <LoginForm submit={submit} /> </section>

ตอนนี้แบบฟอร์มทำงานตามที่ตั้งใจไว้ สามารถแสดงข้อผิดพลาดและแจ้งให้ผู้ใช้ทราบว่าการเข้าสู่ระบบสำเร็จหรือไม่

แบบฟอร์มการเข้าสู่ระบบสำเร็จ

การแบ่งปันบริบท

ดูเหมือนว่าทุกสิ่งที่จำเป็นในการสร้างแอปพลิเคชันจะแสดงอยู่ในรายการ ด้วยคุณสมบัติและสภาพภายใน เราก็พร้อมลุย นั่นเป็นความจริงเพียงบางส่วนเท่านั้น ประเด็นทั่วไปสองข้อนี้ทำให้สามารถออกแบบ SPA ที่มีความซับซ้อนสูงได้ อย่างไรก็ตาม หากคุณพยายามแบ่งปันข้อมูลระหว่างองค์ประกอบต่างๆ คุณจะพบว่ามันยากมาก

ตัวอย่างที่ง่ายที่สุดคือการมีตัวแปร user ที่เข้าถึงได้ทั่วโลก ส่วนประกอบจำนวนมากควรเปลี่ยนพฤติกรรมที่เกี่ยวข้องกับผู้ใช้ ขึ้นอยู่กับบทบาทของผู้ใช้ อายุ สถานะ ฯลฯ อย่างไรก็ตาม มันไม่ DRY ที่จะทำซ้ำตัวเองโดยส่งผู้ใช้ไปยังแต่ละองค์ประกอบในแอปโดยใช้อุปกรณ์ประกอบฉาก

Svelte มีวิธีแก้ปัญหาสำหรับสิ่งนี้: บริบท API

API บริบทมีกลไกสำหรับส่วนประกอบในการ 'พูดคุย' ซึ่งกันและกันโดยไม่ต้องส่งต่อข้อมูลและทำหน้าที่เป็นอุปกรณ์ประกอบฉากหรือส่งกิจกรรมจำนวนมาก เป็นคุณลักษณะขั้นสูง แต่มีประโยชน์

มาเพิ่มบริบทผู้ใช้ให้กับแบบฟอร์มการเข้าสู่ระบบที่เรากำลังออกแบบกัน สร้างไฟล์ userContext.js ภายในโฟลเดอร์ src ด้วยเนื้อหาต่อไปนี้:

 export const key = "userContext"; export const initialValue = null;

key เป็นตัวระบุเฉพาะสำหรับบริบท เนื่องจากแอปพลิเคชันอาจมีบริบทที่แตกต่างกันจำนวนไม่จำกัดซึ่งต้องสามารถเข้าถึงได้ initialValue เป็นเพียงค่าเริ่มต้นสำหรับบริบทก่อนที่จะตั้งค่า

ขั้นตอนต่อไปคือการเพิ่มบริบทให้กับแอปพลิเคชันของเรา ไปที่ไฟล์ App.svelte และเพิ่มคำสั่งนำเข้า 2 รายการ:

 import { onMount, setContext } from "svelte"; import { key as userContextKey, initialValue as userContextInitialValue } from "./userContext";

เมื่อดูโค้ดด้านบน คุณอาจสงสัยว่าเรากำลังนำเข้าอะไรจากแพ็คเกจ svelte onMount เป็นฟังก์ชันตัวช่วยที่ต้องการฟังก์ชันเรียกกลับเป็นอาร์กิวเมนต์ การเรียกกลับนี้จะดำเนินการเมื่อมีการต่อเชื่อมส่วนประกอบปัจจุบัน (เมื่อเริ่มต้นการโหลดส่วนประกอบ) setContext เป็นฟังก์ชัน setter สำหรับบริบท ต้องใช้คีย์ในบริบทและค่าใหม่เป็นอาร์กิวเมนต์

ลองใช้ฟังก์ชัน onMount เพื่อตั้งค่าเริ่มต้นสำหรับบริบท:

 onMount(() => { setContext(userContextKey, userContextInitialValue); });

และแก้ไขฟังก์ชัน submit เพื่อกำหนดบริบทของผู้ใช้:

 const submit = ({ email, password }) => new Promise((resolve, reject) => { setTimeout(() => { setContext(userContextKey, { name: "Foo", lastName: "Bar", email: "[email protected]" }); resolve(); }, 1000); });

แค่นั้นแหละ. การส่งที่สำเร็จจะเปลี่ยนบริบทของผู้ใช้เป็นวัตถุผู้ใช้ปลอม ซึ่งสามารถเข้าถึงได้โดยตัวรับบริบท getContext :

 <script> import { getContext } from 'svelte'; import { key as userContextKey } from "./userContext"; const user = getContext(key); </script>

สรุป

Svelte เป็นเครื่องมือที่ทรงพลังที่มีประสิทธิภาพสูงและมี API ที่ยืดหยุ่น นอกจากข้อมูลพื้นฐานที่กล่าวถึงในโพสต์นี้ Svelte ยังมีคุณสมบัติดังต่อไปนี้:

  • การประกาศและแถลงการณ์เชิงโต้ตอบ
  • รอบล็อกเทมเพลต
  • การผูกมิติ
  • ร้านค้าระดับโลกอย่าง Redux
  • แอนิเมชั่นและตัวช่วยการเปลี่ยนแปลง
  • ผู้ช่วยดีบัก

โดยสรุป Svelte เป็นห้องสมุดที่ยอดเยี่ยมที่ตอบสนองทุกความต้องการในการสร้าง SPA และอื่นๆ มันสามารถแข่งขันกับผู้เล่นรายใหญ่ที่สุดในตลาดและแม้กระทั่งชนะ สิ่งที่สามารถใช้ได้ในขณะนี้คือการสนับสนุนในชุมชนนักพัฒนาส่วนหน้า

หมายเหตุ: รหัสทั้งหมดในบทความนี้มีอยู่ในที่เก็บ GitHub teimurjan/svelte-login-form การสาธิตสำหรับแบบฟอร์มการเข้าสู่ระบบมีอยู่ที่นี่