3.2 · محركات القوالب وخدمة الملفات

المستوى 3 · إكسبريس وقواعد البيانات (Express & databases)

3.2محركات القوالب وخدمة الملفات

الهدف: خدمة الملفات الثابتة (express.static) وتوليد HTML ديناميكي بمحرك قوالب (res.render)، مع تموضع SSR مقابل API + واجهة منفصلة.
الوقت المقدّر: 10 دقيقة · قراءة ذاتية · إذا كان لديك 5 دقائق فقط: اقرأ «الأساسي في 30 ثانية» + المخطط.

الأساسي في 30 ثانية

  • الثابت يُقدَّم بسطر واحد : ‏app.use(express.static('public'))‏ يقدم CSS والصور و JS العميل من مجلد مخصص.
  • الديناميكي يُصيَّر بمحرك : قوالب EJS/Handlebars/Pug + ‏res.render('vue', { données })‏ ‏= HTML‏ مُجمَّع جهة الخادم (SSR).
  • بنيتان صالحتان : SSR للمحتوى وتحسين الظهور (SEO)، و API JSON + واجهة منفصلة للتطبيقات التفاعلية — والمستويات التالية تميل نحو الـ API.

حالة مصغرة متسلسلة — ساليم ينشر الفهرس SSR ثم API

ساليم، مطور مبتدئ في الجزائر، عليه نشر الفهرس : بطاقات منتجات بـ HTML لأجل الفهرسة، إضافة إلى لوحة متابعة داخلية شديدة التفاعل. يقدم أولا CSS والصور مع ‏express.static('public')‏، ويضبط EJS ‏(app.set('view engine', 'ejs'))‏ ويصير ‏res.render('produit', { produit })‏ لبطاقات SSR. وللوحة المتابعة، يعرض البيانات نفسها بـ res.json() : ستستهلك الواجهة المخصصة الـ API. خادم واحد، وعرضان حسب الاستعمال.

هذه الحالة نفسها تعود في الدرس والمخطط والنص الجاهز وتحدي 48 ساعة.

1. الملفات الثابتة والقوالب

يقدم تطبيق الوب موارد ثابتة (CSS والصور و JS العميل والخطوط) : يقدمها إكسبريس بالوسيط الأصلي express.static() — ‏app.use(express.static('public'))‏ يعرض كل مجلد public/ (طلب نحو /style.css يرجع public/style.css). نجمع الأصول في هذا المجلد المخصص.

ولأجل HTML الديناميكي، نستعمل محرك قوالب (template engine) : قالب (HTML + متغيرات وحلقات وشروط) يُملأ ببيانات. الشائعة : EJS (‏JS‏ داخل وسوم <% %>، قريب من HTML)، و Handlebars/hbs (بصيغة {{ }}، مُنقاة)، و Pug (بالإزاحة، موجزة). نضبط (‏app.set('view engine', 'ejs')‏)، ونرتب العروض في views/، ونصير مع ‏res.render('page', { données })‏. وهذا هو SSR (التصيير جهة الخادم) : يبني الخادم HTML كاملا ويرسله للمتصفح.

2. ‏SSR‏ أو API + واجهة منفصلة : التحكيم حسب المشروع

يناسب SSR مواقع المحتوى (الواجهات والمدونات والتجارة الكلاسيكية)، و SEO (‏HTML‏ جاهز، جيد الفهرسة) و التحميل الأولي السريع. والبديل العصري : يعرض نود API REST بـ JSON (القسم 4-1) تستهلكها واجهة منفصلة (React و Vue و Angular) تعرض جهة المتصفح — مثالي للتطبيقات التفاعلية (لوحات المتابعة والأدوات) والتجربة السلسة دون إعادة تحميل.

وكلتاهما صالحة : يختار ساليم SSR للبطاقات (المحتوى و SEO) و API + واجهة للوحة المتابعة (التفاعلية). وليس SSR متجاوَزا : بل يعود بقوة عبر Next.js/Nuxt اللذين يجمعان تصيير الخادم والتفاعلية. والمستويات التالية تميل نحو مقاربة API/JSON، الغالبة جهة نود.

