# إلى أي مدى يمكن أن يكون المُعلّم المُعلّم بسيطاً حقاً؟

<!--category-- ASP.NET, Markdown, Blogging -->
<datetime class="hidden">2025-12-01T12:00</datetime>

## أولاً

إذا كنتم تتبعون هذه المدونة، ربما لاحظتم أن منصة التدوين الرئيسية هي... دعونا نسميها "مهندسة هندسية". PostgresQL وقواعد بيانات المتجهات، البحث الدلالي و النص الكامل مع الفهارس GIN، الترجمة الآلية إلى 14 لغة، خدمات مستضيفة متعددة، جدولة الوظائف Hangfire، بروميثيوس، قياسات Serilog، تفاعلات HTMX، استخدام حزم النواة الخاصة بي، وما يكفي من حاويات Docker لجعل سفينة غيورة.

**هذا كلّيّاً متعمداً.** هذا الموقع هو مختبري الحي - ملعب حيث أختبر مع التقنيات، استراتيجيات نشر الاختبار، قياس خصائص الأداء، وبناء حزم قابلة لإعادة الاستخدام. *مفترض* لأن هذه هي الطريقة التي أتعلم بها: من خلال حل المشاكل التي لا توجد في معظم المدونات في الواقع، ثم تعبئة تلك الحلول كمكتبات مفتوحة المصدر يمكن للآخرين استخدامها.

لكن هذا هو الشيء: **ربما لا تحتاج إلى أي من ذلك لتشغيل مدونة.**

لهذا السبب أنا خلقت **اللغم المصغري** - إظهار ما يحدث عندما تقوم بإزالة كل التجارب والتركيز على الضروريات المطلقة. لا قاعدة بيانات. لا بناء خط الأنابيب. لا تعقيد. فقط وضع علامات على الملفات في مجلد، تظهر على الشبكة. هذا ما تبدو عليه المدونة عندما لا تستخدمها كمختبر.

