การเพิ่มฟังก์ชันไดนามิกและอะซิงโครนัสให้กับไซต์ JAMstack
เผยแพร่แล้ว: 2022-03-10นั่นหมายความว่าไซต์ JAMstack ไม่สามารถจัดการการโต้ตอบแบบไดนามิกได้ใช่หรือไม่ ไม่อย่างแน่นอน!
ไซต์ JAMstack นั้นยอดเยี่ยมสำหรับการสร้างการโต้ตอบแบบอะซิงโครนัสไดนามิกสูง ด้วยการปรับเปลี่ยนเล็กน้อยในวิธีที่เราคิดเกี่ยวกับโค้ดของเรา เราสามารถสร้างปฏิสัมพันธ์ที่สนุกสนานและสมจริงได้โดยใช้เฉพาะเนื้อหาแบบคงที่เท่านั้น!
เป็นเรื่องปกติมากขึ้นที่จะเห็นเว็บไซต์ที่สร้างโดยใช้ JAMstack นั่นคือเว็บไซต์ที่สามารถทำหน้าที่เป็นไฟล์ HTML แบบคงที่ที่สร้างจาก JavaScript, Markup และ API บริษัทต่างๆ ชื่นชอบ JAMstack เพราะช่วยลดต้นทุนโครงสร้างพื้นฐาน เพิ่มความเร็วในการจัดส่ง และลดอุปสรรคในการปรับปรุงประสิทธิภาพและความปลอดภัย เนื่องจากการขนส่งทรัพย์สินแบบคงที่ขจัดความจำเป็นในการปรับขนาดเซิร์ฟเวอร์หรือทำให้ฐานข้อมูลพร้อมใช้งานสูง (ซึ่งหมายความว่าไม่มีเซิร์ฟเวอร์หรือฐานข้อมูลที่สามารถทำได้ ถูกแฮ็ก) นักพัฒนาอย่าง JAMstack จะช่วยลดความซับซ้อนในการทำให้เว็บไซต์ใช้งานได้จริงบนอินเทอร์เน็ต: ไม่มีเซิร์ฟเวอร์ให้จัดการหรือปรับใช้ เราสามารถเขียน front-end code และมันก็ ใช้ งานได้เหมือน มายากล
(“Magic” ในกรณีนี้คือการปรับใช้สแตติกอัตโนมัติ ซึ่งให้บริการฟรีจากบริษัทหลายแห่ง รวมถึง Netlify ที่ฉันทำงาน)
แต่ถ้าคุณใช้เวลามากในการพูดคุยกับนักพัฒนาเกี่ยวกับ JAMstack คำถามที่ว่า JAMstack สามารถจัดการกับ Serious Web Applications ได้หรือไม่ หลังจากที่ทุกไซต์ JAMstack เป็นไซต์แบบคงที่ใช่ไหม และไซต์แบบคงที่ไม่ได้ถูกจำกัดอย่างสุดความสามารถในสิ่งที่พวกเขาสามารถทำได้ใช่หรือไม่
นี่เป็นความเข้าใจผิดที่พบบ่อยมาก และในบทความนี้ เราจะเจาะลึกถึงที่มาของความเข้าใจผิด ดูความสามารถของ JAMstack และดูตัวอย่างต่างๆ ของการใช้ JAMstack เพื่อสร้าง Serious Web Applications
JAMstack Fundamentals
Phil Hawksworth อธิบายว่า JAMStack หมายถึงอะไรจริง ๆ และเมื่อใดที่เหมาะสมที่จะใช้ในโครงการของคุณ รวมถึงผลกระทบที่มีต่อเครื่องมือและสถาปัตยกรรมส่วนหน้า อ่านบทความที่เกี่ยวข้อง →
อะไรทำให้ไซต์ JAMstack "คงที่"
เว็บเบราว์เซอร์ในปัจจุบันโหลดไฟล์ HTML, CSS และ JavaScript เหมือนกับที่ทำใน 90s
แกนหลักของไซต์ JAMstack คือโฟลเดอร์ที่เต็มไปด้วยไฟล์ HTML, CSS และ JavaScript
สิ่งเหล่านี้คือ “สินทรัพย์คงที่” ซึ่งหมายความว่าเราไม่ต้องการขั้นตอนกลางในการสร้าง (เช่น โครงการ PHP เช่น WordPress จำเป็นต้องมีเซิร์ฟเวอร์เพื่อ สร้าง HTML ในทุกคำขอ)
นั่นคือพลังที่แท้จริงของ JAMstack: ไม่ต้องใช้โครงสร้างพื้นฐานพิเศษใดๆ เพื่อทำงาน คุณสามารถเรียกใช้ไซต์ JAMstack บนคอมพิวเตอร์ของคุณ โดยวางไว้บนเครือข่ายการจัดส่งเนื้อหาที่คุณต้องการ (CDN) โฮสต์ด้วยบริการต่างๆ เช่น GitHub Pages คุณยังสามารถลากและวางโฟลเดอร์ลงในไคลเอนต์ FTP ที่คุณชื่นชอบเพื่ออัปโหลด เพื่อแชร์โฮสติ้ง
ทรัพย์สินคงที่ไม่จำเป็นต้องหมายถึงประสบการณ์คงที่
เนื่องจากไซต์ JAMstack นั้นสร้างจากไฟล์สแตติก จึงเป็นเรื่องง่ายที่จะสรุปว่าประสบการณ์ในไซต์เหล่านั้น คุณก็รู้ static แต่นั่นไม่ใช่กรณี!
JavaScript สามารถทำสิ่งต่าง ๆ แบบไดนามิกได้มากมาย ท้ายที่สุดแล้ว เฟรมเวิร์ก JavaScript ที่ทันสมัยเป็นไฟล์สแตติกหลังจากที่เราผ่านขั้นตอนการสร้าง — และมีตัวอย่างประสบการณ์เว็บไซต์แบบไดนามิกที่น่าทึ่งหลายร้อยตัวอย่างที่ขับเคลื่อนโดยพวกเขา
มีความเข้าใจผิดกันทั่วไปว่า "คงที่" หมายถึงไม่ยืดหยุ่นหรือคงที่ แต่สิ่งที่ "คงที่" มีความหมายจริงๆ ในบริบทของ "ไซต์คงที่" คือเบราว์เซอร์ไม่ต้องการความช่วยเหลือใดๆ ในการนำเสนอเนื้อหา — พวกเขาสามารถใช้งานได้โดยกำเนิดโดยไม่ต้องให้เซิร์ฟเวอร์จัดการขั้นตอนการประมวลผลก่อน
หรือพูดอีกอย่างหนึ่งว่า
“ทรัพย์สินแบบคงที่” ไม่ได้หมายถึงแอพแบบคงที่ หมายความว่าไม่จำเป็นต้องใช้เซิร์ฟเวอร์
“
JAMstack สามารถทำได้หรือไม่
หากมีคนถามเกี่ยวกับการสร้างแอปใหม่ เป็นเรื่องปกติที่จะเห็นคำแนะนำสำหรับแนวทาง JAMstack เช่น Gatsby, Eleventy, Nuxt และเครื่องมืออื่นๆ ที่คล้ายคลึงกัน เป็นเรื่องปกติที่จะเห็นการโต้แย้งเกิดขึ้น: "ตัวสร้างไซต์แบบคงที่ไม่สามารถทำ _______" โดยที่ _______ เป็นแบบไดนามิก
แต่ดังที่เราได้กล่าวไปแล้วในหัวข้อก่อนหน้านี้ ไซต์ JAMstack สามารถ จัดการเนื้อหาและการโต้ตอบแบบไดนามิกได้!
นี่คือรายการที่ไม่สมบูรณ์ของสิ่งที่ฉันเคยได้ยินมาหลายครั้งว่ามีคนอ้างว่า JAMstack ไม่สามารถจัดการได้ซึ่งสามารถทำได้อย่างแน่นอน:
- โหลดข้อมูลแบบอะซิงโครนัส
- จัดการไฟล์การประมวลผล เช่น การจัดการรูปภาพ
- อ่านและเขียนลงฐานข้อมูล
- จัดการการตรวจสอบผู้ใช้และปกป้องเนื้อหาเบื้องหลังการเข้าสู่ระบบ
ในส่วนต่อไปนี้ เราจะดูวิธีการใช้เวิร์กโฟลว์เหล่านี้บนไซต์ JAMstack
หากคุณแทบรอไม่ไหวที่จะได้เห็นการทำงานของ JAMstack แบบไดนามิก คุณสามารถตรวจสอบการสาธิตก่อน จากนั้นกลับมาเรียนรู้วิธีทำงาน
หมายเหตุเกี่ยวกับการสาธิต :
การสาธิตเหล่านี้เขียนขึ้นโดยไม่มีกรอบการทำงานใดๆ เป็น HTML, CSS และ JavaScript มาตรฐานเท่านั้น สร้างขึ้นด้วยเบราว์เซอร์ที่ทันสมัย (เช่น Chrome, Firefox, Safari, Edge) และใช้ประโยชน์จากคุณลักษณะใหม่ๆ เช่น โมดูล JavaScript เทมเพลต HTML และ Fetch API ไม่มีการเพิ่มโพลีฟิล ดังนั้นหากคุณใช้เบราว์เซอร์ที่ไม่รองรับ การสาธิตอาจล้มเหลว
โหลดข้อมูลจาก API บุคคลที่สามแบบอะซิงโครนัส
“จะเกิดอะไรขึ้นหากฉันต้องการรับข้อมูลใหม่หลังจากสร้างไฟล์สแตติกแล้ว”
ใน JAMstack เราสามารถใช้ประโยชน์จากไลบรารีคำขอแบบอะซิงโครนัสจำนวนมาก รวมถึง Fetch API ในตัว เพื่อโหลดข้อมูลโดยใช้ JavaScript เมื่อใดก็ได้
การสาธิต: ค้นหา API บุคคลที่สามจากไซต์ JAMstack
สถานการณ์ทั่วไปที่ต้องมีการโหลดแบบอะซิงโครนัสคือเมื่อเนื้อหาที่เราต้องการขึ้นอยู่กับข้อมูลที่ผู้ใช้ป้อน ตัวอย่างเช่น หากเราสร้างหน้าค้นหาสำหรับ Rick & Morty API เราไม่ทราบว่าจะแสดงเนื้อหาใดจนกว่าจะมีผู้ป้อนข้อความค้นหา
เพื่อจัดการกับสิ่งนั้น เราต้อง:
- สร้างแบบฟอร์มที่ผู้คนสามารถพิมพ์ข้อความค้นหา
- ฟังการส่งแบบฟอร์ม
- รับคำค้นหาจากการส่งแบบฟอร์ม
- ส่งคำขอแบบอะซิงโครนัสไปยัง Rick & Morty API โดยใช้คำค้นหา
- แสดงผลคำขอในหน้า
อันดับแรก เราต้องสร้างแบบฟอร์มและองค์ประกอบว่างที่จะมีผลการค้นหาของเรา ซึ่งมีลักษณะดังนี้:
<form> <label for="name">Find characters by name</label> <input type="text" name="name" required /> <button type="submit">Search</button> </form> <ul></ul>
ต่อไป เราต้องเขียนฟังก์ชันที่จัดการการส่งแบบฟอร์ม ฟังก์ชันนี้จะ:
- ป้องกันพฤติกรรมการส่งแบบฟอร์มเริ่มต้น
- รับคำค้นหาจากการป้อนข้อมูลแบบฟอร์ม
- ใช้ Fetch API เพื่อส่งคำขอไปยัง Rick & Morty API โดยใช้คำค้นหา
- เรียกฟังก์ชันตัวช่วยที่แสดงผลการค้นหาบนหน้า
นอกจากนี้เรายังต้องเพิ่มตัวฟังเหตุการณ์ในแบบฟอร์มสำหรับเหตุการณ์ส่งที่เรียกใช้ฟังก์ชันตัวจัดการของเรา
นี่คือลักษณะของรหัสทั้งหมด:
<script type="module"> import showResults from './show-results.js'; const form = document.querySelector('form'); const handleSubmit = async event => { event.preventDefault(); // get the search term from the form input const name = form.elements['name'].value; // send a request to the Rick & Morty API based on the user input const characters = await fetch( `https://rickandmortyapi.com/api/character/?name=${name}`, ) .then(response => response.json()) .catch(error => console.error(error)); // add the search results to the DOM showResults(characters.results); }; form.addEventListener('submit', handleSubmit); </script>
หมายเหตุ: เพื่อให้จดจ่อกับพฤติกรรม JAMstack แบบไดนามิก เราจะไม่พูดถึงวิธีเขียนฟังก์ชันยูทิลิตี้เช่น showResults โค้ดได้รับการแสดงความคิดเห็นอย่างละเอียดถี่ถ้วน ดังนั้นให้ตรวจสอบแหล่งที่มาเพื่อเรียนรู้วิธีการทำงาน!
ด้วยโค้ดนี้ เราสามารถโหลดไซต์ของเราในเบราว์เซอร์ และเราจะเห็นฟอร์มว่างเปล่าโดยไม่มีผลลัพธ์แสดง:
หากเราป้อนชื่อตัวละคร (เช่น "rick") และคลิก "ค้นหา" เราจะเห็นรายการอักขระที่มีชื่อ "rick" แสดงอยู่:
เฮ้! ไซต์สแตติกนั้นเพิ่งโหลดข้อมูลแบบไดนามิกหรือไม่ ถังศักดิ์สิทธิ์!
คุณสามารถลองใช้ได้เองในการสาธิตสด หรือตรวจสอบซอร์สโค้ดแบบเต็มสำหรับรายละเอียดเพิ่มเติม
จัดการงานคอมพิวเตอร์ราคาแพงจากอุปกรณ์ของผู้ใช้
ในหลาย ๆ แอพ เราจำเป็นต้องทำสิ่งต่าง ๆ ที่ใช้ทรัพยากรค่อนข้างมาก เช่น การประมวลผลภาพ แม้ว่าการดำเนินการบางอย่างเหล่านี้ สามารถทำได้ โดยใช้ JavaScript ฝั่งไคลเอ็นต์เท่านั้น แต่ไม่จำเป็นต้องทำให้อุปกรณ์ของผู้ใช้ทำทุกอย่างที่ได้ผล หากพวกเขาใช้อุปกรณ์ที่ใช้พลังงานต่ำหรือพยายามยืดอายุการใช้งานแบตเตอรี่ 5% ล่าสุด การทำให้อุปกรณ์ทำงานหลายอย่างอาจเป็นประสบการณ์ที่น่าผิดหวังสำหรับพวกเขา
นั่นหมายความว่าแอป JAMstack โชคไม่ดีหรือไม่? ไม่เลย!
“A” ใน JAMstack ย่อมาจาก API ซึ่งหมายความว่าเราสามารถส่งงานนั้นไปยัง API และหลีกเลี่ยงการหมุนพัดลมคอมพิวเตอร์ของผู้ใช้จนถึงการตั้งค่า "โฮเวอร์"
“แต่เดี๋ยวก่อน” คุณอาจพูด “หากแอปของเราต้องทำงานแบบกำหนดเอง และงานนั้นต้องใช้ API นั่นหมายความว่าเรากำลังสร้างเซิร์ฟเวอร์อยู่ใช่หรือไม่”
ขอบคุณพลังของฟังก์ชันไร้เซิร์ฟเวอร์ เราไม่ต้องทำอย่างนั้น!
ฟังก์ชันไร้เซิร์ฟเวอร์ (เรียกอีกอย่างว่า "ฟังก์ชันแลมบ์ดา") เป็น API แบบหนึ่งโดยไม่ต้องใช้ต้นแบบเซิร์ฟเวอร์ใดๆ เราต้องเขียนฟังก์ชัน JavaScript แบบเก่า และงานทั้งหมดของการปรับใช้ การปรับขนาด การกำหนดเส้นทาง และอื่นๆ จะถูกถ่ายโอนไปยังผู้ให้บริการแบบไร้เซิร์ฟเวอร์ที่เราเลือก
การใช้ฟังก์ชันแบบไร้เซิร์ฟเวอร์ไม่ได้หมายความว่าไม่มีเซิร์ฟเวอร์ มันหมายความว่าเราไม่จำเป็นต้องคิดถึงเซิร์ฟเวอร์
“
ฟังก์ชันแบบไร้เซิร์ฟเวอร์คือเนยถั่วสำหรับ JAMstack ของเรา โดยจะปลดล็อกโลกทั้งใบของฟังก์ชันการทำงานแบบไดนามิกที่มีพลังสูงโดยไม่ต้องขอให้เราจัดการกับโค้ดเซิร์ฟเวอร์หรือ devops เลย
การสาธิต: แปลงรูปภาพเป็นระดับสีเทา
สมมติว่าเรามีแอปที่ต้องการ:
- ดาวน์โหลดรูปภาพจาก URL
- แปลงภาพนั้นเป็นระดับสีเทา
- อัปโหลดภาพที่แปลงแล้วไปยัง GitHub repo
เท่าที่ฉันรู้ ไม่มีทางที่จะทำการแปลงรูปภาพแบบนั้นทั้งหมดในเบราว์เซอร์ได้ และถึงแม้ว่าจะมีก็เป็นเรื่องที่ต้องทำค่อนข้างมาก ดังนั้นเราจึงไม่ต้องการทำให้ผู้ใช้ของเราทำงานหนัก ' อุปกรณ์
แต่เราสามารถส่ง URL ที่จะแปลงเป็นฟังก์ชันแบบไม่มีเซิร์ฟเวอร์ ซึ่งจะทำให้เราลำบากและส่ง URL กลับเป็นภาพที่แปลงแล้ว
สำหรับฟังก์ชันแบบไร้เซิร์ฟเวอร์ เราจะใช้ฟังก์ชัน Netlify ในโค้ดของไซต์ของเรา เราเพิ่มโฟลเดอร์ที่ระดับรูทที่เรียกว่า “ฟังก์ชัน” และสร้างไฟล์ใหม่ชื่อ “convert-image.js” ภายใน จากนั้นเราจะเขียนสิ่งที่เรียกว่าตัวจัดการ ซึ่งคือสิ่งที่ได้รับ และ — อย่างที่คุณอาจเดาได้ — จัดการ คำขอไปยังฟังก์ชันแบบไร้เซิร์ฟเวอร์ของเรา
ในการแปลงรูปภาพจะมีลักษณะดังนี้:
exports.handler = async event => { // only try to handle POST requests if (event.httpMethod !== 'POST') { return { statusCode: 404, body: '404 Not Found' }; } try { // get the image URL from the POST submission const { imageURL } = JSON.parse(event.body); // use a temporary directory to avoid intermediate file cruft // see https://www.npmjs.com/package/tmp const tmpDir = tmp.dirSync(); const convertedPath = await convertToGrayscale(imageURL, tmpDir); // upload the processed image to GitHub const response = await uploadToGitHub(convertedPath, tmpDir.name); return { statusCode: 200, body: JSON.stringify({ url: response.data.content.download_url, }), }; } catch (error) { return { statusCode: 500, body: JSON.stringify(error.message), }; } };
ฟังก์ชันนี้ทำสิ่งต่อไปนี้:
- ตรวจสอบเพื่อให้แน่ใจว่าคำขอถูกส่งโดยใช้วิธี HTTP POST
- ดึง URL รูปภาพจากเนื้อหา POST
- สร้างไดเร็กทอรีชั่วคราวสำหรับจัดเก็บไฟล์ที่จะล้างข้อมูลเมื่อดำเนินการฟังก์ชันเสร็จสิ้น
- เรียกฟังก์ชันตัวช่วยที่แปลงรูปภาพเป็นระดับสีเทา
- เรียกใช้ฟังก์ชันตัวช่วยที่อัปโหลดรูปภาพที่แปลงแล้วไปยัง GitHub
- ส่งกลับวัตถุตอบกลับด้วยรหัสสถานะ HTTP 200 และ URL ของรูปภาพที่อัปโหลดใหม่
หมายเหตุ : เราจะไม่อธิบายว่าตัวช่วยทำงานอย่างไรสำหรับการแปลงรูปภาพหรือการอัปโหลดไปยัง GitHub แต่ซอร์สโค้ดได้รับการแสดงความคิดเห็นอย่างดี เพื่อให้คุณเห็นว่ามันทำงานอย่างไร
ต่อไป เราต้องเพิ่มแบบฟอร์มที่จะใช้ในการส่ง URL สำหรับการประมวลผลและที่สำหรับแสดงก่อนและหลัง:
<form action="/.netlify/functions/convert-image" method="POST" > <label for="imageURL">URL of an image to convert</label> <input type="url" name="imageURL" required /> <button type="submit">Convert</button> </form> <div></div>
สุดท้าย เราต้องเพิ่มตัวฟังเหตุการณ์ลงในแบบฟอร์ม เพื่อให้เราสามารถส่ง URL ไปยังฟังก์ชันแบบไร้เซิร์ฟเวอร์ของเราเพื่อการประมวลผล:
<script type="module"> import showResults from './show-results.js'; const form = document.querySelector('form'); form.addEventListener('submit', event => { event.preventDefault(); // get the image URL from the form const imageURL = form.elements['imageURL'].value; // send the image off for processing const promise = fetch('/.netlify/functions/convert-image', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ imageURL }), }) .then(result => result.json()) .catch(error => console.error(error)); // do the work to show the result on the page showResults(imageURL, promise); }); </script>
หลังจากปรับใช้ไซต์ (พร้อมกับโฟลเดอร์ "ฟังก์ชัน" ใหม่) ไปยัง Netlify และ/หรือเริ่มต้น Netlify Dev ใน CLI เราจะเห็นแบบฟอร์มในเบราว์เซอร์ของเรา:
หากเราเพิ่ม URL รูปภาพลงในแบบฟอร์มแล้วคลิก "แปลง" เราจะเห็น "กำลังประมวลผล..." ชั่วขณะหนึ่งในขณะที่มีการแปลง เราจะเห็นรูปภาพต้นฉบับและภาพระดับสีเทาที่สร้างขึ้นใหม่
โอ้ แดง! ไซต์ JAMstack ของเราเพิ่งจัดการธุรกิจที่ค่อนข้างจริงจัง และเราไม่ต้องคิดถึงเซิร์ฟเวอร์เลยหรือเปลืองแบตเตอรี่ของผู้ใช้ของเรา!
ใช้ฐานข้อมูลเพื่อจัดเก็บและดึงรายการ
ในหลาย ๆ แอพ เราต้องการความสามารถในการบันทึกข้อมูลของผู้ใช้อย่างหลีกเลี่ยงไม่ได้ และนั่นหมายความว่าเราต้องการฐานข้อมูล
คุณอาจจะคิดว่า “แค่นั้นใช่ไหม? จิ๊กขึ้น? แน่นอนว่าไซต์ JAMstack ซึ่งคุณเคยบอกเราว่าเป็นเพียงกลุ่มของไฟล์ในโฟลเดอร์ ไม่สามารถเชื่อมต่อกับฐานข้อมูลได้!”
ออ คอนทราร์.
ดังที่เราเห็นในหัวข้อก่อนหน้านี้ ฟังก์ชันไร้เซิร์ฟเวอร์ทำให้เราสามารถทำสิ่งต่างๆ ที่ทรงพลังได้โดยไม่ต้องสร้างเซิร์ฟเวอร์ของเราเอง
ในทำนองเดียวกัน เราสามารถใช้เครื่องมือฐานข้อมูลในฐานะบริการ (DBaaS) (เช่น Fauna) เพื่ออ่านและเขียนไปยังฐานข้อมูลโดยไม่ต้องตั้งค่าหรือโฮสต์ฐานข้อมูลเอง
เครื่องมือ DBaaS ช่วยลดความซับซ้อนของขั้นตอนการตั้งค่าฐานข้อมูลสำหรับเว็บไซต์: การสร้างฐานข้อมูลใหม่นั้นตรงไปตรงมาเหมือนกับการกำหนดประเภทของข้อมูลที่เราต้องการจัดเก็บ เครื่องมือจะสร้างโค้ดทั้งหมดโดยอัตโนมัติเพื่อจัดการการสร้าง อ่าน อัปเดต และลบ (CRUD) และทำให้สามารถใช้ได้ผ่าน API ดังนั้นเราจึงไม่ต้อง จัดการ ฐานข้อมูลจริงๆ เราเพิ่งจะได้ ใช้ มัน
สาธิต: สร้างหน้าคำร้อง
หากเราต้องการสร้างแอปขนาดเล็กเพื่อรวบรวมลายเซ็นดิจิทัลสำหรับคำร้อง เราจำเป็นต้องตั้งค่าฐานข้อมูลเพื่อจัดเก็บลายเซ็นเหล่านั้นและอนุญาตให้หน้าเว็บอ่านเพื่อแสดงผล
สำหรับการสาธิตนี้ เราจะใช้ Fauna เป็นผู้ให้บริการ DBaaS ของเรา เราจะไม่ลงลึกถึงวิธีการทำงานของ Fauna แต่เพื่อแสดงให้เห็นถึงความพยายามเพียงเล็กน้อยที่จำเป็นในการตั้งค่าฐานข้อมูล เรามาลงรายการแต่ละขั้นตอนแล้วคลิกเพื่อรับฐานข้อมูลที่พร้อมใช้งาน:
- สร้างบัญชี Fauna ที่ https://fauna.com
- คลิก “สร้างฐานข้อมูลใหม่”
- ตั้งชื่อฐานข้อมูล (เช่น “dynamic-jamstack-demos”)
- คลิก “สร้าง”
- คลิก “ความปลอดภัย” ในเมนูด้านซ้ายมือในหน้าถัดไป
- คลิก "คีย์ใหม่"
- เปลี่ยนดรอปดาวน์บทบาทเป็น “เซิร์ฟเวอร์”
- เพิ่มชื่อสำหรับคีย์ (เช่น “Dynamic JAMstack Demos”)
- จัดเก็บกุญแจไว้ที่ที่ปลอดภัยเพื่อใช้กับแอพ
- คลิก “บันทึก”
- คลิก “GraphQL” ในเมนูด้านซ้ายมือ
- คลิก "นำเข้าสคีมา"
- อัปโหลดไฟล์ชื่อ
db-schema.gql
ที่มีรหัสต่อไปนี้:
type Signature { name: String! } type Query { signatures: [Signature!]! }
เมื่อเราอัปโหลดสคีมาแล้ว ฐานข้อมูลของเราก็พร้อมใช้งาน (อย่างจริงจัง.)
สิบสามขั้นตอนมีจำนวนมาก แต่ด้วยสิบสามขั้นตอนนั้น เราเพิ่งได้ฐานข้อมูล, GraphQL API, การจัดการความจุอัตโนมัติ, การปรับขนาด, การปรับใช้, การรักษาความปลอดภัย และอื่นๆ — ทั้งหมดจัดการโดยผู้เชี่ยวชาญด้านฐานข้อมูล ฟรี. เวลาที่มีชีวิตอยู่!
ในการทดลองใช้งาน ตัวเลือก "GraphQL" ในเมนูด้านซ้ายจะทำให้ตัวสำรวจ GraphQL มีเอกสารประกอบเกี่ยวกับการสืบค้นและการกลายพันธุ์ที่พร้อมใช้งาน ซึ่งช่วยให้เราดำเนินการ CRUD ได้
หมายเหตุ : เราจะไม่ลงรายละเอียดเกี่ยวกับการสืบค้นและการกลายพันธุ์ของ GraphQL ในโพสต์นี้ แต่ Eve Porcello ได้เขียนบทนำที่ยอดเยี่ยมในการส่งการสืบค้นและการกลายพันธุ์ของ GraphQL หากคุณต้องการข้อมูลเบื้องต้นเกี่ยวกับวิธีการทำงาน
ด้วยฐานข้อมูลที่พร้อมใช้งาน เราสามารถสร้างฟังก์ชันแบบไร้เซิร์ฟเวอร์ที่เก็บลายเซ็นใหม่ในฐานข้อมูล:
const qs = require('querystring'); const graphql = require('./util/graphql'); exports.handler = async event => { try { // get the signature from the POST data const { signature } = qs.parse(event.body); const ADD_SIGNATURE = ` mutation($signature: String!) { createSignature(data: { name: $signature }) { _id } } `; // store the signature in the database await graphql(ADD_SIGNATURE, { signature }); // send people back to the petition page return { statusCode: 302, headers: { Location: '/03-store-data/', }, // body is unused in 3xx codes, but required in all function responses body: 'redirecting...', }; } catch (error) { return { statusCode: 500, body: JSON.stringify(error.message), }; } };
ฟังก์ชันนี้ทำสิ่งต่อไปนี้:
- ดึงค่าลายเซ็นจากแบบฟอร์ม
POST
data - เรียกฟังก์ชันตัวช่วยที่เก็บลายเซ็นในฐานข้อมูล
- กำหนดการกลายพันธุ์ของ GraphQL เพื่อเขียนไปยังฐานข้อมูล
- ส่งการกลายพันธุ์โดยใช้ฟังก์ชันตัวช่วย GraphQL
- เปลี่ยนเส้นทางกลับไปที่หน้าที่ส่งข้อมูล
ต่อไป เราจำเป็นต้องมีฟังก์ชันแบบไร้เซิร์ฟเวอร์เพื่ออ่านลายเซ็นทั้งหมดจากฐานข้อมูล เพื่อให้เราสามารถแสดงจำนวนผู้ที่สนับสนุนคำร้องของเรา:
const graphql = require('./util/graphql'); exports.handler = async () => { const { signatures } = await graphql(` query { signatures { data { name } } } `); return { statusCode: 200, body: JSON.stringify(signatures.data), }; };
ฟังก์ชันนี้ส่งแบบสอบถามและส่งกลับ
หมายเหตุสำคัญเกี่ยวกับคีย์ที่ละเอียดอ่อนและแอป JAMstack :
สิ่งหนึ่งที่ควรทราบเกี่ยวกับแอปนี้คือ เราใช้ฟังก์ชันแบบไร้เซิร์ฟเวอร์เพื่อโทรออก เนื่องจากเราจำเป็นต้องส่งคีย์เซิร์ฟเวอร์ส่วนตัวไปยัง Fauna ซึ่งพิสูจน์ว่าเรามีสิทธิ์อ่านและเขียนฐานข้อมูลนี้ เราไม่สามารถใส่คีย์นี้ลงในโค้ดฝั่งไคลเอ็นต์ได้ เนื่องจากนั่นหมายความว่าทุกคนสามารถค้นหาคีย์นี้ได้ในซอร์สโค้ดและใช้เพื่อดำเนินการ CRUD กับฐานข้อมูลของเรา ฟังก์ชันแบบไร้เซิร์ฟเวอร์มีความสำคัญต่อการรักษาความเป็นส่วนตัวของคีย์ส่วนตัวในแอป JAMstack
เมื่อเราตั้งค่าฟังก์ชันแบบไร้เซิร์ฟเวอร์แล้ว เราก็สามารถเพิ่มแบบฟอร์มที่ส่งไปยังฟังก์ชันเพื่อเพิ่มลายเซ็น องค์ประกอบเพื่อแสดงลายเซ็นที่มีอยู่ และ JS เล็กน้อยเพื่อเรียกใช้ฟังก์ชันเพื่อรับลายเซ็นและใส่ลงในจอแสดงผลของเรา องค์ประกอบ:
<form action="/.netlify/functions/add-signature" method="POST"> <label for="signature">Your name</label> <input type="text" name="signature" required /> <button type="submit">Sign</button> </form> <ul class="signatures"></ul> <script> fetch('/.netlify/functions/get-signatures') .then(res => res.json()) .then(names => { const signatures = document.querySelector('.signatures'); names.forEach(({ name }) => { const li = document.createElement('li'); li.innerText = name; signatures.appendChild(li); }); }); </script>
หากเราโหลดสิ่งนี้ในเบราว์เซอร์ เราจะเห็นแบบฟอร์มคำร้องพร้อมลายเซ็นด้านล่าง:
แล้วถ้าเราเพิ่มลายเซ็นของเรา...
…และส่ง เราจะเห็นชื่อของเราต่อท้ายรายการ:
น้องหมาสุดฮอต! เราเพิ่งเขียนแอป JAMstack ที่ขับเคลื่อนด้วยฐานข้อมูลเต็มรูปแบบด้วยโค้ดประมาณ 75 บรรทัดและสคีมาฐานข้อมูล 7 บรรทัด!
ปกป้องเนื้อหาด้วยการตรวจสอบผู้ใช้
“โอเค คราวนี้คุณติด แน่ ” คุณอาจจะคิด “ ไม่มีทาง ที่ไซต์ JAMstack สามารถจัดการการพิสูจน์ตัวตนผู้ใช้ได้ มันจะเป็นไปได้ยังไงกันเนี่ย!”
ฉันจะ บอก คุณว่ามันทำงานอย่างไร เพื่อนของฉัน: ด้วยฟังก์ชันไร้เซิร์ฟเวอร์ที่เชื่อถือได้และ OAuth
OAuth เป็นมาตรฐานที่ใช้กันอย่างแพร่หลายในการอนุญาตให้ผู้คนให้แอปเข้าถึงข้อมูลบัญชีของตนได้อย่างจำกัด แทนที่จะแชร์รหัสผ่าน หากคุณเคยลงชื่อเข้าใช้บริการโดยใช้บริการอื่น (เช่น “ลงชื่อเข้าใช้ด้วยบัญชี Google ของคุณ”) แสดงว่าคุณเคยใช้ OAuth มาก่อน
หมายเหตุ: เราจะไม่ลงลึกถึงวิธีการทำงานของ OAuth แต่ Aaron Parecki ได้เขียนภาพรวมที่ชัดเจนของ OAuth ซึ่งครอบคลุมรายละเอียดและเวิร์กโฟลว์
ในแอป JAMstack เราสามารถใช้ประโยชน์จาก OAuth และ JSON Web Tokens (JWT) ที่ให้มาเพื่อระบุผู้ใช้ ปกป้องเนื้อหา และอนุญาตให้เฉพาะผู้ใช้ที่ลงชื่อเข้าใช้เท่านั้นที่ดูได้
การสาธิต: ต้องเข้าสู่ระบบเพื่อดูเนื้อหาที่ได้รับการคุ้มครอง
หากเราจำเป็นต้องสร้างเว็บไซต์ที่แสดงเฉพาะเนื้อหาต่อผู้ใช้ที่เข้าสู่ระบบ เราจำเป็นต้องมีบางสิ่ง:
- ผู้ให้บริการข้อมูลประจำตัวที่จัดการผู้ใช้และขั้นตอนการลงชื่อเข้าใช้
- องค์ประกอบ UI เพื่อจัดการการเข้าสู่ระบบและออกจากระบบ
- ฟังก์ชันไร้เซิร์ฟเวอร์ที่ตรวจสอบผู้ใช้ที่เข้าสู่ระบบโดยใช้ JWT และส่งคืนเนื้อหาที่ได้รับการป้องกันหากมีให้
สำหรับตัวอย่างนี้ เราจะใช้ Netlify Identity ซึ่งให้ประสบการณ์นักพัฒนาที่น่าพึงพอใจในการเพิ่มการรับรองความถูกต้อง และจัดเตรียมวิดเจ็ตแบบดรอปอินสำหรับจัดการการดำเนินการเข้าสู่ระบบและออกจากระบบ
วิธีเปิดใช้งาน:
- ไปที่แดชบอร์ด Netlify ของคุณ
- เลือกไซต์ที่ต้องการการตรวจสอบสิทธิ์จากรายการไซต์ของคุณ
- คลิก “identity” ในการนำทางด้านบน
- คลิกปุ่ม "เปิดใช้งานข้อมูลประจำตัว"
เราสามารถเพิ่ม Netlify Identity ในไซต์ของเราได้โดยเพิ่มมาร์กอัปที่แสดงเนื้อหาที่ออกจากระบบและเพิ่มองค์ประกอบเพื่อแสดงเนื้อหาที่ได้รับการป้องกันหลังจากเข้าสู่ระบบ:
<div class="content logged-out"> <h1>Super Secret Stuff!</h1> <p> only my bestest friends can see this content</p> <button class="login">log in / sign up to be my best friend</button> </div> <div class="content logged-in"> <div class="secret-stuff"></div> <button class="logout">log out</button> </div>
มาร์กอัปนี้ใช้ CSS ในการแสดงเนื้อหาโดยพิจารณาว่าผู้ใช้เข้าสู่ระบบหรือไม่ อย่างไรก็ตาม เราไม่สามารถพึ่งพาสิ่งนั้นในการปกป้องเนื้อหาได้อย่างแท้จริง ทุกคนสามารถดูซอร์สโค้ดและขโมยความลับของเราได้!
แต่เราได้สร้าง div ว่างที่จะมีเนื้อหาที่ได้รับการคุ้มครองของเรา แต่เราจำเป็นต้องส่งคำขอไปยังฟังก์ชันแบบไร้เซิร์ฟเวอร์เพื่อรับเนื้อหานั้นจริงๆ เราจะเจาะลึกวิธีการทำงานในไม่ช้า
ต่อไป เราต้องเพิ่มรหัสเพื่อให้ปุ่มเข้าสู่ระบบทำงาน โหลดเนื้อหาที่ได้รับการป้องกัน และแสดงบนหน้าจอ:
<script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script> <script> const login = document.querySelector('.login'); login.addEventListener('click', () => { netlifyIdentity.open(); }); const logout = document.querySelector('.logout'); logout.addEventListener('click', () => { netlifyIdentity.logout(); }); netlifyIdentity.on('logout', () => { document.querySelector('body').classList.remove('authenticated'); }); netlifyIdentity.on('login', async () => { document.querySelector('body').classList.add('authenticated'); const token = await netlifyIdentity.currentUser().jwt(); const response = await fetch('/.netlify/functions/get-secret-content', { headers: { Authorization: `Bearer ${token}`, }, }).then(res => res.text()); document.querySelector('.secret-stuff').innerHTML = response; }); </script>
นี่คือสิ่งที่รหัสนี้ทำ:
- โหลดวิดเจ็ต Netlify Identity ซึ่งเป็นไลบรารีตัวช่วยที่สร้างโมดอลการเข้าสู่ระบบ จัดการเวิร์กโฟลว์ OAuth ด้วย Netlify Identity และให้แอปของเราเข้าถึงข้อมูลของผู้ใช้ที่ล็อกอิน
- เพิ่มตัวฟังเหตุการณ์ให้กับปุ่มเข้าสู่ระบบที่ทริกเกอร์โมดอลการเข้าสู่ระบบ Netlify Identity เพื่อเปิด
- เพิ่มตัวฟังเหตุการณ์ให้กับปุ่มออกจากระบบที่เรียกวิธีการออกจากระบบ Netlify Identity
- เพิ่มตัวจัดการเหตุการณ์สำหรับการล็อกเอาต์เพื่อลบคลาสที่รับรองความถูกต้องเมื่อออกจากระบบ ซึ่งซ่อนเนื้อหาที่ล็อกอินและแสดงเนื้อหาที่ล็อกเอาต์
- เพิ่มตัวจัดการเหตุการณ์สำหรับการเข้าสู่ระบบที่:
- เพิ่มคลาสรับรองความถูกต้องเพื่อแสดงเนื้อหาที่เข้าสู่ระบบและซ่อนเนื้อหาที่ออกจากระบบ
- คว้าJWT .ของผู้ใช้ที่เข้าสู่ระบบ
- เรียกใช้ฟังก์ชันแบบไร้เซิร์ฟเวอร์เพื่อโหลดเนื้อหาที่มีการป้องกัน โดยส่ง JWT ในส่วนหัวการอนุญาต
- ใส่เนื้อหาที่เป็นความลับใน div ของ secret-stuff เพื่อให้ผู้ใช้ที่ลงชื่อเข้าใช้สามารถมองเห็นได้
ตอนนี้ฟังก์ชันไร้เซิร์ฟเวอร์ที่เรากำลังเรียกใช้ในรหัสนั้นไม่มีอยู่จริง มาสร้างมันด้วยรหัสต่อไปนี้:
exports.handler = async (_event, context) => { try { const { user } = context.clientContext; if (!user) throw new Error('Not Authorized'); return { statusCode: 200, headers: { 'Content-Type': 'text/html', }, body: `
คุณได้รับเชิญ ${user.user_metadata.full_name}!
หากคุณอ่านได้ แสดงว่าเราคือเพื่อนซี้กัน
นี่คือรายละเอียดลับสำหรับงานเลี้ยงวันเกิดของฉัน:
`, }; } จับ (ผิดพลาด) { กลับ { รหัสสถานะ: 401, เนื้อหา: 'ไม่ได้รับอนุญาต', }; } };
jason.af/party
ฟังก์ชันนี้ทำสิ่งต่อไปนี้:
- ตรวจสอบผู้ใช้ในอาร์กิวเมนต์บริบทของฟังก์ชันไร้เซิร์ฟเวอร์
- เกิดข้อผิดพลาดหากไม่พบผู้ใช้
- ส่งคืนเนื้อหาลับหลังจากตรวจสอบว่าผู้ใช้ที่เข้าสู่ระบบร้องขอ
ฟังก์ชั่น Netlify จะตรวจจับ Netlify Identity JWT ในส่วนหัวการอนุญาตและใส่ข้อมูลนั้นลงในบริบทโดยอัตโนมัติ ซึ่งหมายความว่าเราสามารถตรวจสอบ JWT ที่ถูกต้องโดยไม่ต้องเขียนโค้ดเพื่อตรวจสอบ JWT!
เมื่อเราโหลดหน้านี้ในเบราว์เซอร์ เราจะเห็นหน้าออกจากระบบก่อน:
หากเราคลิกปุ่มเพื่อเข้าสู่ระบบ เราจะเห็นวิดเจ็ต Netlify Identity:
หลังจากเข้าสู่ระบบ (หรือลงทะเบียน) เราจะเห็นเนื้อหาที่ได้รับการคุ้มครอง:
ว้าว! เราเพิ่งเพิ่มการเข้าสู่ระบบของผู้ใช้และเนื้อหาที่ได้รับการป้องกันลงในแอป JAMstack!
สิ่งที่ต้องทำต่อไป
JAMstack เป็นมากกว่า "ไซต์แบบคงที่" — เราสามารถตอบสนองต่อการโต้ตอบของผู้ใช้ เก็บข้อมูล จัดการการตรวจสอบผู้ใช้ และอะไรก็ได้ที่เราต้องการทำบนเว็บไซต์สมัยใหม่ และทั้งหมดนี้ไม่จำเป็นต้องจัดเตรียม กำหนดค่า หรือปรับใช้เซิร์ฟเวอร์!
คุณต้องการสร้างอะไรด้วย JAMstack? มีอะไรที่คุณยังไม่มั่นใจว่า JAMstack สามารถจัดการได้ ฉันชอบที่จะได้ยินเกี่ยวกับเรื่องนี้ - ติดต่อเราทาง Twitter หรือในความคิดเห็น!