المحتويات
المفاهيم الأساسية
فهم مفاهيم Carats الأساسية يساعدك على بناء تطبيقات بفاعلية أكبر.
JJSX
تتيح JJSX تجربة HTML وJavaScript خالصة شبيهة بـ PHP. تتيح لك كتابة شيفرة JavaScript داخل ملفات TSX بطريقة تشبه React، لكن دون خطافات React أو React DOM. ولأن المكونات دوال عادية تُعيد HTML، فإن المكوّن نفسه يُصيَّر بشكل متطابق على الخادم وفي المتصفح.
الخصائص الرئيسية
- صياغة HTML وJavaScript خالصة
- بلا اعتماديات React
- تصيير تلقائي على الخادم وفي جانب العميل
تُترجَم JJSX إلى استدعاء دالة، لذا المكوّن دالة عادية تُعيد سلسلة HTML. لا يوجد DOM افتراضي يُقارَن ولا نسخة مكوّن تبقى حيّة، ولهذا من الآمن تشغيل الدالة نفسها على الخادم ثم في المتصفح.
export default function Greeting(props: { name: string }) {
return <p>Hello {props.name}</p>
}
الأوجه (Facets)
الأوجه هي نظام التوجيه في Carats. وهي كائن واحد يربط أنماط المسارات بمكونات الصفحات، ويستخدم العميل والخادم الكائن نفسه، فلا يمكن أن ينحرف مسار بين الاثنين أبدًا. تُعرَّف الأوجه في src/client/facets.cara.ts ويمكنها التصريح بمعاملات المسار وحالات تعليق التصيير وما إذا كان التوجيه داخل التطبيق مُفعَّلًا.
تعريف الأوجه
import { defineFacets } from '@carats/render';
import ErrorPage from './pages/_error';
import NotFound from './pages/_not_found';
import Home from './pages/home';
import Profile from './pages/profile';
export default defineFacets({
routes: {
'/': Home,
'/profile': Profile
},
suspense: {
error: ErrorPage,
notFound: NotFound
},
inAppRouting: true
});
يقبل defineFacets تعريفًا جزئيًا، لذا فإن المسارات وحالات التعليق كلاهما اختياري. يصرّح القالب المرجعي بـ error وnotFound فقط؛ احذف loading ما لم تُعلِّق صفحة فعلًا.
الوجه هو أيضًا وحدة جلب البيانات. المسار داخل `routes` هو المسار الذي يجب أن تُسجَّل عنده الدالة الخادمية، والصفحة المغلَّفة بـ `Burnish` تتلقى القيمة التي أعادتها تلك الدالة.
الدوال الخادمية (Culets)
الدوال الخادمية دوال تعمل على الخادم وتوفّر بيانات للمكونات. تُعرَّف في src/server/culets وتُثبَّت في نقطة دخول الخادم. أما المكونات التي تحتاج بيانات من الخادم فهي مُبرَزة، وهذا يجعل الإطار يجلب البيانات من دالتها الخادمية تلقائيًا. تُطابَق الدالة الخادمية مع الصفحة عبر سلسلة مسارها، لذا يجب أن يتطابق مسار الدالة الخادمية ومسار الوجه تمامًا.
تعريف دالة خادمية
// src/server/culets/profile.ts
import { culet } from '@carats/ssr';
export default culet<User>('/profile', (req) => {
return {
id: '1',
name: 'John Doe',
username: 'johndoe',
email: 'john@example.com'
};
});
مع المسار الديناميكي، تُقرأ المعامل من `req.params`:
// src/server/culets/trade.ts
import { culet } from '@carats/ssr';
export default culet<TradeData>('/trade/:symbol', async (req) => {
const symbol = req.params.symbol.toUpperCase();
const quote = await fetchQuote(symbol);
return { symbol, price: quote.price };
});
تثبيت الدوال الخادمية
الدالة الخادمية المعرَّفة في ملفها الخاص تُنشأ بـ culet(route, handler) ثم تُسجَّل بـ seat(). يُعيد seat الدالة الخادمية دون تغيير، لذا التثبيت مجرد خطوة تسجيل. لا تُسجِّل الدالة الخادمية نفسها مرة ثانية باستدعاء culet() آخر.
// src/server/entrypoint.ts
import { defineServerEntry, seat } from '@carats/ssr';
import facets from '../client/facets.cara';
import getTradeData from './culets/trade';
seat(getTradeData);
export default defineServerEntry(facets);
خصائص الخادم
خصائص الخادم هي القيم التي تُعيدها الدالة الخادمية. يحلّها الإطار أثناء التصيير على الخادم، ثم يسلّمها مُسلسلة داخل الصفحة، ثم يمرّرها إلى المكوّن المُبرَز كأول وسيط. المكوّن لا يجلب أي شيء بنفسه أبدًا.
تصل خصائص الخادم كأول وسيط إلى المكوّن المُبرَز:
import { Burnish } from '@carats/render';
import Layout from '../_layout';
export default Burnish<TradeData>(function (data) {
this.head = <title>Trade {data.symbol}</title>;
return (
<Layout>
<h1>{data.symbol}</h1>
</Layout>
);
});
الصفحة غير المُبرَزة تستقبل ببساطة ما لا خصائص لها، وهذا هو الحال الطبيعي للصفحات الثابتة.
نموذج التصيير
تُصيَّر كل صفحة على الخادم أولًا. يُملأ قالب HTML ثم يعمل مكوّن الصفحة، ويُرسَل الناتج إلى المتصفح مع خصائص الخادم المحلولة. وفي المتصفح تُركَّب الأوجه نفسها ويcontrol التطبيق. ولهذا تعمل دالة المكوّن في الموضعين، وهو سبب وجوب تأجيل الآثار الجانبية إلى afterMount أو beforeMount.
النتيجة العملية هي أن العبارات الموجودة في جسم المكوّن تعمل مرتين في تحميل الصفحة المعتاد: مرة على الخادم ومرة في المتصفح. وكل ما يلمس `document` أو يقرأ `window` أو يُحدث أثرًا جانبيًا يجب تأجيله إلى خطاف، وإلا فسيفشل التصيير على الخادم.
بيئة تشغيل العميل
تُركِّب @carats/csr الأوجه، وتتدخل نقرات الروابط الداخلية عندما يكون التوجيه داخل التطبيق مُفعَّلًا، وتعرض خصائص الخادم المُسلسلة. يحمل window.carats.ssp.for المسار الذي تنتمي إليه خصائص الخادم الحالية، ويحمل window.carats.ssp.data الخصائص نفسها. يُفضَّل قراءتها عبر الإطار بدل تحليل HTML، واستخدام goTo للتنقل البرمجي.
import { goTo } from '@carats/csr';
import { afterMount } from '@carats/hooks';
import './search-bar.sass';
export default function SearchInput() {
afterMount(() => {
const form = document.getElementById('search-bar');
const submit = (e: Event) => {
e.preventDefault();
const q = (document.getElementById('search-input') as HTMLInputElement).value;
goTo(`/search?q=${q}`);
};
form?.addEventListener('submit', submit);
return () => form?.removeEventListener('submit', submit);
});
return (
<form id="search-bar">
<input id="search-input" name="q" type="text" />
</form>
);
}
ينتقل `goTo` بالطريقة نفسها التي ينتقل بها النقر على رابط مُتدخَّل فيه، لذا لا يُعاد تحميل المستند عندما يكون التوجيه داخل التطبيق مُفعَّلًا.