• nextjs
  • sdk
  • edge

ประสบการณ์ของเราในการเพิ่ม Edge Runtime ให้กับ Next.js SDK

Logto's Next.js SDK รองรับ Edge Runtime แล้ว ในบทความนี้ เราจะแบ่งปันการผจญภัยของเรา เพื่อตรวจสอบอุปสรรคที่เผชิญ วิธีที่เราแก้ไขปัญหา และสิ่งที่เจ๋ง ๆ ที่เราได้เรียนรู้ระหว่างทาง

Sijie
Sijie
Developer

บทนำ

Edge Runtime ได้กลายเป็นคำที่ฮิตในเทคโนโลยี โดยขับเคลื่อนฟังก์ชันที่มีการตอบสนองต่ำและไดนามิกในแพลตฟอร์มต่าง ๆ ตั้งแต่ AWS Lambda@Edge และ Cloudflare Workers ไปจนถึง Vercel Edge โดยเน้นความสำคัญนี้ Vercel เพิ่งเปลี่ยนจาก "experimental-edge" เป็น "edge" ซึ่งแสดงถึงการสนับสนุนอย่างเป็นทางการในเฟรมเวิร์ก Next.js ที่เป็นที่นิยมของพวกเขา

เมื่อ Next.js SDK ของเราได้รับความสนใจอย่างจริงจัง เราที่ Logto คิดว่า "ทำไมไม่เพิ่มการสนับสนุน Edge Runtime ล่ะ?" ดังนั้นเราจึงเริ่มลงมือแล้วกระโจนเข้าไป ในบทความนี้ เราจะแบ่งปันการผจญภัยของเรา เพื่อตรวจสอบอุปสรรคที่เผชิญ วิธีที่เราแก้ไขปัญหา และสิ่งที่เจ๋ง ๆ ที่เราได้เรียนรู้ระหว่างทาง

การเปลี่ยนแปลงโมดูลและไลบรารีสำหรับการสนับสนุน Edge Runtime

การทำงานกับ Edge Runtime นำมาซึ่งความท้าทายที่มีเอกลักษณ์ ซึ่งส่วนใหญ่เกิดจากการที่มันไม่สนับสนุนโมดูลและไลบรารีทั้งหมดที่ใช้อยู่ทั่วไปใน Node.js เราพบปัญหานี้กับโมดูล crypto, lodash, และ iron-session ซึ่งทำให้ต้องมีการคิดค้นวิธีแก้ไขใหม่ ๆ

Crypto

ในสภาพแวดล้อม Node.js โมดูล crypto ใช้เป็นการทำห่อหุ้มสำหรับฟังก์ชันการเข้ารหัส OpenSSL แต่โชคร้าย Edge Runtime ไม่รองรับมัน แต่ว่า ไม่ต้องกังวล - Edge Runtimes ส่วนใหญ่สนับสนุน Web Crypto API ซึ่งแม้ว่าจะมีความแตกต่างเล็กน้อย แต่ก็เป็นสำหรับการแทนที่โมดูล crypto ได้ดีเยี่ยม ยกตัวอย่างเช่น การสร้างไบต์สุ่ม:

และการทำแฮช:

Lodash

Lodash เป็นที่นิยมท่ามกลางนักพัฒนาสำหรับความสะดวก แต่ Edge Runtime ไม่ชอบมัน วิธีแก้ปัญหาของเราคือ? เราเปลี่ยนฟังก์ชัน Lodash กับวิธีการใน JavaScript ต้นฉบับ ทำให้โค้ดของเรายังคงมีประสิทธิภาพและอ่านได้ง่าย

ในขณะที่การ แทนที่ฟังก์ชัน Lodash ส่วนใหญ่ ไม่ใช่เรื่องที่ลำบากเหลือเกิน แต่มันก็ต้องใช้ความชำนาญหน่อย ลองดูตัวอย่างที่เราได้สร้างสรรค์ความสามารถในการทำ "once" ในแบบของเราเอง:

Iron Session

เวอร์ชั่นล่าสุดของโมดูล iron-session เป็นมิตรกับ Edge Runtime ดังนั้นสิ่งที่เราต้องทำมีเพียงการอัปเดตเวอร์ชันของเรา ง่ายใช่ไหม!

