العرفان

يحلّ Carats عددًا قليلًا من المسارات وأسماء الملفات بالعرف. والانحراف عنها ينجح حتى لا ينجح، لذا يجدر الالتزام بها.

مجلدات الصفحات

يعيش كل مسار في مجلده الخاص تحت src/client/pages، ويصدِّر المجلد مكوّنًا افتراضيًا من index.tsx بجوار ورقة أنماط بالاسم نفسه. أما المجلدات التي تبدأ بشرطة سفلية ليست مسارات؛ إنها لبنات بناء مشتركة تشير إليها المسارات التي تحتاجها.

src/client/pages/
├── _layout/          # shared building block, not a route
│   ├── index.tsx
│   └── _layout.sass
├── _error/           # suspense.error
│   └── index.tsx
├── _not_found/       # suspense.notFound
│   └── index.tsx
├── home/             # '/'
│   ├── index.tsx
│   └── home.sass
├── market/           # '/market'
│   ├── index.tsx
│   └── market.sass
├── profile/          # '/profile'
│   ├── index.tsx
│   └── profile.sass
└── trade/            # '/trade/:symbol'
    ├── index.tsx
    └── trade.sass

الشرطة السفلية البادئة هي ما يعلّم مجلدًا بأنه لبنة بناء لا صفحة. فهي تُبقي المكونات المشتركة بعيدًا في شجرة الملفات وتُشير إلى أنها ليست مسارات مقصودة.

التخطيط المشترك

لا يوجد تخطيط قائم على عُرف الملفات مثل Next.js. فمكوّن ‎_layout‎ يستورده الصفحات التي تحتاجه، ما يجعل التركيب صريحًا ويتيح لصفحة أن تخرج عنه. ويغلّف القالب المرجعي كل صفحة بالتخطيط نفسه لمشاركة الترويسة والتذييل وقائمة الجوال.

// src/client/pages/profile/index.tsx
import { Burnish } from '@carats/render';
import Layout from '../_layout';
import './profile.sass';

export default Burnish(function (user: User) {
    this.head = <>
        <title>Profile for {user.name}</title>
    </>;
    return (
        <Layout>
            <h1>{user.name}</h1>
        </Layout>
    );
});

يُصيّر التخطيط ‎`props.children`‎ حيثما ينتمي محتوى الصفحة، وهذه هي آلية التركيب الوحيدة. لا توجد شجرة مسارات متداخلة ولا التفاف تلقائي، لذا فإن التبعية ظاهرة في الاستيراد.

صفحات الخطأ وغير الموجود

مكوّنا تعليق error وnotFound مكوّنان عاديان. يستقبل الأول Error المُلقى فيستطيع قراءة message وstack، ولا يستقبل الثاني شيئًا. ويجدر تغليف الاثنين في التخطيط المشترك كي يُصيَّر هيكل الموقع حتى عند الفشل.

‏DTO عامة

الواجهات الموضوعة في src/dto عامة، لأن typeRoots يشير إلى ذلك المجلد. وهذا ما يتيح كتابة دالة خادمية بصيغة ‎culet‎ دون استيراد في كل من نقطة دخول الخادم ومكوّن الصفحة. أبقِ هذه الملفات خالية من الاستيرادات وشيفرة وقت التشغيل؛ فهي تصريحات فقط.

// src/dto/user.d.ts
interface User {
  id: string
  name: string
  username: string
  email: string
  phone: string
  website: string
}

لا يملك الواجهة ‎`export`‎، وهذا ما يجعله عامًا. ومع إشارة ‎`typeRoots`‎ إلى ‎`src/dto`‎ يُحل ‎`culet`‎ و‎`Burnish`‎ في كل ملف دون استيراد، وتلتقط إعادة التسمية في موضع واحد كل المواضع.

ورقات الأنماط

تستورد الصفحة أو المكوّن ورقة SASS الخاصة به، وتستورد تلك الورقة ‎base.sass‎ بـ ‎@use ... as *‎. والامتداد اختياري في المسار. احتفظ بعمليات التصفير العامة والرموز في ‎base.sass‎ ولا شيء غير ذلك هناك.

// src/client/pages/trade/trade.sass
@use '../../base' as *

#trade
  .trade-header
    display: flex

الامتداد في مسار ‎`@use`‎ اختياري، والمسار نسبي إلى ورقة الأنماط لا إلى المكوّن. و‎`base.sass`‎ هو الملف الوحيد الذي يعرّف الرموز؛ وكل ملف آخر يستهلكها.

التسمية

تُسمّى مجلدات المسارات بعد مقطع المسار، ويجب أن يتطابق اسم المعامل الديناميكي في الوجه وفي الدالة الخادمية. وتُسمّى ملفات الدوال الخادمية بعد الإجراء الذي تؤديه وتُصدِّر الدالة افتراضيًا، ثم تُثبَّت في نقطة دخول الخادم.