خطأ شائع في الفهم: « ‏SSR‏ متجاوز، ويجب فعل كل شيء SPA، و express.static يقدم القوالب أيضا ». لا. يبقى SSR وجيها (المحتوى و SEO والبساطة) ويعرف نهضة عصرية ؛ والـ SPA تعقد دون فائدة موقع واجهة بسيطا. ولا يقدم express.static إلا الملفات الثابتة من public/، أبدا عروض views/ المصيَّرة بـ res.render().
ثابت أم SSR أم API ؟ خادم واحد، وثلاث مخارج حسب الحاجة ثابتexpress.static : ‏CSS‏ والصور+SSR‏res.render‏ : ‏HTML‏ كامل+API + واجهة‏res.json‏ : بيانات لـ React/Vue المحتوى/SEO ← ‏SSR‏ ؛ والتطبيق التفاعلي ← ‏API‏ + واجهة.
خادم واحد، وثلاث مخارج حسب الحاجة
نص المخطط (SEO / قارئات الشاشة / الترجمة): 1) الثابت : يضع ساليم CSS والصور في public/ المقدمة بـ express.static. 2) ‏SSR‏ : يصير EJS بطاقة المنتج بـ HTML كامل لأجل SEO. 3) ‏API‏ : تنطلق البيانات نفسها بـ res.json() نحو لوحة المتابعة. الدرس : نختار العرض حسب الاستعمال، لا حسب الموضة.

🔎 مثال ملموس — التقديم ثم التصيير، ثم العرض JSON

يغطي ساليم المخارج الثلاثة بالخادم نفسه.

app.use(express.static('public'));
app.set('view engine', 'ejs');
app.get('/produits/:id', (req, res) => {
  res.render('produit', { produit: { id: req.params.id } });
});
app.get('/api/produits/:id', (req, res) => {
  res.json({ id: req.params.id });
});

القراءة : نفس البيانات، وعرضان : ‏HTML‏ عبر EJS أو JSON عبر res.json().

الدرس : مقارنة العرضين تُشعر بالفرق بين SSR و API.

مفردات القسم

الملفات الثابتة
موارد ثابتة (CSS والصور و JS العميل والخطوط) تُقدَّم كما هي بـ ‏express.static('public')‏.

مثال بسيط: الـ style.css الخاص بساليم مقدم من public/.

ما ليس كذلك: عرض EJS مصيَّر ببيانات.

رد فعل: تجميع كل الأصول في public/.

محرك القوالب
أداة تولد HTML ديناميكيا من قوالب (متغيرات وحلقات وشروط) : ‏EJS‏ و Handlebars و Pug.

مثال بسيط: بطاقة منتج EJS الخاصة بساليم التي تحلق على الآراء.

ما ليس كذلك: مجرد مجلد ملفات ثابتة.

رد فعل: اختيار EJS للبدء، لقربها من HTML.

‏res.render()‏
طريقة إكسبريس تصير عرضا : ‏res.render('page', { données })‏ تحقن البيانات في قالب views/.

مثال بسيط: ‏res.render('produit', { produit })‏ عند ساليم.

ما ليس كذلك: إرسال JSON خام للواجهة.

رد فعل: تسمية العرض باسم ملف views/.

‏SSR‏
التصيير جهة الخادم : يولد الخادم HTML كاملا ويرسله للمتصفح ؛ وميزته المحتوى و SEO.

مثال بسيط: بطاقات فهرس ساليم القابلة للفهرسة.

ما ليس كذلك: ‏SPA‏ تصير كل شيء في المتصفح.

رد فعل: تفضيل SSR للصفحات المراد فهرستها.

API + واجهة منفصلة
يعرض نود JSON ‏(API REST)‏ تستهلكه واجهة React/Vue/Angular تعرض جهة المتصفح.

مثال بسيط: لوحة المتابعة الداخلية المغذاة بـ res.json().

ما ليس كذلك: قالب EJS مصيَّر جهة الخادم.

رد فعل: حصر هذه البنية في التطبيقات التفاعلية.

في التطبيق — خدمة الملفات وتوليد HTML

  1. اخدموا ملفات ثابتة مع ‏app.use(express.static('public'))‏ : ضعوا CSS وصورة في public/ وتحققوا من الوصول إليهما.
  2. اضبطوا محرك قوالب (مثلا EJS : ‏app.set('view engine', 'ejs')‏) وضعوا القوالب في views/.
  3. صيروا عرضا ببيانات : ‏res.render('page', { titre: '...', items: [...] })‏ ؛ وفي القالب، أدخلوا المتغيرات وحلقوا على قائمة.
  4. قارنوا : صيروا البيانات نفسها JSON ‏(res.json(data)، مقاربة API)‏ لإدراك الفرق بين SSR و API + واجهة منفصلة.
تخدمون ملفات ثابتة (express.static) وتولدون HTML ديناميكيا بمحرك قوالب (res.render)، مع تموضع SSR مقابل API + واجهة منفصلة.

نص جاهز للقول — تبرير SSR مقابل API (30 ثانية)

