HTML روی وبسوکت؛ SPA بدون فریمورک سنگین
خلاصهٔ کاملتر
ساختن یه SPA معمولاً یعنی یه فریمورک جاوااسکریپتی برای رندر، یه API که JSON میده، و دو تا کدبیس مستقل که مجبورن از راه قرارداد همدیگه رو بفهمن. نویسنده میگه این استاندارد شده، ولی تنها راه نیست، و یه مسیر دیگه رو معرفی میکنه: HTML over WebSockets. ایده سادهست؛ سرور بهجای JSON، خودِ HTML ساختهشده رو میفرسته و کلاینت فقط اونو سر جاش میذاره. کل منطق رندر تو بکاند میمونه، با یه زبان واحد و بدون API.
به این خانواده hypermedia یا «HTML over the wire» میگن و سه تا نوع داره که فرقشون تو کاناله: روی HTTP و درخواستبهدرخواست مثل htmx، روی SSE با یه کانال یکطرفهٔ پیوسته از سرور به کلاینت مثل Datastar، و روی WebSocket با یه کانال دائمی و دوطرفه مثل Phoenix LiveView یا Django LiveView. به گفتهٔ نویسنده همین انتخاب کانال، معماری و الگوی ارتباطی کل برنامه رو تعیین میکنه.
شروع ماجرا برمیگرده به ElixirConf 2019، جایی که Chris McCord سازندهٔ Phoenix تو ۱۵ دقیقه یه کلون توییترِ بیدرنگ ساخت، بدون هیچ جاوااسکریپت رندری. جاوااسکریپت هنوز سمت کلاینت هست، ولی کارش رندر نیست؛ فقط کانال وبسوکت رو باز میکنه و HTML دریافتی رو جای درستش میذاره. چون کانال هیچوقت بسته نمیشه، سرور میتونه جلو بیفته و بدون اینکه کلاینت چیزی بخواد، تغییرات رو بفرسته.
مزیتهاش یه موتور رندر واحد، حذف API، نگهداری state روی سرور، اتصال مستقیم به دیتابیس، بیدرنگ بودن واقعی بدون polling، و broadcast به همهٔ کلاینتهای متصله؛ ساختن چت یا داشبورد یا بازی چندنفره تقریباً مجانی درمیاد. سئو هم قابلقبوله چون بار اول HTML سمت سرور رندر میشه، البته خزنده بهروزرسانیهای بعدی رو نمیبینه. چون HTML قبل از رفتن رو کانال escape میشه، تلاش برای تزریق کد بهشکل متن بیاثر میرسه و XSS عملاً بستهست.
در مقابل، سرور منابع بیشتری میخواد و معمولاً state هر کلاینت رو تو حافظه نگه میداره؛ برای مقیاس افقی باید اون state رو به اشتراک بذاری (تو جنگو یعنی Channels + یه سرور ASGI + Redis). نویسنده میگه این مشکل فقط با تعداد زیاد کاربر همزمان خودشو نشون میده و سایت خودش پیک ۶۰۰ خوانندهٔ همزمان رو روی سختافزاری در حد رزبریپای ۳ رد کرده. با لتنسی فیزیکی زیاد حس «آنی» بودن از بین میره، آفلاین کار نمیکنه، و منحنی یادگیریش از انداختن یه تگ اسکریپت تو صفحه تندتره.
امروز تقریباً هر زبانی پیادهسازی خودشو داره: Hotwire تو ریلز، Livewire 3 بههمراه Reverb تو لاراول، Blazor تو داتنت، و چند گزینه تو جنگو. نویسنده برای وقتی که جریان عمدتاً از سرور به کلاینته — نوتیفیکیشن، فید زنده، داشبورد، توکنهای جواب یه مدل هوش مصنوعی — SSE رو گزینهٔ ارزونتر میدونه: همون ایده روی یه کانال HTTP یکطرفه، با زیرساخت سادهتر و مقیاسپذیری راحتتر. قانون سرانگشتیش اینه: ارتباط دوطرفه و کمتأخیر میخوای، وبسوکت؛ فقط پوش از سمت سرور میخوای، SSE.
نکات کلیدی:
- کانال ارتباطی معماری رو تعیین میکنه: HTTP برای درخواستپاسخ، SSE برای پوش یکطرفه، وبسوکت برای دوطرفهٔ بیدرنگ
- منطق رندر و state روی سرور میمونه؛ نه API لازمه نه قرارداد بین دو کدبیس
- broadcast سمت سرور، ساختن چت و داشبورد زنده رو تقریباً رایگان میکنه
- escape شدن HTML سمت سرور جلوی XSS رو میگیره
- هزینهش مصرف منابع سرور، وابستگی به اتصال دائم و منحنی یادگیری تندتره
- تقریباً هر اکوسیستمی پیادهسازی داره: Phoenix LiveView، Django LiveView، Livewire + Reverb، Blazor، Hotwire




