دوت نت و رياكت: دمج React مع تطبيق .NET Razor Pages
تطوير التطبيقات الويب المتقدمة باستخدام MVC في .NET من المهام التي قد تتطلب بعض الجهد، خاصةً عندما يتعلق الأمر بـ(State Management)، او التحقق من صحة المدخلات في واجهات المستخدم (Frontend Validation)، أو التعامل مع نماذج بيانات معقدة.
بالمقابل تطوير مثل هذه الخصائص عبر أطر عمل جافاسكربت الحديثة مثل React وغيرها يجعل هذه العملية أكثر سهولة. بالإضافة إلى توفر دعم البرمجيات المفتوحة و المجتمعات الغنية بالمكتبات والأدوات الجاهزة التي تسهل تنفيذ مثل هذه المهام.
مؤخرًا، تم تكليفي بمهمة تتطلب إنشاء نموذج إدخال بيانات (Form) بداخل تطبيق ويب تم بناؤه مسبقًا باستخدام .NET ويعتمد على Razor Pages MVC. و خيار إستخدام إطار عمل آخر لم يكن متاح.
بعد عمليات بحث مطولة، اعتقد وصلت لحل وسطي لطيف، بحيث تستطيع إستخدام React Vite و تضمينه بداخل تطبيق الويب المبني عن طريق .NET.
في هذه المقالة بنشرح التفاصيل وكيف نبني بيئة عمل مماثلة، و نجاوب على عدة اسئلة تتعلق بالموضوع.
تجهيز بيئة العمل
في البداية سنقوم بإنشاء تطبيقين:
الأول هو تطبيق .NET باستخدام القوالب الأساسية لـ Razor Pages
والثاني هو تطبيق React باستخدام Vite
1. إنشاء تطبيق .NET باستخدام قالب Razor Pages
ابدأ بإنشاء تطبيق .NET جديد باستخدام القوالب الأساسية لـ Razor Pages. يمكنك القيام بذلك باستخدام الأوامر التالية:
dotnet new razor -n MyRazorApp
cd MyRazorApp
2. إنشاء تطبيق React باستخدام Vite
بعد إعداد تطبيق .NET، ننتقل إلى إنشاء تطبيق React باستخدام Vite. Vite هو أداة بناء حديثة وسريعة لتطبيقات JavaScript. لإنشاء تطبيق React باستخدام Vite، استخدم الأوامر التالية:
npm create vite@latest react-app -- --template react-ts
cd my-react-app
npm install
3. ربط الـ Builds من React إلى .NET
لدمج تطبيق React مع تطبيق .NET، نحتاج إلى إعداد عملية بناء (Build) تقوم بنقل الملفات النهائية إلى مجلد wwwroot
في تطبيق .NET.
يمكن تحقيق ذلك عن طريق تعديل إعدادات Vite لتوليد ملف manifest.json
الذي يحتوي على معلومات حول الملفات المولدة.
نحتاج manifest.json
لتحديد مسارات الملفات المولدة من عملية بناء React، مما يسهل تضمينها بشكل ديناميكي في تطبيق .NET وهذا يساعدنا لإستخدام ال cache.
لضمان تضمين ملفات CSS بشكل صحيح في تطبيق React، يمكننا استخدام حزمة vite-plugin-css-injected-by-js
.
هذه الحزمة تساعد في إضافة ملفات CSS مباشرة من JavaScript، مما يسهل عملية الدمج مع تطبيق .NET. قم بتثبيت الحزمة وإجراء التعديلات اللازمة في إعدادات Vite.
cd react-app
npm i vite-plugin-css-injected-by-js -D
// in file: vite.config.ts
import {defineConfig} from "vite";
import react from "@vitejs/plugin-react";
import cssInjectedByJsPlugin from "vite-plugin-css-injected-by-js";
export default defineConfig({
plugins: [cssInjectedByJsPlugin(), react()],
build: {
manifest: true,
rollupOptions: {
output: {
dir: "../wwwroot/react-app", // Output to the wwwroot folder of .NET project
},
},
},
});
4. ربط الصفحة من تطبيق Razor
أخيرًا، نحتاج إلى ربط الصفحة التي تحتوي على React في تطبيق Razor. للقيام بذلك راح نحتاج عدة خطوات:
- عند طلب الصفحة المطلوبة نحتاج ناخذ إسم الملف الذي تم توليده في جزئية الView Controller عن طريق هذا الكود:
using System.Text.Json;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace mvc_and_react.Pages;
public class ReactAppModel : PageModel
{
public string? JsFileName { get; set; }
public void OnGet()
{
// مسار الملف الذي سيتم إنشائه بعد كل عملية بناء لتطبيق الرياكت
var manifestFilePath = Path.Combine(
Directory.GetCurrentDirectory(),
"wwwroot",
"react-app",
"manifest.json"
);
// قراءة الملف
using StreamReader reader = new(manifestFilePath);
var json = reader.ReadToEnd();
if (string.IsNullOrEmpty(json)) return;
// البحث عن اسم ملف الجافاسكربت الجديد
var manifestData = JsonSerializer.Deserialize<Dictionary<string, Dictionary<string, object>>>(json);
var data = manifestData?["index.html"]["file"];
JsFileName = data?.ToString();
}
}
- في ملف ال cshtml نحتاج نضيف سطرين مهمين:
<div id="root"></div>
<script type="module" crossorigin src="react-app/@Model.JsFileName" defer/>
السطر الأول هو اول مدخل لتطبيق react بداخل هذه الصفحة
السطر الثاني يطلب ملف الjs الذي تم إنشائه مسبقًا في الView Controller مثل ماهو موضح اعلاه
@Model.JsFileName
بحيث هذا المتغير يحمل اسم الملف المطلوب
اخيرا، نجد الكود اخيرا يعمل بشكل جيد:
نسخة تعمل من الكود اعلاه على Github:
عبر الرابط ادناه تجد نسخة كاملة للتطبيق:
رسم بياني لطريقة عمل و تواصل العناصر
الفكرة تنقسم إلى جزئين:
- Compile Time: عملية بناء تطبيق React ونقل الملفات النهائية إلى مجلد
wwwroot
في تطبيق .NET
- Run Time: عرض الصفحة التي تحتوي على React في تطبيق Razor
اسئلة
السؤال | الإجابة |
---|---|
كيف تكون طريقة التطوير؟ | يمكنك تشغيل أوامر التطوير لكل من React و .NET بشكل متزامن باستخدام vite build --watch --emptyOutDir لتطبيق React و dotnet watch run لتطبيق .NET. هذا يتيح لك رؤية التغييرات في الوقت الحقيقي أثناء التطوير. |
كيف تتعامل مع ملفات الـ CSS؟ | هناك طريقتان للتعامل مع ملفات CSS: إما عن طريق استيرادها في تخطيط .NET (layout) أو استيرادها في تطبيق React. من الأفضل التركيز على مكان واحد لتجنب التعارضات. |
هل بيشتغل الـ Routing؟ | نعم، يعمل الـ Routing بشكل جيد، لكن يجب أن تكون الصفحة الأولى هي الصفحة التي تقوم باستيراد ملف الـ JS. |
هل التوثيق بيشتغل؟ | غالبًا ما تستخدم تطبيقات Razor (cookies) أو (sessions)، لذلك يمكن لـ React استخدام نفس الشيء والتعامل معه. |
طيب لو عندي بيانات مسبقة يحتاجها التطبيق حتى يشتغل، مثل اوبجكت JSON؟ | يمكنك استخدام window في صفحة Razor، وعندما تصل الصفحة إلى المستخدم، يمكن لـ React طلب نفس الأوبجكت والعمل عليه. |
كيف نضمن وجود آخر نسخة دائمًا في البيئة التشغيلية؟ | يمكنك إنشاء بايبلاين في CI/CD لضمان عدم الحاجة إلى تدخل يدوي لإنشاء تطبيق React ونقله إلى .NET. |
في النهاية اعتقد دائما أن الحلول السيطة هي الأفضل، الي حد ما يمكنك الاستفادة من مزايا كل من React و .NET في تطبيق واحد. وهذا يعتبر حلاً جيدًا للمشاريع التي تحتاج إلى تكامل بين الجزئين.