الصفحات · فصل ٤

الصفحات والراوتنج

file-based routing · getStaticPaths · rest params · endpoints · redirects
🎯 الهدف: تربط ملف في src/pages برابط، وتولّد صفحات ديناميكية، وتفرّق صفحة HTML عن endpoint.

الملف هو الرابط

Astro مش عنده جدول راوتس تكتبه. أي ملف صفحة جوّه src/pages بيبقى رابط. الأنواع: .astro و .md و .mdx (بعد ما تركّب MDX). ملف .ts أو .js في نفس الفولدر endpoint بيرجّع Response، مش صفحة HTML.

src/pages/index.astro          →  /src/pages/about.astro          →  /aboutsrc/pages/about/index.astro    →  /aboutsrc/pages/menu/koshary.md      →  /menu/kosharysrc/pages/rss.xml.ts           →  /rss.xml

الانتقال بين الصفحات وسم <a> عادي. مفيش مكوّن Link خاص بالإطار. شكل الملف الناتج (/about ولا /about.html ولا /about/index.html) بيتظبط بـ build.format: directory أو file أو preserve.

تضيف ملف في src/pages، يبقى عندك رابط. مفيش كونفج راوتنج جنبه.

صفحات ديناميكية

قوسين في اسم الملف يعني جزء متغير: src/pages/menu/[slug].astro يمسك /menu/koshary. في الوضع الثابت (الافتراضي) لازم تقول وقت البناء إيه القيم المسموحة، عن طريق getStaticPaths.

src/pages/menu/[slug].astro
---export function getStaticPaths() {  return [    { params: { slug: "koshary" }, props: { title: "كشري", price: 25 } },    { params: { slug: "salad" }, props: { title: "سلطة", price: 10 } },  ];}const { slug } = Astro.params;const { title, price } = Astro.props;---<h1>{title}</h1><p>الرابط: {slug} · {price} جنيه</p>

كل عنصر في المصفوفة صفحة. params لازم يغطي كل الأقواس في اسم الملف. props بيانات زيادة توصل لـ Astro.props، ومش بتظهر في الرابط.

أكتر من قوس ينفع: src/pages/[lang]/[version]/info.astro يطلّع /ar/v1/info لو رجّعت params فيها lang و version.

params اللي راجعة من getStaticPaths مش مفكوكة. لو القيمة فيها ترميز، فكها بـ decodeURI وأنت بترجّعها.

الباقي من المسار

[...slug] بيمسك أي عمق: /docs و /docs/a و /docs/a/b. لو رجّعت slug: undefined تمسك الصفحة الأم نفسها.

في الوضع الثابت، صفحة ثابتة (about.astro) بتكسب لو اتصادفت مع نمط ديناميكي على نفس الرابط. متخليش الاتنين يتنازعوا على نفس الـ URL من غير ما تبقى عارف مين اللي هيطلع.

التقسيم على صفحات

getStaticPaths بياخد paginate. ادّيله المصفوفة و pageSize، وهيعمل روابط الصفحات. الصفحة بتستقبل page فيها data للشريحة الحالية، و url للسابق والتالي، ورقم الصفحة. مناسب لأرشيف بلوج. راجع توقيع paginate في الـ docs لأن شكل page أدق من إن نحفظه غصب.

أخطاء وتحويلات

src/pages/404.astro صفحة غير موجود. src/pages/500.astro لخطأ السيرفر لما يبقى عندك رندر عند الطلب.

التحويلات في الكونفج، مش في ملف صفحة:

astro.config.mjs
export default defineConfig({  redirects: {    "/old-menu": "/menu",    "/dish/[slug]": "/menu/[slug]",  },});

trailingSlash بيقرر الشرطة في آخر الرابط: ignore (افتراضي، الاتنين شغالين) أو always أو never. لازم يتفق مع الاستضافة، لأن بعض المنصات بتزوّد الشرطة لوحدها وبتعمل حلقة تحويل.

الـ endpoints

ملف src/pages/api/order.ts رابط /api/order بيرجّع بيانات مش HTML.

src/pages/api/order.ts
import type { APIRoute } from "astro";export const GET: APIRoute = () => {  return new Response(JSON.stringify({ dish: "كشري" }), {    headers: { "content-type": "application/json" },  });};export const POST: APIRoute = async ({ request }) => {  const body = await request.json();  return new Response(JSON.stringify({ ok: true, body }));};

الدوال المعروفة: GET و POST و PUT و PATCH و DELETE و HEAD و OPTIONS. لو الطريقة مش متصدّرة، Astro يرد 405. export const prerender = false يخلّي الـ endpoint يشتغل وقت الطلب، وده محتاج adapter (الفصل بتاع أوضاع الرندر).

خلّصت الفصل لما

🧠 اختبر نفسك
١) src/pages/menu/index.astro رابطه إيه؟
/menu.
٢) ليه الصفحة الديناميكية الثابتة محتاجة getStaticPaths؟
عشان البناء يعرف كل الروابط قبل ما الزائر يطلب.
٣) ملف src/pages/health.ts اللي مصدّر GET بيرجّع إيه؟
Response، مش مكوّن HTML. ده endpoint.