« بطاقات الفهرس تنطلق SSR مع EJS : ‏HTML‏ كامل، جيد لـ SEO والعرض الأول. ولوحة المتابعة، شديدة التفاعل، تستهلك البيانات نفسها JSON عبر الـ API خاصتنا. والثابت CSS والصور مقدم بـ express.static من public. »

يُقال في تحكيم البنية ؛ وتُعرَض البيانات نفسها HTML ثم JSON.

نموذج نسخ-لصق — ثابت + EJS ‏+ JSON‏

const express = require('express');
const path = require('path');
const app = express();
app.use(express.static('public'));
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
app.get('/produits/:id', (req, res) => {
  res.render('produit', { id: req.params.id });
});
app.get('/api/produits/:id', (req, res) => {
  res.json({ id: req.params.id });
});
app.listen(3000);

مستقل

يكفي موقع واجهة SSR + ثابت : لا واجهة ثقيلة لصفحات قليلة.

مقاولة صغيرة في الجزائر

يصير ساليم البطاقات EJS لأجل SEO ويبقي API JSON للإدارة الداخلية.

فريق منتج

الفصل بين views/ ‏(SSR)‏ و /api ‏(JSON)‏ ليتقدم فريقان دون تعارض.

مبتدئ

هذا الأسبوع : ‏CSS‏ مقدم ثابتا وعرض EJS واحد بحلقة على ثلاثة عناصر.

✓ ممارسات جيدة

  • خدمة الأصول مع express.static (مجلد public واحد).
  • اختيار البنية حسب المشروع (المحتوى/SEO مقابل التطبيق التفاعلي).
  • إتقان API REST ‏(JSON)‏ : المقاربة الغالبة في المستويات التالية.

✗ أخطاء شائعة

  • اعتقاد SSR « متجاوَزا » (وهو يعرف نهضة : Next.js/Nuxt).
  • اختيار SPA لموقع محتوى بسيط (تعقيد عديم الفائدة).
  • إهمال SEO في بنية SPA خالصة.

النقاط الأساسية

  • الخدمة الثابتة : ‏app.use(express.static('public'))‏ يقدم الموارد الثابتة (CSS والصور و JS العميل).
  • محركات القوالب (EJS و Handlebars و Pug) : ‏HTML‏ ديناميكي عبر ‏res.render('vue', {données})‏.
  • ‏SSR‏ : يولد الخادم HTML كاملا — مقاربة المواقع الكلاسيكية (المحتوى و SEO).
  • البديل العصري الشائع جدا : يعرض نود API REST ‏(JSON)‏ تستهلكها واجهة منفصلة (React/Vue/Angular).

تحدي 48 ساعة — طبّق غدا

اخدموا ‏CSS‏ واحدا ثابتا وصيروا عرض EJS واحدا مع حلقة على 3 عناصر.

قائمة الخروج من القسم
  • أخدم مجلد public/ دون تردد.
  • أصير عرضا مع res.render().
  • أحكم بين SSR و API حسب المشروع.
تقييم ذاتي 1-5 : هل عروضي في views/ وأصولي في public/ ؟هل أعرف تبرير SSR أو API لحاجة ؟

أسئلة شائعة

‏SSR‏ (قوالب) أو API + واجهة منفصلة : أي بنية نختار ؟

كلتاهما صالحة حسب المشروع. يناسب SSR مواقع المحتوى (المدونات والواجهات والتجارة الكلاسيكية)، عندما يهم SEO ‏(HTML‏ مقدم جاهزا)، ولأجل تحميل أولي سريع والمواقع قليلة التفاعل (أبسط). وتناسب API + واجهة منفصلة التطبيقات التفاعلية (لوحات المتابعة والأدوات)، و التجربة السلسة دون إعادة تحميل و الفصل بين الواجهة والخلفية. ينوع ساليم : ‏SSR‏ للبطاقات، و API للوحة المتابعة.

هل التصيير جهة الخادم متجاوز أمام React ؟

لا، بل يعرف نهضة. فبعد عهد SSR الكلاسيكي (قوالب EJS)، ثم حماس SPA (كل شيء مصيَّر جهة العميل، بحدود SEO والتحميل الأولي)، تجمع أطر مثل Next.js و Nuxt بين الاثنين : ‏HTML‏ مصيَّر خادميا (‏SEO‏ والسرعة) + تفاعلية العميل (تجربة SPA). ويبقى SSR الكلاسيكي وجيها لمواقع كثيرة ببساطته.

تحقّق من فهمك

أي طريقة إكسبريس تصير عرضا ببيانات ؟

موارد إضافية (اختياري، للتعمّق أكثر)

اختبار المستوى 3أسئلة جديدة وأصعب للتحقق من مكتسباتك