การนำพาความซับซ้อนของ "Response" ใน Edge Runtime

อีกหนึ่งความท้าทายที่เราพบเมื่อปรับ SDK ของเราสำหรับ Edge Runtime คือการจัดการความแตกต่างในวัตถุ "Response" นี่คือวิธีที่เราเอาชนะความแตกต่างเหล่านี้:

การสร้างการตอบสนองด้วยตนเอง

แต่ต่างจากใน Node.js, คำขอใน Edge Runtime ไม่มีการตอบรับที่มาพร้อมกัน นั่นหมายความว่าเราต้องสร้างมันขึ้นมาใหม่โดยการเรียก new Response(), นี่คือตัวอย่างการคืนข้อมูล:

การปล่อย "withIronSessionApiRoute"

ใน Edge Runtime, Response.body เป็นสิ่งที่อ่านได้เท่านั้น นั่นหมายความว่าเราไม่สามารถเริ่มตอบสนองก่อนที่ข้อมูลจะถูกจัดเตรียมให้แล้ว ผลที่ตามมา ฟังก์ชัน "withIronSessionApiRoute" (ร่วมกับ middleware อื่น ๆ) ของเราต้องพักไว้

เพื่อทำความเข้าใจว่าทำไมเราต้องแทนที่ฟังก์ชันนี้ มาทำความเข้าใจกันก่อนว่า withIronSessionApiRoute มันทำอะไรบ้าง:

  1. มันจะดูลึกเข้าไปในคุกกี้, สร้างวัตถุเซสชัน, และผูกมันเข้ากับ res
  2. มันโดยอัตโนมัติจะเพิ่มส่วนหัว "set-cookie" ไปที่ res หากมีการเปลี่ยนแปลงในเซสชัน

แล้วเราทำอย่างไรเพื่อจำลองความสามารถนี้ใน Edge Runtime ใหม่นี้ของเรา?

  1. อ่าน: เราใช้ฟังก์ชัน getIronSession ที่มีอยู่ โดยให้มัน response ที่ว่างเปล่าและหลอก พิทักษ์เซสชันตามที่ต้องการ สิ่งนี้แทนที่วิธี "get" จาก req.session
  2. การเขียน: เราเตรียม response พร้อมข้อมูลล่วงหน้า แล้วใช้ getIronSession กับอินสแตนซ์ response นี้เพื่อรับวัตถุเซสชัน เมื่อเราได้รับวัตถุนี้มาแล้ว เราสามารถแก้ไขเซสชันตามต้องการ

การเปลี่ยนทิศทาง

การเปลี่ยนทิศทางใน Edge Runtime ต้องการให้เราต้องเพิ่มส่วนหัว Location ด้วยตัวเองในคำตอบของเรา

หนึ่งแพ็คเกจ สองรันไทม์

ในเส้นทางนี้ของเรา เราเลือกที่จะยึดติดกับแพ็คเกจเดียวเพื่อสนับสนุนทั้ง Edge และ Node.js รันไทม์

นี่คือเหตุผล

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

นี่คือสิ่งที่เราทำ

แทนที่จะทำซ้ำ เราเลือกที่จะขยายแพ็คเกจที่มีอยู่ เราเพิ่มโฟลเดอร์ "edge" ตรงที่ต้นตอของแพ็คเกจข้าง ๆ โฟลเดอร์ "src" เก่า จากนั้นเราอัปเดตไฟล์ package.json ด้วยการเพิ่มเส้นทางใหม่ใน "exports" ด้วยวิธีนี้ ทั้ง Edge และ Node.js รันไทม์สามารถอยู่ร่วมกันในแพ็คเกจเดียวกันได้โดยไม่มีความยุ่งยาก

สรุป

คุณสามารถตรวจสอบซอร์สโค้ดทั้งหมดของส่วน edge ของ Next.js SDK ของเราได้ที่ ที่นี่.

โดยการแบ่งปันการเดินทางของเราในการยอมรับ Edge Runtime เราหวังว่าจะเป็นแรงบันดาลใจและแนะแนวผู้ที่กำลังสำรวจเส้นทางที่คล้ายคลึงกัน คอยติดตามข้อมูลอัปเดตเพิ่มเติมกับ Next.js SDK ของเรา