السلام عليكم يا جماعة الخير، معكم أخوكم أبو عمر.
قبل كم سنة، كنت قاعد مع فريق شغال على مشروع لعميل مهم. المشروع كان عبارة عن لوحة تحكم (Dashboard) ضخمة بتعرض بيانات حية من آلاف أجهزة إنترنت الأشياء (IoT) موزعة حول العالم. تخيل معي… حساسات حرارة، ضغط، حركة، كله بتدفق بشكل مباشر على الشاشة. بدأنا المشروع بحماس، واستخدمنا الأدوات اللي كلنا بنعرفها وبنحبها: React في الواجهة الأمامية و Node.js في الخلفية.
الأمور كانت ماشية تمام في البداية، والنموذج الأولي كان شكله حلو. لكن لما بدأنا نربط البيانات الحقيقية… بدأت المصايب. الصفحة صارت “تعلق”، التحديثات بطيئة، ومروحة اللابتوب تبعي صارت تشتغل كإنها محرك طيارة نفاثة. حاولنا كل الحلول: عملنا Debouncing، و Throttling، وحسّنا من أداء المكونات، لكن المشكلة كانت أعمق. الـ Virtual DOM تبع React كان بيستهلك موارد هائلة مع كل تحديث، والـ Garbage Collector في JavaScript كان بيعمل “وقفات” مفاجئة عشان “ينظف الذاكرة”، وهذا كان يسبب تجربة استخدام سيئة جداً.
وقتها حسيت بإحباط كبير. هل معقول إنه تكنولوجيا الويب وصلت لحدودها؟ في جلسة عصف ذهني مع الفريق، واحد من الشباب الجداد اقترح فكرة كانت تبدو مجنونة وقتها: “ليش ما نجرب Rust و WebAssembly؟”. أنا، زي أي مبرمج قديم، كنت متعود على أدواتي وكنت شايف Rust لغة معقدة خاصة ببرمجة الأنظمة. لكن اليأس بخليك تجرب أي إشي. وهذا القرار… غيّر كل نظرتي لمستقبل تطوير الويب.
لماذا لم تعد JavaScript كافية وحدها؟
خلونا نكون صريحين، JavaScript لغة عظيمة خدمت الويب لعقود. لكن الويب اليوم غير عن ويب الأمس. الويب تطور من مجرد صفحات لعرض النصوص والصور إلى “منصة تطبيقات” متكاملة. اليوم، نحن نبني تطبيقات معقدة داخل المتصفح مباشرة: برامج تصميم مثل Figma، محررات فيديو، أدوات تحليل بيانات، وحتى نماذج ذكاء اصطناعي.
هذه التطبيقات تحتاج أداءً يقترب من أداء تطبيقات سطح المكتب، وهو أمر تكافح JavaScript لتوفيره لسببين رئيسيين:
- طبيعتها المفسّرة (Interpreted): على عكس اللغات المترجمة (Compiled) مثل C++ أو Rust، يتم تفسير كود JS أثناء التشغيل، مما يجعله أبطأ بطبيعته.
- إدارة الذاكرة التلقائية (Garbage Collection): صحيح أنها تريح المبرمج، لكن الـ GC يمكن أن يسبب “تجميد” أو توقف مؤقت للتطبيق في لحظات غير متوقعة ليقوم بتنظيف الذاكرة، وهذا قاتل في التطبيقات التي تتطلب استجابة فورية.
هنا يأتي دور Rust و WebAssembly ليقدموا الحل: أداء قريب من اللغات الأصلية (Native) مع أمان ذاكرة لا مثيل له، وكل هذا يعمل داخل المتصفح.
Leptos: ثورة في عالم الواجهات الأمامية
عندما بدأنا رحلتنا مع Rust في تطوير الويب، وقعنا في حب إطار عمل اسمه Leptos. هذا الإطار ليس مجرد “React بنكهة Rust”، بل هو إعادة تفكير جذرية في كيفية بناء الواجهات التفاعلية. سر قوته يكمن في مفهومين أساسيين.
وداعاً للـ Virtual DOM، ومرحباً بالتفاعلية الدقيقة (Fine-Grained Reactivity)
إطارات العمل مثل React تستخدم ما يسمى بالـ “DOM الافتراضي” (Virtual DOM). الفكرة هي أنه عند حدوث أي تغيير في حالة التطبيق (State)، يقوم React ببناء شجرة كاملة من المكونات في الذاكرة، ثم يقارنها بالشجرة القديمة، وبعدها يكتشف الفروقات ويطبقها على الـ DOM الحقيقي في المتصفح. تخيل الأمر وكأنك تملك نسختين من قائمة مشتريات طويلة جداً، ومع كل تغيير بسيط، تضطر لمقارنة القائمتين سطراً بسطر لتجد الاختلاف. هذا الأمر مكلف جداً من ناحية المعالج والذاكرة.
Leptos (وإطارات عمل حديثة أخرى مثل SolidJS) يتبع نهجاً مختلفاً تماماً وأكثر ذكاءً: التفاعلية الدقيقة باستخدام ما يسمى بـ “الإشارات” (Signals). الإشارة هي مجرد قيمة يمكن “مراقبتها”. عندما تربط عنصراً في واجهتك (مثل نص داخل <p>) بإشارة معينة، وعندما تتغير قيمة هذه الإشارة، يتم تحديث ذلك العنصر المحدد فقط، وبشكل مباشر، بدون بناء أي أشجار افتراضية وبدون أي مقارنات.
نصيحة من أبو عمر: فكر في الأمر هكذا: الـ Virtual DOM مثل مدير يصرخ في كل الموظفين “انتبهوا، هناك تغيير ما!”، بينما الـ Signals مثل رسالة مباشرة تصل فقط للموظف المعني بالتغيير. النتيجة؟ كفاءة أعلى بكثير، استهلاك أقل للبطارية، وسرعة استجابة خرافية، وهذا بالضبط ما احتجناه في مشروع لوحة التحكم.
السحر الحقيقي: الدوال المتشابهة (Server Functions)
هذه الميزة، يا جماعة، هي التي تجعل تجربة المطور (Developer Experience) مع Leptos إشي من الآخر. في الوضع الطبيعي، عندما تريد جلب بيانات من السيرفر، عليك أن:
- تكتب كود الواجهة الخلفية (Backend) لإنشاء نقطة نهاية API (e.g.,
/api/get-user-data). - تحدد شكل البيانات المتبادلة (JSON).
- تكتب كود الواجهة الأمامية (Frontend) لعمل طلب `fetch` لهذه النقطة.
- تتعامل مع تحويل البيانات (Serialization/Deserialization).
مع Leptos، كل هذا التعقيد يختفي. يمكنك كتابة دالة Rust عادية، وتضيف فوقها علامة #[server]. عندما تستدعي هذه الدالة من كود الواجهة الأمامية، يقوم Leptos تلقائياً بكل السحر في الخلفية: يحول الاستدعاء إلى طلب شبكة، ينفذ الكود على السيرفر، ويعيد لك النتيجة كأنك استدعيت دالة عادية. هذا ما نسميه “التطوير المتشابه” (Isomorphic Development).
شاهد هذا المثال البسيط لترى كيف تبدو الأمور:
use leptos::*;
// 1. نعرّف دالة السيرفر ونعطيها اسماً ومساراً
#[server(GetGreeting, "/api")]
pub async fn get_greeting(name: String) -> Result {
// هذا الكود يتنفذ على السيرفر فقط!
// يمكنه الوصول لقواعد البيانات والملفات بأمان.
Ok(format!("أهلاً وسهلاً، {}! رسالة من السيرفر.", name))
}
#[component]
fn App(cx: Scope) -> impl IntoView {
// 2. ننشئ "إشارة" لتخزين رد السيرفر
let (greeting, set_greeting) = create_signal(cx, String::new());
// 3. نستدعي دالة السيرفر كأنها دالة عادية عند الضغط على الزر
let on_click = move |_| {
spawn_local(async move {
// الاستدعاء يبدو عادياً، لكن Leptos يحوله لطلب API
let res = get_greeting("أبو عمر".to_string()).await;
set_greeting.set(res.unwrap_or_default());
});
};
view! { cx,
{greeting}
}
}
لاحظ كيف أننا لم نكتب أي كود `fetch` أو REST API. كتبنا دالة Rust واحدة، والإطار قام بالباقي. هذا يسرّع عملية التطوير بشكل لا يصدق ويوحد الكود بين الواجهتين الأمامية والخلفية.
وماذا عن الواجهات الخلفية؟ Axum يدخل الحلبة
بينما يتألق Leptos في بناء تطبيقات Full-Stack متكاملة، ماذا لو كنت تريد بناء واجهة خلفية (Backend) فقط؟ ربما تريد بناء Microservice أو API نقية لخدمة تطبيق موبايل. هنا يأتي دور إطار عمل آخر قوي جداً في عالم Rust وهو Axum.
Axum هو إطار عمل للويب مبني فوق مكتبة `tokio`، وهي المحرك الأساسي للبرمجة غير المتزامنة (Asynchronous) في Rust. يتميز Axum ببيئة عمل مريحة جداً (Ergonomic) ومرونة هائلة في بناء الخدمات الخلفية. Leptos نفسه يستخدم Axum تحت الغطاء لإدارة جزء السيرفر.
متى أستخدم Leptos ومتى أختار Axum؟
نصيحة من أبو عمر: القاعدة بسيطة، زي ما بنحكيها بالبلد:
- استخدم Leptos (Full-Stack): عندما تبني تطبيق ويب متكامل (Monolith). مثل لوحات التحكم، الأدوات الداخلية للشركات، أو أي تطبيق تكون فيه الواجهة الأمامية والخلفية مرتبطتين بشكل وثيق. ستستفيد من سرعة التطوير الهائلة التي توفرها الدوال المتشابهة.
- استخدم Axum (Backend-Only): عندما تبني خدمة خلفية مستقلة تماماً. مثل واجهة برمجة تطبيقات (API) لتطبيق جوال، أو خدمة مصغرة (Microservice) ضمن بنية تحتية أكبر، أو أي سيناريو تحتاج فيه إلى أقصى درجات التحكم في الواجهة الخلفية بمعزل عن الواجهة الأمامية.
WebAssembly (Wasm): نظام التشغيل الجديد للمتصفح
من المهم أن نفهم أن WebAssembly ليس بديلاً لـ JavaScript، بل هو المكمل المثالي لها. Wasm هو “هدف ترجمة” (Compilation Target)، بمعنى أنك تستطيع كتابة كود بلغات عالية الأداء مثل Rust أو C++ أو C# ثم ترجمته ليعمل داخل المتصفح بسرعة تقترب من سرعة الكود الأصلي (Native).
في عام 2026، ومع نضوج معيار WASI (WebAssembly System Interface)، أصبح بإمكان كود Wasm الوصول إلى موارد النظام (مثل نظام الملفات والشبكة) بطريقة آمنة ومقننة (Sandboxed)، مما يفتح الباب لتطبيقات ويب كانت في السابق من نسج الخيال:
- محاكاة فيزيائية معقدة داخل المتصفح.
- تشغيل نماذج الذكاء الاصطناعي مباشرة على جهاز المستخدم (Client-side).
- تطبيقات تحرير الفيديو والصوت عالية الأداء.
- نقل أجزاء كبيرة من منطق الألعاب الثقيلة لتعمل على الويب.
الاستراتيجية الرابحة هي استخدام JavaScript لما تبرع فيه (التعامل مع الـ DOM، تنظيم واجهة المستخدم)، واستخدام WebAssembly للمهام التي تتطلب قوة حسابية هائلة.
خلاصة القول ونصيحة من القلب 🚀
يا جماعة الخير، عالم تطوير الويب يتغير بسرعة. الأدوات التي كانت تعتبر الخيار الأول بالأمس، قد لا تكون الأنسب لتحديات الغد. لغة Rust، مع إطارات عمل مثل Leptos وتقنية WebAssembly، لم تعد مجرد “موضة” أو تقنية متخصصة، بل أصبحت لاعباً أساسياً في بناء الجيل القادم من تطبيقات الويب عالية الأداء والأمان.
الانتقال لم يكن سهلاً في البداية، فـ Rust تتطلب منك طريقة تفكير مختلفة، خاصة فيما يتعلق بملكية الذاكرة (Ownership). لكن العائد على هذا الاستثمار هائل: تطبيقات أسرع، أكثر استقراراً، وأقل استهلاكاً للموارد، مع تجربة تطوير موحدة ورائعة.
نصيحتي لك: لا تخف من الخروج من منطقة راحتك. ابدأ اليوم بتعلم أساسيات Rust. جرب بناء مشروع صغير باستخدام Leptos. قد تكون هذه الخطوة هي التي ستضعك في مقدمة المطورين في السنوات القادمة.
الله يوفقكم جميعاً في رحلتكم البرمجية!