ما وراء الـ WebView: هندسة تطبيقات سطح مكتب عالمية حقاً باستخدام Expo و Tauri
تخلص من ثقل Electron وتعرف على كيفية دمج بيئة React Native العالمية من Expo مع خلفية Tauri البرمجية عالية الأداء بلغة Rust. سأتعمق في الأنماط المعمارية المطلوبة لشحن تطبيقات سطح مكتب خفيفة وذات طابع أصيل (native) من قاعدة برمجية واحدة.

ما وراء الـ WebView: هندسة تطبيقات سطح مكتب عالمية حقاً باستخدام Expo و Tauri
لسنوات، كان حلم "اكتب الكود مرة واحدة، وشغله في أي مكان" (write once, run everywhere) يطارده شبح واحد متضخم: Electron. لا تفهمني خطأ—لقد أحدث Electron ثورة في الصناعة من خلال خفض حواجز الدخول لبناء تطبيقات سطح المكتب. ولكن كمهندس برمجيات خبير (Senior Engineer)، سئمت من شحن تطبيقات 'Hello World' بحجم 100MB تستهلك 400MB من الـ RAM لمجرد البقاء في وضع الخمول.
مؤخراً، كنت أختبر Stack يبدو وكأنه طفرة حقيقية لنموذج التطبيقات العالمية: Expo (React Native Web) مع Tauri.
الأمر لا يتعلق فقط بوضع موقع إلكتروني داخل إطار؛ بل يتعلق بالاستفادة من بيئة Expo للتطبيقات الجوالة والويب، مع استخدام Rust للتعامل مع المهام الثقيلة على سطح المكتب. إليك كيف أقوم بهندسة هذه التطبيقات العالمية حقاً.
المعمارية: لماذا تنجح هذه الطريقة؟
عندما نستخدم Expo، فنحن نكتب بالفعل كوداً يستهدف iOS و Android والويب. إن تطبيق Expo لـ react-native-web ناضج بشكل ملحوظ. ومع ذلك، كانت الحلقة المفقودة دائماً هي استراتيجية أداء عالية لسطح المكتب.
من خلال إدخال Tauri في المزيج، نستبدل Chromium بـ WebView الأصلي للنظام (WebView2 على Windows، و WebKit على macOS) ونستبدل خلفية Node.js البرمجية بلغة Rust.
المقارنة
| الميزة | Electron | Expo + Tauri |
|---|---|---|
| Bundle Size | ~80MB+ | ~3-10MB |
| Memory Usage | مرتفع (V8 + Chromium) | منخفض (System WebView) |
| Backend Language | JavaScript/Node.js | Rust |
| Security | سطح هجوم واسع | ذاكرة آمنة (Rust) |
وضع الأساسات
لجعل هذا يعمل، يجب تهيئة مشروع Expo الخاص بك للويب أولاً. عادةً ما أبدأ بالتأكد من تحسين ملف app.json لعمليات تصدير الويب (web exports).
بمجرد تشغيل مشروع Expo، تقوم ببدء Tauri في المجلد الرئيسي. التحول الجوهري هنا هو توجيه devPath الخاص بـ Tauri إلى خادم تطوير Expo (عادةً localhost:8081) وتوجيه distDir إلى مجلد التصدير ./dist.
نمط الجسر "العالمي" (Universal Bridge Pattern)
التحدي الهندسي الحقيقي هو التعامل مع الـ Native Modules. كيف تستدعي أمر Rust على سطح المكتب ولكن Native Module على iOS؟
لقد وجدت نجاحاً في استخدام Adapter Pattern. أقوم بإنشاء طبقة تجريد (abstraction layer) تكتشف المنصة وتوجه الاستدعاء بناءً على ذلك. هذا يحافظ على نظافة مكونات الـ UI ويجعلها منفصلة عن النظام الأساسي.
مكاسب الأداء في بيئة الإنتاج
في مشروع أخير قمت فيه بنقل لوحة تحكم (dashboard) كثيفة البيانات من Electron إلى Stack (Expo-Tauri) هذا، كانت النتائج مذهلة:
- وقت التشغيل البارد (Cold Start): انخفض من 4.2 ثانية إلى 1.1 ثانية.
- حجم الملف الثنائي (Binary Size): انخفض برنامج التثبيت الخاص بنا من 115MB (في Electron) إلى 8MB (في Tauri).
- الكفاءة: انخفض استهلاك الـ RAM في وضع الخمول بنسبة 70% تقريباً.
لكن الفوز الأكبر لم يكن الأداء فحسب؛ بل كانت سرعة التطوير (Developer Velocity). تمكن فريقي من استخدام نفس مكونات React ومنطق الأعمال لتطبيق الجوال وتطبيق سطح المكتب. لم نكن ندير قاعدتين برمجيتين مختلفتين؛ بل كنا ندير قاعدة برمجية واحدة مع "hooks" محددة لوظائف سطح المكتب الأصلية عبر Rust.
ميزة Rust
إحدى الطفرات التي حققتها كانت نقل المهام ذات الحوسبة العالية—مثل معالجة الصور ومعالجة ملفات JSON الضخمة—خارج خيط (thread) JavaScript تماماً. من خلال كتابة هذه المهام كأوامر Tauri في Rust، استفدت من تعدد الخيوط (multi-threading) الذي لا يمكن لـ JavaScript مضاهاته ببساطة.
كلمات أخيرة
إن عصر تطبيقات سطح المكتب المتضخمة يقترب من نهايته. بصفتنا مهندسين، نحن مدينون لمستخدمينا بشحن برمجيات تحترم موارد أنظمتهم. إن الجمع بين قدرات Expo في بناء واجهات مستخدم عالمية ونواة Tauri الخفيفة بلغة Rust هو، في تجربتي، الطريقة الأكثر قوة لبناء برمجيات عابرة للمنصات اليوم.
يتطلب الأمر تعلم القليل من Rust والتفكير بعمق في تجريدات المنصات (platform abstractions)، لكن النتيجة هي تجربة احترافية ذات طابع أصيل تتجاوز حقاً مجرد الـ WebView.