> ملاحظة: انظر نهاية المقالة للربط مع المصدر، وأنا أخطط لاطلاق هذا على أنه [دعم](https://www.nuget.org/packages?q=mostlylucid&includeComputedFrameworks=true&prerel=true&sortby=relevance) بمجرد أن أحصل على الوقت لأتأكد أنه موثوق به 100% و هو ليس سيئاً جداً (لذا ابحثوا عن مواد اختبار k6 قريباً!)

[TOC]

## الفلسفية: أقل هو أكثر

ويتمحور المشروع برمته حول مبدأ واحد هو: *** أبقي عليه بسيطاً**لا قاعدة بيانات، لا خط أنابيب بناء، لا إطار جافاسكربت، فقط ASP.net 9.0، ماركديج للرسم التنازلي، وحوالي 500 سطر من الرمز الكلي، هذا كل شيء.
ملاحظة: يمكنك حتى أن تفعل هذا جانب العميل باستخدام مثل [دال - الحد الأدنى](https://github.com/markdown-it/markdown-it) هذا صحيح فقط `.md` هذه مدونة ASP.NET (نوعاً ما).

## هيكل المشروع

دعونا ننظر إلى كيفية تنظيم المشروع:

```
Mostlylucid.MinimalBlog/
├── Pages/
│   ├── Index.cshtml              # Homepage with post list
│   ├── Post.cshtml                # Individual post page
│   ├── Categories.cshtml          # List of all categories
│   ├── Category.cshtml            # Posts in a category
│   ├── _Layout.cshtml             # Shared layout
│   ├── _ViewImports.cshtml        # Shared imports
│   └── _ViewStart.cshtml          # Layout selection
├── wwwroot/
│   └── css/
│       └── site.css               # All the CSS you need
├── MarkdownBlogService.cs         # Core blog logic
├── MetaWeblogService.cs           # XML-RPC for external editors
├── Program.cs                     # Application setup
├── appsettings.json               # Configuration
└── Mostlylucid.MinimalBlog.csproj # Project file
```

## القلب : خدمة التدرج في الخدمة

جوهر المدوّنة هو: `MarkdownBlogService` إنه بسيط جداً فقط 120 سطراً من الرموز التي تتعامل مع:

1. & جاري
2. البيانات الوصفية (العنوان، الفئات، تاريخ النشر)
3. إلى HTML باستخدام مُز
4. كل شيء في الذاكرة

وهنا كيف يعمل:

### 

الـ لا `.md` ويحمّلها كلها في الذاكرة:

```csharp
private List<BlogPost> LoadAllPosts()
{
    if (!Directory.Exists(_markdownPath)) return [];

    return Directory.GetFiles(_markdownPath, "*.md", SearchOption.TopDirectoryOnly)
        .Where(f => Path.GetFileName(f).Count(c => c == '.') == 1) // Only base .md files
        .Select(ParseFile)
        .Where(p => p is { IsHidden: false })
        .OrderByDescending(p => p!.PublishedDate)
        .ToList()!;
}
```

احفظ المرشّح: `Count(c => c == '.') == 1` نحن فقط نحصل على القاعدة `.md` نسخ النسخ المترجمة مثل `post.ar.md` أو `post.de.md` (في حالة ما إذا كنت تريد إضافة ترجمات لاحقاً).

### تقديم البيانات الفواتية

ويتبع كل ملف فاصلة اتفاقية بسيطة:

```markdown
# Post Title

<!-- category -- Category1, Category2 -->
<datetime class="hidden">2024-11-30T12:00</datetime>

Your content here...
```

يستخلص المكافئ هذه البيانات الفوقية باستخدام تعابير منتظمة و AST علامة:

```csharp
private BlogPost? ParseFile(string filePath)
{
    var markdown = File.ReadAllText(filePath);
    var slug = Path.GetFileNameWithoutExtension(filePath);
    var document = Markdown.Parse(markdown, _pipeline);

    // Extract title from first H1
    var title = document.Descendants<HeadingBlock>()
        .FirstOrDefault(h => h.Level == 1)?
        .Inline?.FirstChild?.ToString() ?? slug;

    // Extract categories: <!-- category -- Cat1, Cat2 -->
    var categoryMatch = CategoryRegex().Match(markdown);
    var categories = categoryMatch.Success
        ? categoryMatch.Groups[1].Value.Split(',', StringSplitOptions.TrimEntries)
        : [];

    // Extract date: <datetime class="hidden">2024-01-01T00:00</datetime>
    var dateMatch = DateTimeRegex().Match(markdown);
    var publishedDate = dateMatch.Success && DateTime.TryParse(dateMatch.Groups[1].Value, out var dt)
        ? dt : File.GetCreationTimeUtc(filePath);

    return new BlogPost
    {
        Slug = slug,
        Title = title,
        Categories = categories,
        PublishedDate = publishedDate,
        HtmlContent = Markdown.ToHtml(markdown, _pipeline),
        IsHidden = markdown.Contains("<hidden")
    };
}
```

### 

كل طريقة في استخدامات الخدمة `IMemoryCache` إلى تجنب إعادة قراءة وإعادة إعداد الملفات عند كل طلب:

```csharp
public IReadOnlyList<BlogPost> GetAllPosts()
{
    return cache.GetOrCreate("all_posts", entry =>
    {
        entry.SetOptions(CacheOptions);
        return LoadAllPosts();
    }) ?? [];
}
```

لـ (كاشي) 30 دقيقة إنتهاء ، و ساعتين إنتهاء مطلق ، بسيط ، فعّال

## إعداد التطبيق: البرنامج.cs

إعدادات التطبيق كلها عبارة عن 43 سطرًا فقط: zazor pages، ذاكرة مخبئة، مخرجات مخبئة، اثنين من خدمات الأفردتون، خدمة الملف الساكن، و نقطة نهاية لـ MetaWeblog XML-RSC. كل شيء مخبّأ كصفحات منفردة لأن لا شيء يتغير ما لم يتم تعديل الملفات.

## أولاً: الصفحات المبسطة من المستخلصات

UI هو صافي خادم HTML لا جافاسكربت ، لا HTMX ، لا الألب. js. الـ قائمة الصفحة الرئيسية قائمة الوظائف ، الـ قائمة `@Html.Raw(post.HtmlContent)` مع وجود `[OutputCache]` 4 صفحات، كل منها تحت 30 سطراً.

## المطبعة: 55 خطا من طراز CSS

التصميم البصري بالكامل يتم التعامل معه بواسطة ملف واحد لـ CSS مع فقط 55 سطر. إنه يستخدم خواص تخصيص CSS لـ و يخلق صورة نظيفة و داكنة لـ GetHub مستوحاة من مظهر:

```css
:root {
  --bg: #0d1117;
  --bg-card: #161b22;
  --text: #c9d1d9;
  --text-muted: #8b949e;
  --accent: #58a6ff;
  --border: #30363d;
}

body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  background: var(--bg);
  color: var(--text);
  line-height: 1.6;
  max-width: 48rem;
  margin: 0 auto;
  padding: 2rem 1rem;
}

/* ... more styles ... */
```

لا توجد معالجات مسبقة، لا توجد خطوة بناء، لا آلاف من فئات المرافق، فقط نظيفة، مقروءة من الـ CSS التي تعمل.

## الميزات المكافئة: AP

لكتاب الكتاب الذين يفضلون مُنْصَفين مُحَرِّرين مُحَرِّرين مثل [مُعَجّز](https://markdownmonster.west-wind.com/)هذا الـ XML-RPC API يسمح للمحررين الخارجيين بما يلي:

- وظائف من الفئة الفنية
- إنشاء الوظائف الجديدة
- تحرير الحالي
- احذف الوظائف
- 
- الفئات المُنَصِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِ الاستِ ِِِِِِ الاستِ ِِِِِِِِِ الاستِ ِِِِِِِِِ الاستِ ِِِِِِِِِِ الاستِ ِِِِ الاستِ المِِِِِِِِِِِِِ المِِِِِِِِِِِِِِِِِِِِ

يجري التنفيذ في: `MetaWeblogService.cs` ويتعامل مع بروتوكول XML-RPC الكامل، يفكّر الطلبات ويولّد الردود. هذا يعني أنه يمكنك كتابة مقالات مدونتك في محررك المفضل ونشرها مباشرة إلى مدونتك.

## 

الـ الكلى ملفّ هو فقط 14 سطر:

```json
{
  "MarkdownPath": "../Mostlylucid/Markdown",
  "ImagesPath": "wwwroot/images",
  "MetaWeblog": {
    "Username": "admin",
    "Password": "changeme",
    "BlogUrl": "http://localhost:5000"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information"
    }
  }
}
```

- `MarkdownPath` - حيث تُعْمَلُ ملفاتُكَ المُعَزَلَة حيّاً
- `ImagesPath` - مكان تخزين الصور
- `MetaWeblog` - وثائق تفويض الدخول إلى محرِّر الدخول الخارجي

## مُستخدِ مستخدم كحزم

> وكما ذكر أعلاه، ستكون متاحة ولكن ليس بعد:

المدونات متاحة الآن كحزمة نوغيت، مما يجعل من السهل إضافة إلى أي تطبيق من تطبيقات ASP.NET الأساسية:

```bash
dotnet add package mostlylucid.MinimalBlog
```

ثم في `Program.cs`:

```csharp
builder.Services.AddRazorPages();
builder.Services.AddMinimalBlog(options =>
{
    options.MarkdownPath = "Markdown";
    options.ImagesPath = "wwwroot/images";
    options.EnableMetaWeblog = false; // Optional, defaults to true
});

var app = builder.Build();

app.UseStaticFiles();
app.UseMinimalBlog();
app.MapRazorPages();
app.Run();
```

هذا هو الأمر - مجرد مُكالمتين طريقتين فقط (`AddMinimalBlog` وقد عقد مؤتمراً بشأن `UseMinimalBlog`(ولديك مدونة عمل)

## جاري تنفيذ مشروع

لتشغيل مشروع العينة المشمول:

```bash
cd Mostlylucid.MinimalBlog
dotnet run
```

زيارة زيارة `http://localhost:5000` وسترون التدوينة التي تحتوي على ملفات من المسار المهيأ.

## جاري إنشاء المحتوى

إنشاء تدوينة جديدة:

1. إنشاء `.md` في حالة أنت `MarkdownPath`
2. يُضاف إلى البيانات الفوقيّة القياسية:
   ```markdown
   # Your Post Title
   
   <!-- category -- YourCategory, AnotherCategory -->
   <datetime class="hidden">2024-11-30T12:00</datetime>
   
   Your content here...
   ```
3. 
4. سينتهي العمل في غضون 30 دقيقة (أو إعادة تشغيل التطبيق)

لإضافة صور، ببساطة ضعها في مُعَدّك `ImagesPath` دليل و مرجع لهم في هدفك:

```markdown
![Alt text](your-image.jpg)
```

## ما هو مفقود (في قصد)

هذا الحد الأدنى من المدونات لا يتضمن ما يلي:

- **التعليقات (التعليقات)** - استخدام خدمة طرف ثالث عند الحاجة
- **** - إبقاء المحتوى منظماً حسب الفئات
- **** - تكون الأصناف كافية للمدونات الصغيرة
- **RSSS/Aتوم** - بسيطة لإضافة إذا كنت في حاجة إليها
- **** - Meta Webblog API استخدامات أساسية للآوث فقط
- **** مُضضِض مُضِضِضِف جافاSCCCbr مُنْى
- **تدبج SEW** - يُشغّلُ تَدْنَةً مَع أساسياتِ المُمْتَزَكَاتِ الأساسيةِ
- **** -المصفف يَعالجُه
- **الموضوع المظلم/الخفيض** -موضوع واحد يكفي

هذه الملام هي كل *يمكن - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -* لأن معظم المدونات الصغيرة لا تحتاجها.

## (أ)

على الرغم من بساطتها، فإن هذه المدونة **-لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا.**:

- **** لا يوجد ملف I/O بعد أول تحميل
- **** لا يُقصد بأيّ مُعَدّ لِمُرْضِحْ بعد الطلب الأوّل
- **لا يوجد قاعدة بيانات** لا يوجد
- **لا لا لا جافSScr سكر** & أكثر أسرع
- **مُبسِز مُبسِزSS** & حد

بالنسبة لمدوّنة صغيرة إلى متوسطة (أقل من 1000 صفحة)، هذا العمارة سوف تفوق أداء معظم منصات المدونات المدعومة بقاعدة البيانات.

## إلى استخدام هذا vs الـ مُنتمِل

 **غالباً لوثدي. المدوّل المُقلّي** متى:

- أنت تَبْدأُ a مدّة شخصية
- لديك أقل من 500 وظيفة
- لا تحتاج إلى لغات متعددة
- تريد أن تبقي الأمور بسيطة
- أنتِ مرتاحة مع الملفات
- أنت فقط تريد كتابة ونشر

 **منصة** متى:

- تستخدم مدونتك كـ **مرحلة التعلم في المختبر** في التكنولوجيات الجديدة
- تريد أن تختبر استراتيجيات النشر، الرصد، والأداء الأمثل
- تحتاج إلى خصائص محددة مثل دعم متعدد اللغات، البحث عن النص الكامل، أو التعليقات
- أنت تبنين الحزم وتحتاجين إلى اختبار حقيقي للعالم
- أنتِ توثقين عمليات تنفيذ تقني معقدة
- رحلة بناء المنصة قيمة بقدر قيمة المحتوى الذي تستضيفه

## الاستنتاج: البساطة كعلامة

في عالم تطوير الإنترنت الحديث، غالباً ما نصل إلى حلول معقدة بالافتراض. هل تحتاج إلى مدونة؟ من الأفضل أن ننشئ قاعدة بيانات، نُعِدّ قاعدة بيانات، نُعِدّ قاعدة بيانات ORM، نُنشئ الهجرات، نضيف الكاتشين، نُنفّذ البحث، نُعِّد الوظائف الأساسية...

لكن أحياناً الحل البسيط هو *الحق في حق* محلول. في الغالب lulucid. minimal Blog يثبت أنه يمكنك بناء منصة مدونة وظيفية وسريعة وقابلة للصيانة مع:

- **342 سطور C#** (الخدمات الإضافية + الخدمات التنفيذية + البرنامج.Cs)
- **120 سُطّان من سُجّل وَزْر** )٤ صفحات(
- **55 خطا من طراز CSS**
- **(أ) الانتقاص** (المرتج)

هذا هو **أقل من ٥٢٠ ٥ سطرا من مجموع الرمز** منصة كاملة للمدونات.

يعمل المشروع كمنصة وظيفية للمدونات وتذكير: قبل أن تضيف التعقيد، اسأل نفسك إذا كنت بحاجة إليه حقاً. أحياناً مجلد مليء بالملفات المرجعية هو كل ما تحتاجه.

يمكنك العثور على المصدر الكامل للرمز في [مُنت مُحد مُحد مُث مُث مُث مُث مُث مُل مُف](https://github.com/scottgal/mostlylucidweb/tree/main/Mostlylucid.MinimalBlog) سأطلق الحزمة حالما أكون سعيداً بالرمز

مدونونة سعيدة!